name: Continuous Integration run-name: Triggered by ${{ github.actor }} on ${{ github.event_name }} on: pull_request: merge_group: types: [checks_requested] workflow_call: inputs: stage: required: true type: string profile: required: true type: string # Cancel old workflow runs if new code is pushed concurrency: group: "ci-${{ github.event_name }}-${{ github.workflow }}-${{ github.ref }}" cancel-in-progress: ${{ github.event_name != 'workflow_call' }} jobs: kotlin: uses: ./.github/workflows/_kotlin.yml secrets: inherit swift: uses: ./.github/workflows/_swift.yml secrets: inherit elixir: uses: ./.github/workflows/_elixir.yml rust: uses: ./.github/workflows/_rust.yml secrets: inherit static-analysis: uses: ./.github/workflows/_static-analysis.yml terraform: uses: ./.github/workflows/_terraform.yml secrets: inherit codeql: uses: ./.github/workflows/_codeql.yml secrets: inherit update-release-draft: name: update-release-draft-${{ matrix.config_name }} runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: include: # mark:next-gateway-version - release_name: gateway-1.4.4 config_name: release-drafter-gateway.yml # mark:next-headless-version - release_name: headless-client-1.4.2 config_name: release-drafter-headless-client.yml steps: - uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0 # Only draft releases on merges to main if: ${{ github.ref_name == 'main' }} id: update-release-draft with: config-name: ${{ matrix.config_name }} tag: ${{ matrix.release_name }} version: ${{ matrix.release_name }} name: ${{ matrix.release_name }} commitish: ${{ github.sha }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} tauri: uses: ./.github/workflows/_tauri.yml secrets: inherit build-artifacts: needs: update-release-draft uses: ./.github/workflows/_build_artifacts.yml secrets: inherit with: # Build debug/ on PRs and merge group, no prefix for production release images image_prefix: ${{ ((github.event_name == 'pull_request' || github.event_name == 'merge_group') && 'debug') || '' }} profile: ${{ inputs.profile || 'debug' }} stage: ${{ inputs.stage || 'debug' }} build-perf-artifacts: needs: update-release-draft uses: ./.github/workflows/_build_artifacts.yml secrets: inherit with: sha: ${{ github.sha }} image_prefix: "perf" profile: "release" stage: "debug" # Only the debug images have perf tooling integration-tests: uses: ./.github/workflows/_integration_tests.yml needs: build-artifacts secrets: inherit with: gateway_image: ${{ needs.build-artifacts.outputs.gateway_image }} client_image: ${{ needs.build-artifacts.outputs.client_image }} relay_image: ${{ needs.build-artifacts.outputs.relay_image }} http_test_server_image: ${{ needs.build-artifacts.outputs.http_test_server_image }} compatibility-tests: strategy: fail-fast: false matrix: client: - image: "ghcr.io/firezone/client" tag: "latest" gateway: - image: ${{ needs.build-artifacts.outputs.gateway_image }} tag: ${{ github.sha }} ci-name: sha - image: "ghcr.io/firezone/gateway" tag: "latest" ci-name: latest # Don't run compatibility tests when called from hotfix.yml or publish.yml on `main` because # it'll be red if there was a breaking change we're trying to publish, # and the deploy_production workflow checks for main to be green. if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }} name: compatibility-tests-client(${{ matrix.client.tag }})-gateway(${{ matrix.gateway.ci-name }}) uses: ./.github/workflows/_integration_tests.yml needs: build-artifacts secrets: inherit with: gateway_image: ${{ matrix.gateway.image }} gateway_tag: ${{ matrix.gateway.tag }} client_image: ${{ matrix.client.image }} client_tag: ${{ matrix.client.tag }} perf-tests: name: perf-tests needs: build-perf-artifacts runs-on: ubuntu-22.04 permissions: contents: read id-token: write pull-requests: write env: API_IMAGE: "us-east1-docker.pkg.dev/firezone-staging/firezone/api" API_TAG: ${{ github.sha }} WEB_IMAGE: "us-east1-docker.pkg.dev/firezone-staging/firezone/web" WEB_TAG: ${{ github.sha }} ELIXIR_IMAGE: "us-east1-docker.pkg.dev/firezone-staging/firezone/elixir" ELIXIR_TAG: ${{ github.sha }} GATEWAY_IMAGE: "us-east1-docker.pkg.dev/firezone-staging/firezone/perf/gateway" GATEWAY_TAG: ${{ github.sha }} CLIENT_IMAGE: "us-east1-docker.pkg.dev/firezone-staging/firezone/perf/client" CLIENT_TAG: ${{ github.sha }} RELAY_IMAGE: "us-east1-docker.pkg.dev/firezone-staging/firezone/perf/relay" RELAY_TAG: ${{ github.sha }} strategy: fail-fast: false matrix: test_name: - direct-tcp-client2server - direct-tcp-server2client - direct-udp-client2server - direct-udp-server2client - relayed-tcp-client2server - relayed-tcp-server2client - relayed-udp-client2server - relayed-udp-server2client steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: ./.github/actions/gcp-docker-login id: login with: project: firezone-staging - name: Seed database run: docker compose run elixir /bin/sh -c 'cd apps/domain && mix ecto.seed' - name: Start docker compose in the background run: | # We need to increase the log level to make sure that they don't hold off storm of packets # generated by UDP tests. Wire is especially chatty. sed -i 's/^\(\s*\)RUST_LOG:.*$/\1RUST_LOG: wire=error,info/' docker-compose.yml cat docker-compose.yml | grep RUST_LOG # Start services in the same order each time for the tests docker compose up -d iperf3 docker compose up -d api web domain --no-build docker compose up -d relay-1 relay-2 --no-build docker compose up -d gateway --no-build docker compose up -d client --no-build - name: "Performance test: ${{ matrix.test_name }}" timeout-minutes: 5 env: TEST_NAME: ${{ matrix.test_name }} run: | ./scripts/tests/perf/${{ matrix.test_name }}.sh jq '{ "${{ matrix.test_name }}": { "throughput": { "value": .end.sum_received.bits_per_second } } }' ./${{ matrix.test_name }}.json > ./${{ matrix.test_name }}.bmf.json - name: "Save performance test results: ${{ matrix.test_name }}" uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: overwrite: true name: ${{ matrix.test_name }}-${{ github.sha }}-iperf3results path: ./${{ matrix.test_name }}.bmf.json - name: Show Client logs if: "!cancelled()" run: docker compose logs client - name: Show Client UDP stats if: "!cancelled()" run: docker compose exec client cat /proc/net/udp - name: Show Relay-1 logs if: "!cancelled()" run: docker compose logs relay-1 - name: Show Relay-2 logs if: "!cancelled()" run: docker compose logs relay-2 - name: Show Gateway logs if: "!cancelled()" run: docker compose logs gateway - name: Show Gateway UDP stats if: "!cancelled()" run: docker compose exec gateway cat /proc/net/udp - name: Show API logs if: "!cancelled()" run: docker compose logs api - name: Show iperf3 logs if: "!cancelled()" run: docker compose logs iperf3 upload-bencher: continue-on-error: true needs: perf-tests runs-on: ubuntu-22.04 permissions: contents: read id-token: write pull-requests: write checks: write steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: bencherdev/bencher@main - name: Download performance test results uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: pattern: "*-${{ github.sha }}-iperf3results" merge-multiple: true path: ./${{ github.sha }} - name: Merge benchmarks results into one report run: jq -s 'reduce .[] as $item ({}; . * $item)' ./${{ github.sha }}/*.bmf.json > bmf.json - name: Report results to bencher run: | bencher run \ --project firezone-1l75jv1z \ --testbed github-actions \ --file bmf.json \ --adapter json \ --branch "${{ github.head_ref || github.ref_name }}" \ --branch-start-point "${{ github.base_ref }}" \ --github-actions ${{ secrets.GITHUB_TOKEN }} \ --ci-only-on-alert env: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}