Skip to content

chore: skip coverage gate on tagged release #5810

chore: skip coverage gate on tagged release

chore: skip coverage gate on tagged release #5810

Workflow file for this run

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 }}