chore: skip coverage gate on tagged release #5810
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Go package | |
| on: | |
| push: | |
| tags: | |
| - "v*" # push events to tagged commits | |
| branches: | |
| - "**" | |
| paths: | |
| - ".github/workflows/go.yml" | |
| - "Makefile" | |
| - "pkgs/**" | |
| - "src/**" | |
| permissions: | |
| contents: read | |
| id-token: write # for GitHub id-token auth | |
| jobs: | |
| go-test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: src/go.mod | |
| cache-dependency-path: src/go.sum | |
| - name: Sanitize branch name for artifact | |
| id: branch | |
| run: echo "name=$(echo '${{ github.ref_name }}' | tr '/' '-')" >> $GITHUB_OUTPUT | |
| - name: Run Go unit tests | |
| run: go test -test.short -v -coverprofile=coverage.out -covermode=atomic ./... | |
| working-directory: src | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # to avoid GH rate limits | |
| - name: Generate coverage summary | |
| run: go tool cover -func=coverage.out | tee coverage.txt | |
| working-directory: src | |
| - name: Upload coverage report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-${{ steps.branch.outputs.name }} | |
| path: src/coverage.txt | |
| overwrite: true | |
| - name: Download main branch coverage | |
| if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/v') | |
| uses: dawidd6/action-download-artifact@1f8785ff7a5130826f848e7f72725c85d241860f | |
| with: | |
| workflow: go.yml | |
| branch: main | |
| name: coverage-main | |
| path: coverage-main | |
| continue-on-error: true # no baseline yet on first run | |
| - name: Check coverage regression | |
| if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/v') | |
| run: | | |
| if [ ! -f coverage-main/coverage.txt ]; then | |
| echo "No main coverage baseline found, skipping comparison" | |
| exit 0 | |
| fi | |
| main_pct=$(grep '^total:' coverage-main/coverage.txt | awk '{print $3}' | tr -d '%') | |
| curr_pct=$(grep '^total:' src/coverage.txt | awk '{print $3}' | tr -d '%') | |
| if [ -z "$main_pct" ] || [ -z "$curr_pct" ]; then | |
| echo "ERROR: Could not parse coverage percentages (main='$main_pct', current='$curr_pct')" | |
| exit 1 | |
| fi | |
| echo "Main: ${main_pct}% Current branch: ${curr_pct}%" | |
| if awk "BEGIN { exit !(${curr_pct} < ${main_pct}) }"; then | |
| echo "ERROR: Coverage decreased from ${main_pct}% to ${curr_pct}%" | |
| exit 1 | |
| fi | |
| echo "Coverage OK (${curr_pct}% >= ${main_pct}%)" | |
| - name: Verify Go modules | |
| working-directory: src | |
| run: | | |
| go mod tidy | |
| git diff --exit-code go.mod go.sum || { echo "Go modules are not up to date"; exit 1; } | |
| - name: Install protoc and plugins | |
| run: | | |
| PROTOC_VERSION=32.1 | |
| curl -fsSL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip" -o protoc.zip | |
| sudo unzip -o protoc.zip -d /usr/local bin/protoc 'include/*' | |
| rm protoc.zip | |
| go install google.golang.org/protobuf/cmd/protoc-gen-go@latest | |
| go install connectrpc.com/connect/cmd/protoc-gen-connect-go@latest | |
| - name: Verify Proto files | |
| working-directory: src | |
| run: | | |
| touch protos/io/defang/v1/fabric.proto protos/google/type/money.proto | |
| make protos | |
| git diff --exit-code protos || { echo "Proto files are not up to date"; exit 1; } | |
| - name: Build MacOS binary | |
| run: GOOS=darwin go build ./cmd/cli | |
| working-directory: src | |
| - name: Build Windows binary | |
| run: GOOS=windows go build ./cmd/cli | |
| working-directory: src | |
| nix-shell-test: | |
| runs-on: ubuntu-latest | |
| needs: go-test | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: cachix/install-nix-action@v26 | |
| with: | |
| nix_path: nixpkgs=channel:nixos-unstable | |
| - name: Check nix-shell default.nix | |
| id: nix-test | |
| continue-on-error: true | |
| run: | | |
| set -o pipefail | |
| make test-nix 2>&1 | tee /tmp/nix-test-output.log | |
| exit ${PIPESTATUS[0]} | |
| - name: Update vendorHash if needed | |
| if: steps.nix-test.outcome == 'failure' | |
| run: | | |
| # Extract the correct hash from the error output | |
| NEW_HASH=$(grep 'got:' /tmp/nix-test-output.log | grep -oP 'sha256-[A-Za-z0-9+/]+=*' | head -1) | |
| if [ -n "$NEW_HASH" ]; then | |
| # Validate hash format (should be sha256- followed by 44 base64 characters) | |
| if ! echo "$NEW_HASH" | grep -qE '^sha256-[A-Za-z0-9+/]{43}=$'; then | |
| echo "❌ Extracted hash has invalid format: $NEW_HASH" | |
| exit 1 | |
| fi | |
| echo "Found new hash: $NEW_HASH" | |
| # Update the vendorHash in cli.nix | |
| OLD_HASH=$(grep -oP 'vendorHash = "\Ksha256-[A-Za-z0-9+/]+=*' pkgs/defang/cli.nix) | |
| echo "Old hash: $OLD_HASH" | |
| # Use @ as delimiter since it won't appear in base64 hashes | |
| sed -i "s@vendorHash = \"$OLD_HASH\"@vendorHash = \"$NEW_HASH\"@" pkgs/defang/cli.nix | |
| # Verify the fix works before committing | |
| echo "Verifying the updated hash..." | |
| if make test-nix; then | |
| echo "✅ Verification successful" | |
| # Configure git | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # Commit and push the change | |
| git add pkgs/defang/cli.nix | |
| git commit -m "Update Nix vendorHash to $NEW_HASH" | |
| git push | |
| echo "✅ Updated vendorHash and committed the change" | |
| else | |
| echo "❌ Verification failed after updating hash" | |
| exit 1 | |
| fi | |
| else | |
| echo "❌ Could not extract hash from error output" | |
| echo "Last 20 lines of output:" | |
| tail -20 /tmp/nix-test-output.log | |
| exit 1 | |
| fi | |
| # go-byoc-test: | |
| # runs-on: ubuntu-latest | |
| # steps: | |
| # - name: Configure AWS Credentials for CI | |
| # uses: aws-actions/configure-aws-credentials@v4 | |
| # with: | |
| # aws-region: us-west-2 | |
| # output-credentials: true | |
| # role-to-assume: arn:aws:iam::488659951590:role/ci-role-d4fe904 # ciRoleArn from defang-io/infrastructure stack | |
| # - name: Configure AWS Credentials for Staging | |
| # uses: aws-actions/configure-aws-credentials@v4 | |
| # with: | |
| # aws-region: us-west-2 | |
| # role-duration-seconds: 1200 | |
| # role-chaining: true | |
| # role-to-assume: arn:aws:iam::426819183542:role/admin # adminUserRoleArn from defang-io/bootstrap stack | |
| # - uses: actions/checkout@v4 | |
| # - name: Set up Go | |
| # uses: actions/setup-go@v5 | |
| # with: | |
| # go-version-file: src/go.mod | |
| # cache-dependency-path: src/go.sum | |
| # - name: Run sanity tests | |
| # run: go run ./cmd/cli -C testdata/sanity compose up --debug | |
| # working-directory: src | |
| go-playground-test: | |
| runs-on: ubuntu-latest | |
| needs: go-test | |
| env: | |
| COMPOSE_PROJECT_NAME: ${{ github.run_id }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: src/go.mod | |
| cache-dependency-path: src/go.sum | |
| - name: Login using GitHub token | |
| run: go run ./cmd/cli login --debug | |
| working-directory: src | |
| - name: Add dummy config | |
| id: add-dummy-config | |
| run: echo blah | go run ./cmd/cli -C testdata/sanity config set --provider=defang -n dummy --debug | |
| working-directory: src | |
| - name: Run sanity tests UP | |
| continue-on-error: true # until we have multi-project support in playground | |
| run: go run ./cmd/cli -C testdata/sanity compose up --provider=defang --debug | |
| working-directory: src | |
| - name: Run sanity tests DOWN | |
| continue-on-error: true # until we have multi-project support in playground | |
| run: go run ./cmd/cli -C testdata/sanity compose down --provider=defang --detach --debug | |
| working-directory: src | |
| - name: Remove dummy config | |
| if: steps.add-dummy-config.conclusion == 'success' # only clean up if the config was added | |
| run: go run ./cmd/cli -C testdata/sanity config rm --provider=defang -n dummy --debug | |
| working-directory: src | |
| build-and-sign: | |
| name: Build app and sign files (with Trusted Signing) | |
| if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' # only run this step on tagged commits or the main branch | |
| environment: release # must use environment to be able to authenticate with Azure Federated Identity for Trusted Signing | |
| needs: go-test | |
| runs-on: windows-latest | |
| env: # from https://github.com/spiffe/spire/pull/5158 | |
| GOPATH: 'D:\golang\go' | |
| GOCACHE: 'D:\golang\cache' | |
| GOMODCACHE: 'D:\golang\modcache' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: src/go.mod | |
| cache-dependency-path: src/go.sum | |
| - name: Download Go dependencies | |
| run: go mod download | |
| working-directory: src | |
| - name: Install GoReleaser Pro | |
| uses: goreleaser/goreleaser-action@v6 | |
| with: | |
| distribution: goreleaser-pro | |
| install-only: true | |
| env: | |
| GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} | |
| - name: Run GoReleaser (Linux) | |
| run: goreleaser release --split ${{ !startsWith(github.ref, 'refs/tags/v') && '--snapshot' || '' }} ${{ github.event_name == 'schedule' && '--nightly' || ''}} | |
| working-directory: src | |
| env: | |
| GGOOS: linux | |
| GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} | |
| - name: Run GoReleaser (Windows) | |
| run: goreleaser release --split ${{ !startsWith(github.ref, 'refs/tags/v') && '--snapshot' || '' }} ${{ github.event_name == 'schedule' && '--nightly' || ''}} | |
| working-directory: src | |
| env: | |
| GGOOS: windows | |
| GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} | |
| # From https://github.com/Azure/trusted-signing-action/pull/37 | |
| - name: Azure login | |
| uses: azure/login@v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| - name: Trusted Signing | |
| uses: Azure/trusted-signing-action@v0.3.20 | |
| with: | |
| endpoint: https://wus2.codesigning.azure.net/ # from Azure portal | |
| trusted-signing-account-name: DefangLabs # from Azure portal | |
| certificate-profile-name: signed-binary${{ !startsWith(github.ref, 'refs/tags/v') && '-test' || '' }} # from Azure portal | |
| files-folder: ${{ github.workspace }}\src\dist | |
| files-folder-filter: exe # no dll | |
| files-folder-recurse: true | |
| file-digest: SHA256 | |
| timestamp-rfc3161: http://timestamp.acs.microsoft.com | |
| timestamp-digest: SHA256 | |
| exclude-environment-credential: true | |
| exclude-workload-identity-credential: true | |
| exclude-managed-identity-credential: true | |
| exclude-shared-token-cache-credential: true | |
| exclude-visual-studio-credential: true | |
| exclude-visual-studio-code-credential: true | |
| exclude-azure-cli-credential: false | |
| exclude-azure-powershell-credential: true | |
| exclude-azure-developer-cli-credential: true | |
| exclude-interactive-browser-credential: true | |
| - name: Update archives | |
| if: startsWith(github.ref, 'refs/tags/v') # skip this step for snapshots because we don't know the name of the archive | |
| env: | |
| GITHUB_REF_NAME: ${{ github.ref_name }} | |
| # the prefix "defang-win" should match the id in the build section of .goreleaser.yml | |
| run: | | |
| $version = $env:GITHUB_REF_NAME -replace '^v', '' | |
| Compress-Archive -Path defang-win_windows_amd64_v1\* -DestinationPath "defang_${version}_windows_amd64.zip" -Update | |
| Compress-Archive -Path defang-win_windows_arm64*\* -DestinationPath "defang_${version}_windows_arm64.zip" -Update | |
| shell: pwsh | |
| working-directory: src\dist\windows | |
| - name: Upload dist-win folder | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist-win | |
| path: src/dist | |
| if-no-files-found: error | |
| build-and-sign-mac: | |
| name: Build app and sign (MacOS) | |
| if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' # only run this step on tagged commits or the main branch | |
| environment: release | |
| needs: go-test | |
| runs-on: macos-latest # for codesign and notarytool | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: src/go.mod | |
| cache-dependency-path: src/go.sum | |
| # - name: Download Go dependencies | |
| # run: go mod download | |
| # working-directory: src | |
| - name: Run GoReleaser (macOS) | |
| uses: goreleaser/goreleaser-action@v6 | |
| with: | |
| distribution: goreleaser-pro # either 'goreleaser' (default) or 'goreleaser-pro' | |
| # version: latest | |
| args: release --split ${{ !startsWith(github.ref, 'refs/tags/v') && '--snapshot' || '' }} ${{ github.event_name == 'schedule' && '--nightly' || ''}} | |
| workdir: src | |
| env: | |
| GGOOS: darwin | |
| GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} | |
| MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }} | |
| MACOS_P12_BASE64: ${{ secrets.MACOS_P12_BASE64 }} | |
| MACOS_P12_PASSWORD: ${{ secrets.MACOS_P12_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }} | |
| MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} | |
| MACOS_NOTARIZATION_APP_PW: ${{ secrets.MACOS_NOTARIZATION_APP_PW }} | |
| - name: Upload dist-mac folder | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist-mac | |
| path: src/dist | |
| if-no-files-found: error | |
| go-release: | |
| if: startsWith(github.ref, 'refs/tags/v') # only run this step on tagged commits | |
| environment: release | |
| needs: | |
| - build-and-sign-mac | |
| - build-and-sign | |
| - go-playground-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # to upload archives as GitHub Releases | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # for release notes | |
| - name: Install Nix (for nix-prefetch-url) | |
| uses: cachix/install-nix-action@v26 | |
| - name: Download dist-mac folder | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dist-mac | |
| path: src/dist | |
| - name: Download dist-win folder | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dist-win | |
| path: src/dist | |
| - name: List files | |
| run: ls -lR src/dist | |
| - name: Set up Go # not sure why this is needed for release | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: src/go.mod | |
| cache-dependency-path: src/go.sum | |
| - name: Run GoReleaser | |
| uses: goreleaser/goreleaser-action@v6 | |
| with: | |
| distribution: goreleaser-pro # either 'goreleaser' (default) or 'goreleaser-pro' | |
| # version: latest | |
| args: continue --merge | |
| workdir: src | |
| env: | |
| GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} | |
| GH_PAT_WINGET: ${{ secrets.GH_PAT_WINGET }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GITHUB_TOKEN is limited to the current repository | |
| DISCORD_WEBHOOK_ID: ${{ secrets.DISCORD_WEBHOOK_ID }} | |
| DISCORD_WEBHOOK_TOKEN: ${{ secrets.DISCORD_WEBHOOK_TOKEN }} | |
| # Make sure this "GH_PAT_WINGET" is still valid and is a Github PAT (Classic) with repo permissions | |
| # https://github.com/orgs/community/discussions/106661 | |
| push-docker: | |
| runs-on: ubuntu-latest | |
| environment: release | |
| needs: | |
| - go-release | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Set up QEMU (for multi-arch builds) | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Build and push Docker images and manifests | |
| working-directory: src | |
| run: make push-images ${{ startsWith(github.ref, 'refs/tags/v') && format('VERSION={0}', github.ref_name) || '' }} | |
| post-release: | |
| runs-on: ubuntu-latest | |
| needs: go-release | |
| environment: release | |
| steps: | |
| - name: Trigger CLI Autodoc | |
| uses: peter-evans/repository-dispatch@v3 | |
| with: | |
| token: ${{ secrets.DOCS_ACTION_TRIGGER_TOKEN }} | |
| repository: DefangLabs/defang-docs | |
| event-type: cli-autodoc | |
| client-payload: '{"version": "${{ github.ref_name }}"}' | |
| - name: Trigger Homebrew Formula Update | |
| uses: peter-evans/repository-dispatch@v3 | |
| with: | |
| token: ${{ secrets.HOMEBREW_ACTION_TRIGGER_TOKEN }} | |
| repository: DefangLabs/homebrew-defang | |
| event-type: update-homebrew-formula | |
| client-payload: '{"version": "${{ github.ref_name }}"}' | |
| - name: Checkout tag | |
| uses: actions/checkout@v4 | |
| - name: Install node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" # same as the version in flake.nix | |
| registry-url: https://registry.npmjs.org | |
| - name: Build npm package | |
| shell: bash | |
| working-directory: ./pkgs/npm | |
| run: | | |
| # Get version number without the 'v' | |
| export version_number=`echo "${{ github.ref_name }}" | cut -c2- ` | |
| echo "Setting version number to ${version_number}" | |
| # update version placeholder in package.json with version matching binary. | |
| npm version ${version_number} | |
| # install dependencies | |
| npm ci --ignore-scripts | |
| # build | |
| npm run build | |
| - run: npm publish --access public | |
| shell: bash | |
| working-directory: ./pkgs/npm | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} | |
| on-failure: | |
| runs-on: ubuntu-latest | |
| if: failure() && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) | |
| needs: [go-release, post-release, nix-shell-test, push-docker] | |
| steps: | |
| - name: Slack Notification | |
| uses: rtCamp/action-slack-notify@v2 | |
| env: | |
| MSG_MINIMAL: actions url | |
| SLACK_COLOR: failure | |
| SLACK_FOOTER: "" | |
| SLACK_MESSAGE: "" | |
| SLACK_TITLE: Defang CLI workflow failed | |
| SLACK_WEBHOOK: ${{ secrets.SLACK_NOTIFIER_WEBHOOK_URL }} |