| on: |
| workflow_call: |
| inputs: |
| go-arch: |
| description: The execution architecture (arm, amd64, etc.) |
| required: true |
| type: string |
| enterprise: |
| description: A flag indicating if this workflow is executing for the enterprise repository. |
| required: true |
| type: string |
| total-runners: |
| description: Number of runners to use for executing non-binary tests. |
| required: true |
| type: string |
| binary-tests: |
| description: Whether to run the binary tests. |
| required: false |
| default: false |
| type: boolean |
| env-vars: |
| description: A map of environment variables as JSON. |
| required: false |
| type: string |
| default: '{}' |
| extra-flags: |
| description: A space-separated list of additional build flags. |
| required: false |
| type: string |
| default: '' |
| runs-on: |
| description: An expression indicating which kind of runners to use. |
| required: false |
| type: string |
| default: ubuntu-latest |
| go-tags: |
| description: A comma-separated list of additional build tags to consider satisfied during the build. |
| required: false |
| type: string |
| name: |
| description: A suffix to append to archived test results |
| required: false |
| default: '' |
| type: string |
| go-test-parallelism: |
| description: The parallelism parameter for Go tests |
| required: false |
| default: 20 |
| type: number |
| timeout-minutes: |
| description: The maximum number of minutes that this workflow should run |
| required: false |
| default: 60 |
| type: number |
| testonly: |
| description: Whether to run the tests tagged with testonly. |
| required: false |
| default: false |
| type: boolean |
| checkout-ref: |
| description: The ref to use for checkout. |
| required: false |
| default: ${{ github.ref }} |
| type: string |
| |
| env: ${{ fromJSON(inputs.env-vars) }} |
| |
| jobs: |
| test-matrix: |
| permissions: |
| id-token: write # Note: this permission is explicitly required for Vault auth |
| contents: read |
| runs-on: ${{ fromJSON(inputs.runs-on) }} |
| steps: |
| - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 |
| with: |
| ref: ${{ inputs.checkout-ref }} |
| - uses: ./.github/actions/set-up-go |
| with: |
| github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} |
| - name: Authenticate to Vault |
| id: vault-auth |
| if: github.repository == 'hashicorp/vault-enterprise' |
| run: vault-auth |
| - name: Fetch Secrets |
| id: secrets |
| if: github.repository == 'hashicorp/vault-enterprise' |
| uses: hashicorp/vault-action@130d1f5f4fe645bb6c83e4225c04d64cfb62de6e |
| with: |
| url: ${{ steps.vault-auth.outputs.addr }} |
| caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} |
| token: ${{ steps.vault-auth.outputs.token }} |
| secrets: | |
| kv/data/github/${{ github.repository }}/datadog-ci DATADOG_API_KEY; |
| kv/data/github/${{ github.repository }}/github-token username-and-token | github-token; |
| kv/data/github/${{ github.repository }}/license license_1 | VAULT_LICENSE_CI; |
| kv/data/github/${{ github.repository }}/license license_2 | VAULT_LICENSE_2; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_API_ADDRESS; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_AUTH_URL; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_CLIENT_ID; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_CLIENT_SECRET; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_RESOURCE_ID; |
| - id: setup-git-private |
| name: Setup Git configuration (private) |
| if: github.repository == 'hashicorp/vault-enterprise' |
| run: | |
| git config --global url."https://${{ steps.secrets.outputs.github-token }}@github.com".insteadOf https://github.com |
| - id: setup-git-public |
| name: Setup Git configuration (public) |
| if: github.repository != 'hashicorp/vault-enterprise' |
| run: | |
| git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN}}@github.com".insteadOf https://github.com |
| - uses: ./.github/actions/set-up-gotestsum |
| - run: mkdir -p test-results/go-test |
| - uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 |
| with: |
| path: test-results/go-test |
| key: go-test-reports-${{ github.run_number }} |
| restore-keys: go-test-reports- |
| - name: List cached results |
| id: list-cached-results |
| run: ls -lhR test-results/go-test |
| - name: Build matrix excluding binary, integration, and testonly tests |
| id: build-non-binary |
| if: ${{ !inputs.testonly }} |
| env: |
| GOPRIVATE: github.com/hashicorp/* |
| run: | |
| # testonly tests need additional build tag though let's exclude them anyway for clarity |
| ( |
| go list ./... | grep -v "_binary" | grep -v "vault/integ" | grep -v "testonly" | gotestsum tool ci-matrix --debug \ |
| --partitions "${{ inputs.total-runners }}" \ |
| --timing-files 'test-results/go-test/*.json' > matrix.json |
| ) |
| - name: Build matrix for tests tagged with testonly |
| if: ${{ inputs.testonly }} |
| env: |
| GOPRIVATE: github.com/hashicorp/* |
| run: | |
| set -exo pipefail |
| # enable glob expansion |
| shopt -s nullglob |
| # testonly tagged tests need an additional tag to be included |
| # also running some extra tests for sanity checking with the testonly build tag |
| ( |
| go list -tags=testonly ./vault/external_tests/{kv,token,*replication-perf*,*testonly*} ./vault/ | gotestsum tool ci-matrix --debug \ |
| --partitions "${{ inputs.total-runners }}" \ |
| --timing-files 'test-results/go-test/*.json' > matrix.json |
| ) |
| # disable glob expansion |
| shopt -u nullglob |
| - name: Capture list of binary tests |
| if: inputs.binary-tests |
| id: list-binary-tests |
| run: | |
| LIST="$(go list ./... | grep "_binary" | xargs)" |
| echo "list=$LIST" >> "$GITHUB_OUTPUT" |
| - name: Build complete matrix |
| id: build |
| run: | |
| set -exo pipefail |
| matrix_file="matrix.json" |
| if [ "${{ inputs.binary-tests}}" == "true" ] && [ -n "${{ steps.list-binary-tests.outputs.list }}" ]; then |
| export BINARY_TESTS="${{ steps.list-binary-tests.outputs.list }}" |
| jq --arg BINARY "${BINARY_TESTS}" --arg BINARY_INDEX "${{ inputs.total-runners }}" \ |
| '.include += [{ |
| "id": $BINARY_INDEX, |
| "estimatedRuntime": "N/A", |
| "packages": $BINARY, |
| "description": "partition $BINARY_INDEX - binary test packages" |
| }]' matrix.json > new-matrix.json |
| matrix_file="new-matrix.json" |
| fi |
| # convert the json to a map keyed by id |
| ( |
| echo -n "matrix=" |
| jq -c \ |
| '.include | map( { (.id|tostring): . } ) | add' "$matrix_file" |
| ) >> "$GITHUB_OUTPUT" |
| # extract an array of ids from the json |
| ( |
| echo -n "matrix_ids=" |
| jq -c \ |
| '[ .include[].id | tostring ]' "$matrix_file" |
| ) >> "$GITHUB_OUTPUT" |
| outputs: |
| matrix: ${{ steps.build.outputs.matrix }} |
| matrix_ids: ${{ steps.build.outputs.matrix_ids }} |
| |
| test-go: |
| needs: test-matrix |
| permissions: |
| actions: read |
| contents: read |
| id-token: write # Note: this permission is explicitly required for Vault auth |
| runs-on: ${{ fromJSON(inputs.runs-on) }} |
| strategy: |
| fail-fast: false |
| matrix: |
| id: ${{ fromJSON(needs.test-matrix.outputs.matrix_ids) }} |
| env: |
| GOPRIVATE: github.com/hashicorp/* |
| TIMEOUT_IN_MINUTES: ${{ inputs.timeout-minutes }} |
| steps: |
| - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 |
| with: |
| ref: ${{ inputs.checkout-ref }} |
| - uses: ./.github/actions/set-up-go |
| with: |
| github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} |
| - name: Authenticate to Vault |
| id: vault-auth |
| if: github.repository == 'hashicorp/vault-enterprise' |
| run: vault-auth |
| - name: Fetch Secrets |
| id: secrets |
| if: github.repository == 'hashicorp/vault-enterprise' |
| uses: hashicorp/vault-action@130d1f5f4fe645bb6c83e4225c04d64cfb62de6e |
| with: |
| url: ${{ steps.vault-auth.outputs.addr }} |
| caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} |
| token: ${{ steps.vault-auth.outputs.token }} |
| secrets: | |
| kv/data/github/${{ github.repository }}/datadog-ci DATADOG_API_KEY; |
| kv/data/github/${{ github.repository }}/github-token username-and-token | github-token; |
| kv/data/github/${{ github.repository }}/license license_1 | VAULT_LICENSE_CI; |
| kv/data/github/${{ github.repository }}/license license_2 | VAULT_LICENSE_2; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_API_ADDRESS; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_AUTH_URL; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_CLIENT_ID; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_CLIENT_SECRET; |
| kv/data/github/${{ github.repository }}/hcp-link HCP_RESOURCE_ID; |
| - id: setup-git-private |
| name: Setup Git configuration (private) |
| if: github.repository == 'hashicorp/vault-enterprise' |
| run: | |
| git config --global url."https://${{ steps.secrets.outputs.github-token }}@github.com".insteadOf https://github.com |
| - id: setup-git-public |
| name: Setup Git configuration (public) |
| if: github.repository != 'hashicorp/vault-enterprise' |
| run: | |
| git config --global url."https://${{ secrets.ELEVATED_GITHUB_TOKEN}}@github.com".insteadOf https://github.com |
| - id: build |
| if: inputs.binary-tests && matrix.id == inputs.total-runners |
| env: |
| GOPRIVATE: github.com/hashicorp/* |
| run: time make ci-bootstrap dev |
| - uses: ./.github/actions/set-up-gotestsum |
| - id: run-go-tests |
| name: Run Go tests |
| timeout-minutes: ${{ fromJSON(env.TIMEOUT_IN_MINUTES) }} |
| env: |
| COMMIT_SHA: ${{ github.sha }} |
| run: | |
| set -exo pipefail |
| |
| # Build the dynamically generated source files. |
| make prep |
| |
| packages=$(echo "${{ toJSON(needs.test-matrix.outputs.matrix) }}" | jq -c -r --arg id "${{ matrix.id }}" '.[$id] | .packages') |
| |
| if [ -z "$packages" ]; then |
| echo "no test packages to run" |
| exit 1 |
| fi |
| # We don't want VAULT_LICENSE set when running Go tests, because that's |
| # not what developers have in their environments and it could break some |
| # tests; it would be like setting VAULT_TOKEN. However some non-Go |
| # CI commands, like the UI tests, shouldn't have to worry about licensing. |
| # So we provide the tests which want an externally supplied license with licenses |
| # via the VAULT_LICENSE_CI and VAULT_LICENSE_2 environment variables, and here we unset it. |
| # shellcheck disable=SC2034 |
| VAULT_LICENSE= |
| |
| # Assign test licenses to relevant variables if they aren't already |
| if [[ ${{ github.repository }} == 'hashicorp/vault' ]]; then |
| export VAULT_LICENSE_CI=${{ secrets.ci_license }} |
| export VAULT_LICENSE_2=${{ secrets.ci_license_2 }} |
| export HCP_API_ADDRESS=${{ secrets.HCP_API_ADDRESS }} |
| export HCP_AUTH_URL=${{ secrets.HCP_AUTH_URL }} |
| export HCP_CLIENT_ID=${{ secrets.HCP_CLIENT_ID }} |
| export HCP_CLIENT_SECRET=${{ secrets.HCP_CLIENT_SECRET }} |
| export HCP_RESOURCE_ID=${{ secrets.HCP_RESOURCE_ID }} |
| # Temporarily removing this variable to cause HCP Link tests |
| # to be skipped. |
| #export HCP_SCADA_ADDRESS=${{ secrets.HCP_SCADA_ADDRESS }} |
| fi |
| |
| if [ -f bin/vault ]; then |
| VAULT_BINARY="$(pwd)/bin/vault" |
| export VAULT_BINARY |
| fi |
| |
| # On a release branch, add a flag to rerun failed tests |
| # shellcheck disable=SC2193 # can get false positive for this comparision |
| if [[ "${{ github.base_ref }}" == release/* ]] || [[ -z "${{ github.base_ref }}" && "${{ github.ref_name }}" == release/* ]] |
| then |
| RERUN_FAILS="--rerun-fails" |
| fi |
| |
| # shellcheck disable=SC2086 # can't quote RERUN_FAILS |
| GOARCH=${{ inputs.go-arch }} \ |
| gotestsum --format=short-verbose \ |
| --junitfile test-results/go-test/results-${{ matrix.id }}.xml \ |
| --jsonfile test-results/go-test/results-${{ matrix.id }}.json \ |
| --jsonfile-timing-events failure-summary-${{ matrix.id }}${{ inputs.name != '' && '-' || '' }}${{ inputs.name }}.json \ |
| $RERUN_FAILS \ |
| --packages "$packages" \ |
| -- \ |
| -tags "${{ inputs.go-tags }}" \ |
| -timeout=${{ env.TIMEOUT_IN_MINUTES }}m \ |
| -parallel=${{ inputs.go-test-parallelism }} \ |
| ${{ inputs.extra-flags }} \ |
| - name: Prepare datadog-ci |
| if: github.repository == 'hashicorp/vault' && (success() || failure()) |
| continue-on-error: true |
| run: | |
| curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" |
| chmod +x /usr/local/bin/datadog-ci |
| - name: Upload test results to DataDog |
| continue-on-error: true |
| env: |
| DD_ENV: ci |
| run: | |
| if [[ ${{ github.repository }} == 'hashicorp/vault' ]]; then |
| export DATADOG_API_KEY=${{ secrets.DATADOG_API_KEY }} |
| fi |
| datadog-ci junit upload --service "$GITHUB_REPOSITORY" test-results/go-test/results-${{ matrix.id }}.xml |
| if: success() || failure() |
| - name: Archive test results |
| uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 |
| with: |
| name: test-results${{ inputs.name != '' && '-' || '' }}${{ inputs.name }} |
| path: test-results/go-test |
| if: success() || failure() |
| # GitHub Actions doesn't expose the job ID or the URL to the job execution, |
| # so we have to fetch it from the API |
| - name: Fetch job logs URL |
| uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 |
| if: success() || failure() |
| continue-on-error: true |
| with: |
| retries: 3 |
| script: | |
| // We surround the whole script with a try-catch block, to avoid each of the matrix jobs |
| // displaying an error in the GHA workflow run annotations, which gets very noisy. |
| // If an error occurs, it will be logged so that we don't lose any information about the reason for failure. |
| try { |
| const fs = require("fs"); |
| const result = await github.rest.actions.listJobsForWorkflowRun({ |
| owner: context.repo.owner, |
| per_page: 100, |
| repo: context.repo.repo, |
| run_id: context.runId, |
| }); |
| |
| // Determine what job name to use for the query. These values are hardcoded, because GHA doesn't |
| // expose them in any of the contexts available within a workflow run. |
| let prefixToSearchFor; |
| switch ("${{ inputs.name }}") { |
| case "race": |
| prefixToSearchFor = 'Run Go tests with data race detection / test-go (${{ matrix.id }})' |
| break |
| case "fips": |
| prefixToSearchFor = 'Run Go tests with FIPS configuration / test-go (${{ matrix.id }})' |
| break |
| default: |
| prefixToSearchFor = 'Run Go tests / test-go (${{ matrix.id }})' |
| } |
| |
| const jobData = result.data.jobs.filter( |
| (job) => job.name.startsWith(prefixToSearchFor) |
| ); |
| const url = jobData[0].html_url; |
| const envVarName = "GH_JOB_URL"; |
| const envVar = envVarName + "=" + url; |
| const envFile = process.env.GITHUB_ENV; |
| |
| fs.appendFile(envFile, envVar, (err) => { |
| if (err) throw err; |
| console.log("Successfully set " + envVarName + " to: " + url); |
| }); |
| } catch (error) { |
| console.log("Error: " + error); |
| return |
| } |
| - name: Prepare failure summary |
| if: success() || failure() |
| continue-on-error: true |
| run: | |
| # This jq query filters out successful tests, leaving only the failures. |
| # Then, it formats the results into rows of a Markdown table. |
| # An example row will resemble this: |
| # | github.com/hashicorp/vault/package | TestName | fips | 0 | 2 | [view results](github.com/link-to-logs) | |
| jq -r -n 'inputs |
| | select(.Action == "fail") |
| | "| ${{inputs.name}} | \(.Package) | \(.Test // "-") | \(.Elapsed) | ${{ matrix.id }} | [view test results :scroll:](${{ env.GH_JOB_URL }}) |"' \ |
| failure-summary-${{ matrix.id }}${{ inputs.name != '' && '-' || '' }}${{inputs.name}}.json \ |
| >> failure-summary-${{ matrix.id }}${{ inputs.name != '' && '-' || '' }}${{inputs.name}}.md |
| - name: Upload failure summary |
| uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 |
| if: success() || failure() |
| with: |
| name: failure-summary |
| path: failure-summary-${{ matrix.id }}${{ inputs.name != '' && '-' || '' }}${{inputs.name}}.md |
| |
| test-collect-reports: |
| if: ${{ ! cancelled() }} |
| needs: test-go |
| runs-on: ${{ fromJSON(inputs.runs-on) }} |
| steps: |
| - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 |
| with: |
| path: test-results/go-test |
| key: go-test-reports-${{ github.run_number }} |
| restore-keys: go-test-reports- |
| - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 |
| with: |
| name: test-results |
| path: test-results/go-test |
| - run: | |
| ls -lhR test-results/go-test |
| find test-results/go-test -mindepth 1 -mtime +3 -delete |
| ls -lhR test-results/go-test |