Skip to content

Test Provider CI

Test Provider CI #3505

permissions: write-all # Equivalent to default permissions plus id-token: write
name: Test Provider CI
on:
pull_request:
merge_group: {}
workflow_dispatch: {}
env:
ESC_ACTION_OIDC_AUTH: true
ESC_ACTION_OIDC_ORGANIZATION: pulumi
ESC_ACTION_OIDC_REQUESTED_TOKEN_TYPE: urn:pulumi:token-type:access_token:organization
ESC_ACTION_ENVIRONMENT: github-secrets/pulumi-ci-mgmt
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: Verify against testdata
runs-on: ubuntu-latest
steps:
- name: Fetch secrets from ESC
id: esc-secrets
uses: pulumi/esc-action@8afe12bb7bb3df0a599e5309ee429ff1079ba85f # v3
- name: Checkout Repo
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Configure git
# Set the default branch to silence the warnings about the default branch name changing
# The branch doesn't matter here because it's only used for a temp repo for actionlint
run: git config --global init.defaultBranch master
- name: Install mise
uses: jdx/mise-action@8d3b0ba20a9cea7b883d922ea958553c941ab082
with:
version: 2026.3.7
- name: Build & test
run: cd provider-ci && make all
- name: Check worktree clean
uses: pulumi/git-status-check-action@0d90c81496aa8d6a31d9c6a0d6297feea2f54057 # v2
deploy:
name: Apply ci-mgmt changes (pulumi/pulumi-${{ matrix.provider }})
strategy:
matrix:
provider: [xyz, provider-boilerplate]
uses: ./.github/workflows/update-workflows.yml
secrets: inherit
with:
provider_name: ${{ matrix.provider }}
automerge: ${{ github.event_name == 'merge_group' }}
downstream_test: true
skip_closing_prs: true
caller_workflow: "pull-request"
downstream:
name: Test and release provider (${{ matrix.repo }})
runs-on: ubuntu-latest
needs: deploy
strategy:
fail-fast: false
matrix:
repo:
- pulumi/pulumi-xyz
- pulumi/pulumi-provider-boilerplate
steps:
- name: Fetch secrets from ESC
id: esc-secrets
uses: pulumi/esc-action@8afe12bb7bb3df0a599e5309ee429ff1079ba85f # v3
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-auth
with:
app-id: ${{ steps.esc-secrets.outputs.PULUMI_PROVIDER_AUTOMATION_APP_ID }}
private-key: ${{ steps.esc-secrets.outputs.PULUMI_PROVIDER_AUTOMATION_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Await PR opened for ${{ matrix.repo }}
id: pr_opened
timeout-minutes: 1
continue-on-error: true # Fall through if a PR wasn't created.
run: |
echo Await PR opened for ${{ matrix.repo }}
until gh search prs --repo ${{ matrix.repo }} --match body "This PR was automatically generated by the pull-request workflow in the pulumi/ci-mgmt repo, from commit ${{ github.sha }}." --json url | grep url; do sleep 30; done;
echo "pull_request_created=true" >> "${GITHUB_OUTPUT}"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Find PR number
if: steps.pr_opened.outputs.pull_request_created == 'true'
id: pr_number
run: |
number=$(gh search prs --repo ${{ matrix.repo }} --match body "This PR was automatically generated by the pull-request workflow in the pulumi/ci-mgmt repo, from commit ${{ github.sha }}." --json number --jq '.[0].number')
echo "PR number is $number"
echo "number=${number}" >> "${GITHUB_OUTPUT}"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Add needs-release label
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
run: gh pr edit --repo "${{ matrix.repo }}" "${{ steps.pr_number.outputs.number }}" --add-label "needs-release/patch"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Await required checks start
if: steps.pr_opened.outputs.pull_request_created == 'true'
timeout-minutes: 60
# Wait for at least 3 checks to be started before we start waiting for them to finish.
# There's a couple of quick checks like comment notification and changelog which are started before the PR checks.
run: while [[ ! $(gh pr checks --required --repo "${{ matrix.repo }}" "${{ steps.pr_number.outputs.number }}") ]]; do sleep 1; done
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Await required checks succeed
if: steps.pr_opened.outputs.pull_request_created == 'true'
timeout-minutes: 10
run: gh pr checks --required --repo "${{ matrix.repo }}" "${{ steps.pr_number.outputs.number }}" --watch --fail-fast
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Close test PR
if: github.event_name != 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
run: gh pr close --repo "${{ matrix.repo }}" "${{ steps.pr_number.outputs.number }}"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
# The following steps are only run in the merge queue and confirm we
# were able to successfully release.
- name: Await PR merged
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
run: while [[ $(gh pr view --repo "${{ matrix.repo }}" "${{ steps.pr_number.outputs.number }}" --json "state" --jq ".state") == "OPEN" ]]; do sleep 1; done
timeout-minutes: 10
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Get merge commit
id: merge_commit
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
run: |
merge_commit_oid=$(gh pr view --repo "${{ matrix.repo }}" "${{ steps.pr_number.outputs.number }}" --json "mergeCommit" --jq ".mergeCommit.oid")
if [[ -z "${merge_commit_oid}" ]]; then
echo "Failed to get merge commit"
exit 1
fi
echo "Merge commit oid is ${merge_commit_oid}"
echo "oid=${merge_commit_oid}" >> "${GITHUB_OUTPUT}"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Await main build start
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
id: main_build
run: |
until (gh run list --repo "${{ matrix.repo }}" --workflow main --json headSha | grep -q "${{ steps.merge_commit.outputs.oid }}"); do sleep 1; done
database_id=$(gh run list --repo "${{ matrix.repo }}" --workflow main --json "number,headSha,databaseId" | jq '.[] | select(.headSha == "${{ steps.merge_commit.outputs.oid }}") | .databaseId')
echo "Main build started with database id ${database_id}"
echo "id=${database_id}" >> "${GITHUB_OUTPUT}"
timeout-minutes: 5
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Await main build success
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
timeout-minutes: 60
run: gh run watch --repo "${{ matrix.repo }}" "${{ steps.main_build.outputs.id }}" --exit-status
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Get tag for release
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
id: release_tag
timeout-minutes: 5
run: |
until (git ls-remote --tags "https://github.com/${{ matrix.repo }}.git" | grep -q "${{ steps.merge_commit.outputs.oid }}"); do sleep 1; done
# Also handle annotated tags in the format refs/tags/v0.1.0^{}
tag=$(git ls-remote --tags "https://github.com/${{ matrix.repo }}.git" | grep "${{ steps.merge_commit.outputs.oid }}" | cut -d '/' -f 3 | sed -E 's/\^\{\}$//')
echo "Tag for release is ${tag}"
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Await release workflow run
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
id: release_workflow
timeout-minutes: 10
run: |
until (gh run list --repo "${{ matrix.repo }}" --workflow release --branch "${{ steps.release_tag.outputs.tag }}" --json headBranch | grep -q "${{ steps.release_tag.outputs.tag }}"); do sleep 1; done
database_id=$(gh run list --repo "${{ matrix.repo }}" --workflow release --branch "${{ steps.release_tag.outputs.tag }}" --json "databaseId" --jq '.[0].databaseId')
echo "Release workflow started with id ${database_id}"
echo "id=${database_id}" >> "${GITHUB_OUTPUT}"
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}
- name: Await release workflow success
if: github.event_name == 'merge_group' && steps.pr_opened.outputs.pull_request_created == 'true'
timeout-minutes: 60
run: gh run watch --repo "${{ matrix.repo }}" "${{ steps.release_workflow.outputs.id }}" --exit-status
env:
GH_TOKEN: ${{ steps.app-auth.outputs.token }}