name: Docker Build and Push permissions: contents: write packages: write on: workflow_dispatch: inputs: branch: type: choice description: Target branch options: [develop, master] default: develop choice: type: choice description: Version bump options: [none, major, minor, patch] default: none push: branches: [develop] # Avoid multiple parallel builds for the same branch to prevent race conditions concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false # Set to true if you want to abort old builds immediately jobs: docker-build: runs-on: ubuntu-latest if: >- (github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/develop') && (github.event_name != 'push' || github.actor != 'github-actions[bot]') steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Ensure we always have the right branch context ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.branch || github.ref }} - name: Install Rust Tools (Binaries) uses: taiki-e/install-action@v2 with: tool: cross,trunk,wasm-bindgen-cli,cargo-edit,mdbook - name: Install Rust Toolchain uses: dtolnay/rust-toolchain@stable with: targets: x86_64-unknown-linux-musl,aarch64-unknown-linux-musl,wasm32-unknown-unknown - name: Install wasm tools 128 run: | chmod +x ./bin/install_wasm_tools.sh WASM_TOOLS_BIN="$(./bin/install_wasm_tools.sh 128)" echo "${WASM_TOOLS_BIN}" >> "$GITHUB_PATH" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: cache-targets: "true" - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Cache built resources id: cache-resources uses: actions/cache@v4 with: path: resources/*.ts key: ${{ runner.os }}-resources-${{ hashFiles('resources/*.jpg') }} - name: Install ffmpeg if: steps.cache-resources.outputs.cache-hit != 'true' run: | sudo apt-get update sudo apt-get install -y ffmpeg - name: Build TS resources if: steps.cache-resources.outputs.cache-hit != 'true' run: | chmod +x ./bin/build_resources.sh ./bin/build_resources.sh - name: Verify TS resources run: | required_resources=( "channel_unavailable" "user_connections_exhausted" "provider_connections_exhausted" "user_account_expired" "panel_api_provisioning" ) for resource in "${required_resources[@]}"; do if [[ ! -f "resources/${resource}.ts" ]]; then echo "🧨 Missing resource: resources/${resource}.ts" exit 1 fi done - name: Handle Version Bump run: | chmod +x ./bin/inc_version.sh if [[ "${{ github.event_name }}" == "push" ]]; then ./bin/inc_version.sh else case "${{ github.event.inputs.choice }}" in major) ./bin/inc_version.sh m ;; minor) ./bin/inc_version.sh p ;; patch) ./bin/inc_version.sh ;; esac fi - name: Commit version bump id: version_commit run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add . if git diff --cached --quiet; then echo "did_commit=false" >> "$GITHUB_OUTPUT" else VERSION=$(grep '^version' backend/Cargo.toml | head -n1 | cut -d'"' -f2) git commit -m "ci: bump version v$VERSION" echo "did_commit=true" >> "$GITHUB_OUTPUT" fi - name: Build and push Docker images env: GITHUB_IO_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO_OWNER: ${{ github.repository_owner }} run: | chmod +x ./bin/build_docker.sh ./bin/build_docker.sh ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.branch || 'develop' }} - name: Read project version id: version run: | VERSION=$(grep -Po '^version\s*=\s*"\K[0-9\.]+' ./Cargo.toml) echo "value=${VERSION}" >> "$GITHUB_OUTPUT" - name: Verify static binary artifacts run: | ls -la artifacts test -f "artifacts/tuliprox-v${{ steps.version.outputs.value }}-x86_64-unknown-linux-musl" test -f "artifacts/tuliprox-v${{ steps.version.outputs.value }}-x86_64-unknown-linux-musl.sha256" test -f "artifacts/tuliprox-v${{ steps.version.outputs.value }}-aarch64-unknown-linux-musl" test -f "artifacts/tuliprox-v${{ steps.version.outputs.value }}-aarch64-unknown-linux-musl.sha256" for sum_file in artifacts/*.sha256; do (cd artifacts && sha256sum -c "$(basename "$sum_file")") done - name: Build release checksum notes run: | { echo "## Static Binary Checksums" echo echo "The checksums below were validated in CI via \`sha256sum -c\` before upload." echo echo "| File | SHA256 |" echo "| --- | --- |" for sum_file in artifacts/*.sha256; do checksum=$(awk '{print $1}' "$sum_file") filename=$(awk '{print $2}' "$sum_file") echo "| \`$filename\` | \`$checksum\` |" done echo echo "Verification command after download:" echo "\`\`\`bash" echo "sha256sum -c *.sha256" echo "\`\`\`" } > artifacts/RELEASE_NOTES_SHA256.md - name: Upload static binary artifacts uses: actions/upload-artifact@v4 with: name: tuliprox-static-v${{ steps.version.outputs.value }} path: artifacts/* if-no-files-found: error - name: Push version bump if: success() && steps.version_commit.outputs.did_commit == 'true' run: | # Use origin HEAD to push to the correct remote branch git push origin HEAD - name: Publish static binaries to GitHub Release if: success() && github.event_name == 'workflow_dispatch' && github.event.inputs.branch == 'master' uses: softprops/action-gh-release@v2 with: tag_name: v${{ steps.version.outputs.value }} name: v${{ steps.version.outputs.value }} files: | artifacts/tuliprox-v${{ steps.version.outputs.value }}-x86_64-unknown-linux-musl artifacts/tuliprox-v${{ steps.version.outputs.value }}-x86_64-unknown-linux-musl.sha256 artifacts/tuliprox-v${{ steps.version.outputs.value }}-aarch64-unknown-linux-musl artifacts/tuliprox-v${{ steps.version.outputs.value }}-aarch64-unknown-linux-musl.sha256 body_path: artifacts/RELEASE_NOTES_SHA256.md generate_release_notes: true