pulumi/pulumi

28 workflows · maturity 67% · 13 patterns · GitHub ↗

Security 37.86/100

Security dimensions

permissions
17.9
security scan
0
supply chain
20
secret handling
0
harden runner
0

Workflows (28)

ci matrix perms .github/workflows/ci.yml
Triggers
workflow_call
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
matrix, lint, build-binaries, build-display-wasm-module, build-sdks, unit-test, integration-test, acceptance-test-win, acceptance-test-macos, fuzz-test, test-collect-reports, test-collect-coverage, build-release-binaries
Matrix
target→ ${{ fromJson(needs.matrix.outputs.build-targets) }}
Actions
jdx/mise-action, codecov/codecov-action
Commands
  • echo "$CACHE_KEY" > .gocache.tmp
  • cd vendor/gotestsum go install .
  • SDKS='' make install
  • echo "::group::Prime test timing data" mkdir -p test-results find test-results -type f -empty -print -delete || true echo "::endgroup::" echo "::group::Remove old test timing data" # Timing data prior to this date is unreliable. Codegen tests modified in #11052 and # merged Monday Oct 17 at 6PM Pacific. find test-results -type f ! -newermt "2022-10-17T18:00-07:00" -print -delete || true echo "::endgroup::" echo "::group::Test matrix variables" readarray -td' ' VERSION_SETS_TO_TEST < <(echo -n "$TEST_VERSION_SETS"); declare -p VERSION_SETS_TO_TEST; readarray -td' ' INTEGRATION_PLATFORMS < <(echo -n "$INPUT_INTEGRATION_TEST_PLATFORMS"); declare -p INTEGRATION_PLATFORMS; readarray -td' ' ACCEPTANCE_PLATFORMS < <(echo -n "$INPUT_ACCEPTANCE_TEST_PLATFORMS"); declare -p ACCEPTANCE_PLATFORMS; BUILD_TARGETS='[ { "os": "linux", "arch": "amd64", "build-platform": "ubuntu-latest" }, { "os": "linux", "arch": "arm64", "build-platform": "ubuntu-latest" }, { "os": "windows", "arch": "amd64", "build-platform": "ubuntu-latest" }, { "os": "windows", "arch": "arm64", "build-platform": "ubuntu-latest" }, { "os": "darwin", "arch": "amd64", "build-platform": "ubuntu-latest" }, { "os": "darwin", "arch": "arm64", "build-platform": "ubuntu-latest" } ]' CODEGEN_TESTS_FLAG=--codegen-tests PKG_UNIT_TEST_PARTITIONS=7 UNIT_TEST_MATRIX=$( ./scripts/get-job-matrix.py \ -vvv \ generate-matrix \ --kind unit-test \ "$CODEGEN_TESTS_FLAG" \ --platform "${INTEGRATION_PLATFORMS[@]}" "${ACCEPTANCE_PLATFORMS[@]}" \ --version-set current \ --partition-module pkg "$PKG_UNIT_TEST_PARTITIONS" \ --partition-module sdk 1 \ --partition-module sdk/go/pulumi-language-go 1 \ --partition-module tests 8 ) INTEGRATION_TEST_MATRIX=$( ./scripts/get-job-matrix.py \ -vvv \ generate-matrix \ --kind integration-test \ "$CODEGEN_TESTS_FLAG" \ --platform "${INTEGRATION_PLATFORMS[@]}" \ --version-set "${VERSION_SETS_TO_TEST[@]}" \ --partition-module pkg 1 \ --partition-module sdk 1 \ --partition-module sdk/go/pulumi-language-go 1 \ --partition-package github.com/pulumi/pulumi/sdk/pcl/v3/cmd/pulumi-language-pcl \ sdk/pcl/cmd/pulumi-language-pcl 2 \ --partition-package github.com/pulumi/pulumi/sdk/nodejs/cmd/pulumi-language-nodejs/v3 \ sdk/nodejs/cmd/pulumi-language-nodejs 3 \ --partition-package github.com/pulumi/pulumi/sdk/python/cmd/pulumi-language-python/v3 \ sdk/python/cmd/pulumi-language-python 4 \ --partition-module tests 2 \ --partition-package github.com/pulumi/pulumi/tests/smoke tests/smoke 4 \ --partition-package github.com/pulumi/pulumi/tests/integration tests/integration 8 ) LOWEST_PYTHON_DEPS_TEST_MATRIX=$( ./scripts/get-job-matrix.py \ -vvv \ generate-matrix \ --kind lowest-python-deps-test \ --platform ubuntu-latest \ --version-set minimum ) INTEGRATION_TEST_MATRIX=$( ./scripts/get-job-matrix.py \ combine-matrices \ "${INTEGRATION_TEST_MATRIX}" \ "${LOWEST_PYTHON_DEPS_TEST_MATRIX}" ) ACCEPTANCE_TEST_MATRIX_WIN="{}" if [[ " ${ACCEPTANCE_PLATFORMS[*]} " =~ [[:space:]]windows-latest[[:space:]] ]]; then ACCEPTANCE_TEST_MATRIX_WIN=$( ./scripts/get-job-matrix.py \ -vvv \ generate-matrix \ --kind acceptance-test \ "$CODEGEN_TESTS_FLAG" \ --platform windows-latest \ --version-set current \ --partition-module pkg 2 \ --partition-module sdk 1 \ --partition-module tests 3 \ --partition-package github.com/pulumi/pulumi/tests/smoke tests/smoke 4 \ --partition-package github.com/pulumi/pulumi/tests/integration tests/integration 8 ) fi ACCEPTANCE_TEST_MATRIX_MACOS="{}" if [[ " ${ACCEPTANCE_PLATFORMS[*]} " =~ [[:space:]]macos-latest[[:space:]] ]]; then ACCEPTANCE_TEST_MATRIX_MACOS=$( ./scripts/get-job-matrix.py \ -vvv \ generate-matrix \ --kind acceptance-test \ "$CODEGEN_TESTS_FLAG" \ --platform macos-latest \ --version-set current \ --partition-module pkg 1 \ --partition-module sdk 1 \ --partition-module tests 4 \ --partition-package github.com/pulumi/pulumi/tests/smoke tests/smoke 4 \ --partition-package github.com/pulumi/pulumi/tests/integration tests/integration 8 ) fi echo "::endgroup::" echo "::group::Version set variable" VERSION_SET=$(./scripts/get-job-matrix.py \ generate-version-set \ --version-set current ) echo "::endgroup::" echo "::group::Unit test matrix" echo "$UNIT_TEST_MATRIX" | yq -P '.' echo "::endgroup::" echo "::group::Integration test matrix" echo "$INTEGRATION_TEST_MATRIX" | yq -P '.' echo "::endgroup::" echo "::group::acceptance test matrix windows" echo "$ACCEPTANCE_TEST_MATRIX_WIN" | yq -P '.' echo "::endgroup::" echo "::group::acceptance test matrix macos" echo "$ACCEPTANCE_TEST_MATRIX_MACOS" | yq -P '.' echo "::endgroup::" echo "::group::Version set" echo "$VERSION_SET" | yq -P '.' echo "::endgroup::" echo "::group::Set outputs" ./.github/scripts/set-output unit-test-matrix "${UNIT_TEST_MATRIX}" ./.github/scripts/set-output integration-test-matrix "${INTEGRATION_TEST_MATRIX}" ./.github/scripts/set-output acceptance-test-matrix-win "${ACCEPTANCE_TEST_MATRIX_WIN}" ./.github/scripts/set-output acceptance-test-matrix-macos "${ACCEPTANCE_TEST_MATRIX_MACOS}" ./.github/scripts/set-output version-set "${VERSION_SET}" ./.github/scripts/set-output build-targets "${BUILD_TARGETS}" echo "::endgroup::"
  • ls -lhR test-results find test-results -mindepth 1 -name '*.json' -mtime +7 -delete
  • JSON='${{ toJson(needs) }}' if test -z "$(echo $JSON | jq -r '.[] | .result' | grep -v 'success')"; then echo "Tests OK!" else echo "Test Failure.. skipping CodeCov upload." exit 1 fi
  • curl -Os https://cli.codecov.io/latest/linux/codecov sudo chmod +x codecov ./codecov pr-base-picking --base-sha "$(git merge-base origin/master HEAD)" --pr ${{ github.event.number }} --slug pulumi/pulumi --token ${{ secrets.CODECOV_TOKEN }} --service github
View raw YAML
name: CI

permissions:
  contents: read
  id-token: write

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      lint:
        required: false
        default: true
        description: "Whether to run lints"
        type: boolean
      test-version-sets:
        required: false
        default: minimum current
        description: Version sets on which to run integration tests
        type: string
      integration-test-platforms:
        required: false
        default: ubuntu-latest
        description: Platforms on which to run integration tests, as a space delimited list
        type: string
      acceptance-test-platforms:
        required: false
        default: macos-latest
        description: Platforms on which to run integration tests, as a space delimited list
        type: string
      enable-coverage:
        description: "Collects coverage stats; requires cov-enabled builds"
        default: false
        required: false
        type: boolean
      fail-fast:
        required: false
        default: false
        description: "Fail all workflows whenever one of them fails"
        type: boolean
      test-retries:
        required: false
        default: 0
        description: "Retry tests n times if there are failures"
        type: number
      fuzz-test-optional:
        required: false
        default: false
        description: "If true, fuzz test failures won't block the workflow"
        type: boolean
    secrets:
      PULUMI_PROD_ACCESS_TOKEN:
        required: false
        description: "Pulumi access token, required to run tests against the service"
      CODECOV_TOKEN:
        required: false
        description: "CodeCov token, required to publish CodeCov coverage data"
      AZURE_TENANT_ID:
        required: false
        description: "Azure tenant ID, required to run tests against Azure"
      AZURE_CLIENT_ID:
        required: false
        description: "Azure client ID, required to run tests against Azure"
      AZURE_CLIENT_SECRET:
        required: false
        description: "Azure clients secret, needs to be rotated before 2027-12-22 (see the TestAzureLoginAzLogin test for detailed instructions)"
      AZURE_STORAGE_SAS_TOKEN:
        required: false
        description: "Azure storage SAS token, required to run tests against Azure"
      GCP_SERVICE_ACCOUNT:
        required: false
        description: "GCP service account, required to run tests against GCP"

jobs:
  matrix:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Configure Go Cache Key
        env:
          CACHE_KEY: "matrix-setup"
        run: echo "$CACHE_KEY" > .gocache.tmp
      - name: Setup Go Caching
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 # only used by gotestsum
        with:
          go-version: '>=1.19.0' # decoupled from version sets, only used by gotestsum
          cache: true
          cache-dependency-path: |
            pkg/go.sum
            .gocache.tmp
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          repository: dnephin/gotestsum
          ref: d09768c81065b404caed0855eb3ab8f11a2a4431
          path: vendor/gotestsum
      - run: |
          cd vendor/gotestsum
          go install .
      - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
        with:
          path: test-results
          key: read-gotestsum-timing-${{ github.run_number }}
          restore-keys: gotestsum-timing-
      - uses: jdx/mise-action@v2
        with:
          experimental: true
      - name: Install CLI
        run: SDKS='' make install
      - name: build matrix
        id: matrix
        env:
          TEST_VERSION_SETS: ${{ inputs.test-version-sets }}
          INPUT_INTEGRATION_TEST_PLATFORMS: ${{ inputs.integration-test-platforms }}
          INPUT_ACCEPTANCE_TEST_PLATFORMS: ${{ inputs.acceptance-test-platforms }}
        run: |
          echo "::group::Prime test timing data"
          mkdir -p test-results
          find test-results -type f -empty -print -delete || true
          echo "::endgroup::"

          echo "::group::Remove old test timing data"
          # Timing data prior to this date is unreliable. Codegen tests modified in #11052 and
          # merged Monday Oct 17 at 6PM Pacific.
          find test-results -type f ! -newermt "2022-10-17T18:00-07:00" -print -delete || true
          echo "::endgroup::"

          echo "::group::Test matrix variables"
          readarray -td' ' VERSION_SETS_TO_TEST < <(echo -n "$TEST_VERSION_SETS"); declare -p VERSION_SETS_TO_TEST;
          readarray -td' ' INTEGRATION_PLATFORMS < <(echo -n "$INPUT_INTEGRATION_TEST_PLATFORMS"); declare -p INTEGRATION_PLATFORMS;
          readarray -td' ' ACCEPTANCE_PLATFORMS < <(echo -n "$INPUT_ACCEPTANCE_TEST_PLATFORMS"); declare -p ACCEPTANCE_PLATFORMS;
          BUILD_TARGETS='[
              { "os": "linux",   "arch": "amd64", "build-platform": "ubuntu-latest" },
              { "os": "linux",   "arch": "arm64", "build-platform": "ubuntu-latest" },
              { "os": "windows", "arch": "amd64", "build-platform": "ubuntu-latest" },
              { "os": "windows", "arch": "arm64", "build-platform": "ubuntu-latest" },
              { "os": "darwin",  "arch": "amd64", "build-platform": "ubuntu-latest" },
              { "os": "darwin",  "arch": "arm64", "build-platform": "ubuntu-latest" }
          ]'

          CODEGEN_TESTS_FLAG=--codegen-tests
          PKG_UNIT_TEST_PARTITIONS=7

          UNIT_TEST_MATRIX=$(
            ./scripts/get-job-matrix.py \
            -vvv \
            generate-matrix \
            --kind unit-test \
            "$CODEGEN_TESTS_FLAG" \
            --platform "${INTEGRATION_PLATFORMS[@]}" "${ACCEPTANCE_PLATFORMS[@]}" \
            --version-set current \
            --partition-module pkg "$PKG_UNIT_TEST_PARTITIONS" \
            --partition-module sdk 1 \
            --partition-module sdk/go/pulumi-language-go 1 \
            --partition-module tests 8
          )

          INTEGRATION_TEST_MATRIX=$(
            ./scripts/get-job-matrix.py \
            -vvv \
            generate-matrix \
            --kind integration-test \
            "$CODEGEN_TESTS_FLAG" \
            --platform "${INTEGRATION_PLATFORMS[@]}" \
            --version-set "${VERSION_SETS_TO_TEST[@]}" \
            --partition-module pkg 1 \
            --partition-module sdk 1 \
            --partition-module sdk/go/pulumi-language-go 1 \
            --partition-package github.com/pulumi/pulumi/sdk/pcl/v3/cmd/pulumi-language-pcl \
                sdk/pcl/cmd/pulumi-language-pcl 2 \
            --partition-package github.com/pulumi/pulumi/sdk/nodejs/cmd/pulumi-language-nodejs/v3 \
                sdk/nodejs/cmd/pulumi-language-nodejs 3 \
            --partition-package github.com/pulumi/pulumi/sdk/python/cmd/pulumi-language-python/v3 \
                sdk/python/cmd/pulumi-language-python 4 \
            --partition-module tests 2 \
            --partition-package github.com/pulumi/pulumi/tests/smoke tests/smoke 4 \
            --partition-package github.com/pulumi/pulumi/tests/integration tests/integration 8
          )

          LOWEST_PYTHON_DEPS_TEST_MATRIX=$(
            ./scripts/get-job-matrix.py \
            -vvv \
            generate-matrix \
            --kind lowest-python-deps-test \
            --platform ubuntu-latest \
            --version-set minimum
          )

          INTEGRATION_TEST_MATRIX=$(
            ./scripts/get-job-matrix.py \
            combine-matrices \
            "${INTEGRATION_TEST_MATRIX}" \
            "${LOWEST_PYTHON_DEPS_TEST_MATRIX}"
          )

          ACCEPTANCE_TEST_MATRIX_WIN="{}"
          if [[ " ${ACCEPTANCE_PLATFORMS[*]} " =~ [[:space:]]windows-latest[[:space:]] ]]; then
            ACCEPTANCE_TEST_MATRIX_WIN=$(
              ./scripts/get-job-matrix.py \
              -vvv \
              generate-matrix \
              --kind acceptance-test \
              "$CODEGEN_TESTS_FLAG" \
              --platform windows-latest \
              --version-set current \
              --partition-module pkg 2 \
              --partition-module sdk 1 \
              --partition-module tests 3 \
              --partition-package github.com/pulumi/pulumi/tests/smoke tests/smoke 4 \
              --partition-package github.com/pulumi/pulumi/tests/integration tests/integration 8
            )
          fi

          ACCEPTANCE_TEST_MATRIX_MACOS="{}"
          if [[ " ${ACCEPTANCE_PLATFORMS[*]} " =~ [[:space:]]macos-latest[[:space:]] ]]; then
            ACCEPTANCE_TEST_MATRIX_MACOS=$(
              ./scripts/get-job-matrix.py \
              -vvv \
              generate-matrix \
              --kind acceptance-test \
              "$CODEGEN_TESTS_FLAG" \
              --platform macos-latest \
              --version-set current \
              --partition-module pkg 1 \
              --partition-module sdk 1 \
              --partition-module tests 4 \
              --partition-package github.com/pulumi/pulumi/tests/smoke tests/smoke 4 \
              --partition-package github.com/pulumi/pulumi/tests/integration tests/integration 8
            )
          fi
          echo "::endgroup::"

          echo "::group::Version set variable"
          VERSION_SET=$(./scripts/get-job-matrix.py \
            generate-version-set \
            --version-set current
          )
          echo "::endgroup::"

          echo "::group::Unit test matrix"
          echo "$UNIT_TEST_MATRIX" | yq -P '.'
          echo "::endgroup::"
          echo "::group::Integration test matrix"
          echo "$INTEGRATION_TEST_MATRIX" | yq -P '.'
          echo "::endgroup::"
          echo "::group::acceptance test matrix windows"
          echo "$ACCEPTANCE_TEST_MATRIX_WIN" | yq -P '.'
          echo "::endgroup::"
          echo "::group::acceptance test matrix macos"
          echo "$ACCEPTANCE_TEST_MATRIX_MACOS" | yq -P '.'
          echo "::endgroup::"
          echo "::group::Version set"
          echo "$VERSION_SET" | yq -P '.'
          echo "::endgroup::"

          echo "::group::Set outputs"
          ./.github/scripts/set-output unit-test-matrix "${UNIT_TEST_MATRIX}"
          ./.github/scripts/set-output integration-test-matrix "${INTEGRATION_TEST_MATRIX}"
          ./.github/scripts/set-output acceptance-test-matrix-win "${ACCEPTANCE_TEST_MATRIX_WIN}"
          ./.github/scripts/set-output acceptance-test-matrix-macos "${ACCEPTANCE_TEST_MATRIX_MACOS}"
          ./.github/scripts/set-output version-set "${VERSION_SET}"
          ./.github/scripts/set-output build-targets "${BUILD_TARGETS}"
          echo "::endgroup::"
    outputs:
      unit-test-matrix: "${{ fromJson(steps.matrix.outputs.unit-test-matrix) }}"
      integration-test-matrix: "${{ fromJson(steps.matrix.outputs.integration-test-matrix) }}"
      acceptance-test-matrix-win: "${{ fromJson(steps.matrix.outputs.acceptance-test-matrix-win) }}"
      acceptance-test-matrix-macos: "${{ fromJson(steps.matrix.outputs.acceptance-test-matrix-macos) }}"
      version-set: "${{ fromJson(steps.matrix.outputs.version-set) }}"
      build-targets: "${{ fromJson(steps.matrix.outputs.build-targets) }}"

  lint:
    name: Lint
    needs: [matrix]
    if: ${{ inputs.lint }}
    uses: ./.github/workflows/ci-lint.yml
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
    with:
      ref: ${{ inputs.ref }}
      version-set: ${{ needs.matrix.outputs.version-set }}

  build-binaries:
    name: build binaries
    needs: [matrix]
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix:
        target: ${{ fromJson(needs.matrix.outputs.build-targets) }}
    uses: ./.github/workflows/ci-build-binaries.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      os: ${{ matrix.target.os }}
      arch: ${{ matrix.target.arch }}
      build-platform: ${{ matrix.target.build-platform }}
      version-set: ${{ needs.matrix.outputs.version-set }}
      enable-coverage: ${{ inputs.enable-coverage }}
      # Windows and Linux need CGO and cross compile support to support -race. So for now only enable it for darwin and amd64 linux.
      enable-race-detection: ${{ matrix.target.os == 'darwin' || (matrix.target.os == 'linux' && matrix.target.arch == 'amd64') }}
      artifact-suffix: '-integration'
    secrets: inherit

  build-display-wasm-module:
    name: build display WASM module
    needs: [matrix]
    uses: ./.github/workflows/ci-build-binaries.yml
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      os: js
      arch: wasm
      build-platform: "ubuntu-latest"
      version-set: ${{ needs.matrix.outputs.version-set }}
    secrets: inherit

  build-sdks:
    name: Build SDKs
    needs: [matrix]
    uses: ./.github/workflows/ci-build-sdks.yml
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      version-set: ${{ needs.matrix.outputs.version-set }}
    secrets: inherit

  # Tests that can run concurrently with builds.
  unit-test:
    # By putting a variable in the name, we remove GitHub's auto-generated matrix parameters from
    # appearing in the rendered title of the job name: It changes this:
    #   CI / Unit Test (cd sdk/dotnet && make dotnet_test, cd sdk/dotnet && make dotnet_test, macos-11, mi... / sdk/dotnet dotnet_test on macos-11/current
    #   (See: https://github.com/pulumi/pulumi/runs/8241055084?check_suite_focus=true#logs)
    # To this:
    #   CI / Unit Test / sdk/dotnet dotnet_test on macos-11/current
    name: Unit Test${{ matrix.platform && '' }}
    needs: [matrix]
    if: ${{ needs.matrix.outputs.unit-test-matrix != '{}' }}
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix: ${{ fromJson(needs.matrix.outputs.unit-test-matrix) }}
    uses: ./.github/workflows/ci-run-test.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      platform: ${{ matrix.platform }}

      test-name: ${{ matrix.test-suite.name || matrix.test-suite.command }} on ${{ matrix.platform }}/${{ matrix.version-set.name }}
      test-command: ${{ matrix.test-suite.command }}
      is-integration-test: false
      enable-coverage: ${{ inputs.enable-coverage }}
      test-retries: ${{ inputs.test-retries }}
      # require-build: false # TODO, remove ${{ matrix.require-build || false }}

      version-set: ${{ toJson(matrix.version-set) }}
    secrets: inherit

  # Tests that depend on builds
  integration-test:
    # By putting a variable in the name, we remove GitHub's auto-generated matrix parameters from
    # appearing in the rendered title of the job name. See: unit test.
    name: Integration Test${{ matrix.platform && '' }}
    needs: [matrix, build-binaries, build-sdks]
    if: ${{ needs.matrix.outputs.integration-test-matrix != '{}' }}
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix: ${{ fromJson(needs.matrix.outputs.integration-test-matrix) }}
    uses: ./.github/workflows/ci-run-test.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      platform: ${{ matrix.platform }}

      test-name: ${{ matrix.test-suite.name || matrix.test-suite.command }} on ${{ matrix.platform }}/${{ matrix.version-set.name }}
      test-command: ${{ matrix.test-suite.command }}
      is-integration-test: true
      enable-coverage: ${{ inputs.enable-coverage }}
      test-retries: ${{ inputs.test-retries }}
      # require-build: false # TODO, remove ${{ matrix.require-build || false }}

      version-set: ${{ toJson(matrix.version-set) }}
    secrets: inherit

  # Tests that depend on builds, but a smaller subset against Windows platform.
  acceptance-test-win:
    # By putting a variable in the name, we remove GitHub's auto-generated matrix parameters from
    # appearing in the rendered title of the job name. See: unit test.
    name: Acceptance Test${{ matrix.platform && '' }}
    needs: [matrix, build-binaries, build-sdks]
    if: ${{ needs.matrix.outputs.acceptance-test-matrix-win != '{}' }}
    # allow jobs to fail if the platform contains windows
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix: ${{ fromJson(needs.matrix.outputs.acceptance-test-matrix-win) }}
    uses: ./.github/workflows/ci-run-test.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      platform: ${{ matrix.platform }}

      test-name: ${{ matrix.test-suite.name || matrix.test-suite.command }} on ${{ matrix.platform }}/${{ matrix.version-set.name }}
      test-command: ${{ matrix.test-suite.command }}
      is-integration-test: true
      enable-coverage: false
      test-retries: ${{ inputs.test-retries }}
      # require-build: false # TODO, remove ${{ matrix.require-build || false }}

      version-set: ${{ toJson(matrix.version-set) }}
    secrets: inherit

  # Tests that depend on builds, but a smaller subset against MacOS platform.
  acceptance-test-macos:
    # By putting a variable in the name, we remove GitHub's auto-generated matrix parameters from
    # appearing in the rendered title of the job name. See: unit test.
    name: Acceptance Test${{ matrix.platform && '' }}
    needs: [matrix, build-binaries, build-sdks]
    if: ${{ needs.matrix.outputs.acceptance-test-matrix-macos != '{}' }}
    # allow jobs to fail if the platform contains windows
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix: ${{ fromJson(needs.matrix.outputs.acceptance-test-matrix-macos) }}
    uses: ./.github/workflows/ci-run-test.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      platform: ${{ matrix.platform }}

      test-name: ${{ matrix.test-suite.name || matrix.test-suite.command }} on ${{ matrix.platform }}/${{ matrix.version-set.name }}
      test-command: ${{ matrix.test-suite.command }}
      is-integration-test: true
      enable-coverage: false
      test-retries: ${{ inputs.test-retries }}
      # require-build: false # TODO, remove ${{ matrix.require-build || false }}

      version-set: ${{ toJson(matrix.version-set) }}
    secrets: inherit

  fuzz-test:
    name: Fuzz Test
    uses: ./.github/workflows/ci-run-test.yml
    needs: [matrix]
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      platform: ubuntu-latest
      test-name: Fuzz test
      test-command: make test_lifecycle_fuzz
      is-integration-test: false
      enable-coverage: false
      test-retries: ${{ inputs.test-retries }}
      version-set: ${{ needs.matrix.outputs.version-set }}
      continue-on-error: ${{ inputs.fuzz-test-optional }}
    secrets: inherit

  test-collect-reports:
    needs: [unit-test, integration-test, acceptance-test-macos]
    if: ${{ always() }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
        with:
          path: test-results
          key: gotestsum-timing-${{ github.run_number }}
          restore-keys: gotestsum-timing-
      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        continue-on-error: true
        with:
          pattern: gotestsum-test-results-*
          merge-multiple: true
          path: test-results
      - name: List and clean up test results
        continue-on-error: true
        run: |
          ls -lhR test-results
          find test-results -mindepth 1 -name '*.json' -mtime +7 -delete
  test-collect-coverage:
    needs: [unit-test, integration-test]
    if: ${{ inputs.enable-coverage }}
    runs-on: ubuntu-latest
    steps:
      # Check that there are no failed tests.
      - name: Check tests completed successfully.
        run: |
          JSON='${{ toJson(needs) }}'
          if test -z "$(echo $JSON | jq -r '.[] | .result' | grep -v 'success')"; then
              echo "Tests OK!"
          else
              echo "Test Failure.. skipping CodeCov upload."
              exit 1
          fi
      # Checkout repository to upload coverage results.
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Retrieve code coverage reports
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          pattern: coverage-*
          merge-multiple: true
          path: coverage
      # For PRs we need to set the merge base manually, otherwise it is sometimes incorrect.  See https://github.com/pulumi/pulumi/pull/17204#issuecomment-2405599310
      - name: Set codecov PR base
        if: github.event_name == 'pull_request'
        run: |
          curl -Os https://cli.codecov.io/latest/linux/codecov
          sudo chmod +x codecov
          ./codecov pr-base-picking --base-sha "$(git merge-base origin/master HEAD)" --pr ${{ github.event.number }} --slug pulumi/pulumi --token ${{ secrets.CODECOV_TOKEN }} --service github
      - name: Upload code coverage
        uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
        with:
          directory: coverage/
          files: "*,!.gitkeep"
          fail_ci_if_error: false
          verbose: true
          # TODO: stop pinning to v10.0.1 when https://github.com/codecov/codecov-cli/issues/651 is fixed.
          # At that point, we should consider switching to codecov/codecov-action@v5
          version: v10.0.1
          token: ${{ secrets.CODECOV_TOKEN }}
  build-release-binaries:
    # This overwrites the previously built testing binaries with versions without coverage.
    name: Rebuild binaries
    needs: [matrix]
    if: ${{ inputs.enable-coverage }}
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix:
        target: ${{ fromJson(needs.matrix.outputs.build-targets) }}
    uses: ./.github/workflows/ci-build-binaries.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      os: ${{ matrix.target.os }}
      arch: ${{ matrix.target.arch }}
      build-platform: ${{ matrix.target.build-platform }}
      version-set: ${{ needs.matrix.outputs.version-set }}
      enable-coverage: false
    secrets: inherit
ci-build-binaries perms .github/workflows/ci-build-binaries.yml
Triggers
workflow_call
Runs on
${{ inputs.build-platform }}
Jobs
build
Actions
goreleaser/goreleaser-action
Commands
  • set -x mkdir -p "${TOOL_BIN}" cp "C:/Program Files/Git/usr/bin/tar.exe" "${TOOL_BIN}" PATH="${TOOL_BIN}:${PATH}" echo "$TOOL_BIN" | tee -a "$GITHUB_PATH" command -v tar tar --version
  • echo "$CACHE_KEY" > .gocache.tmp
  • ./scripts/versions.sh | tee -a "${GITHUB_ENV}"
  • ./scripts/prep-for-goreleaser.sh local
  • find bin -type f -printf "%M %p/"\\n
  • brew install findutils gfind bin -type f -printf "%M %p/"\\n
  • set -euxo pipefail # Spurious, this command requires piping via stdin # shellcheck disable=SC2002 cat .goreleaser.yml \ | go run github.com/t0yv0/goreleaser-filter@v0.3.0 -goos ${{ inputs.os }} -goarch ${{ inputs.arch }} \ | goreleaser release -f - -p 5 --skip=validate --clean --snapshot
View raw YAML
name: Build Binaries

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      os:
        required: true
        description: "Target OS (i.e.: GOOS)"
        type: string
      arch:
        required: true
        description: "Target Architecture (i.e.: GOARCH)"
        type: string
      build-platform:
        required: false
        default: ubuntu-latest
        description: 'Build platform (i.e.: runs-on) for job'
        type: string
      artifact-suffix:
        required: false
        description: "Suffix to append to the artifact names"
        type: string
      dev-version:
        required: false
        description: "Dev version to bake into the binary"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      version-set:
        required: true
        description: "Set of language versions to use for builds, lints, releases, etc."
        type: string
      enable-coverage:
        description: "Build coverage instrumented binaries"
        default: false
        required: false
        type: boolean
      enable-race-detection:
        description: "Build binaries with race detection"
        default: false
        required: false
        type: boolean

defaults:
  run:
    shell: bash

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
  build:
    name: ${{ inputs.os }}-${{ inputs.arch }}
    runs-on: ${{ inputs.build-platform }}

    steps:
      - name: "Windows cache workaround"
        # https://github.com/actions/cache/issues/752#issuecomment-1222415717
        # but only modify the path by adding tar.exe
        if: ${{ runner.os == 'Windows' }}
        env:
          TOOL_BIN: ${{ runner.temp }}/tar-bin
        run: |
          set -x
          mkdir -p "${TOOL_BIN}"
          cp "C:/Program Files/Git/usr/bin/tar.exe" "${TOOL_BIN}"
          PATH="${TOOL_BIN}:${PATH}"
          echo "$TOOL_BIN" | tee -a "$GITHUB_PATH"
          command -v tar
          tar --version
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Configure Go Cache Key
        env:
          CACHE_KEY: "${{ fromJson(inputs.version-set).go }}-${{ runner.os }}-${{ runner.arch }}"
        run: echo "$CACHE_KEY" > .gocache.tmp
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
          cache: true
          cache-dependency-path: |
            pkg/go.sum
            .gocache.tmp
      - name: Setup versioning env vars
        run: |
          ./scripts/versions.sh | tee -a "${GITHUB_ENV}"
      - name: Install GoReleaser
        uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6
        with:
          install-only: true
          distribution: goreleaser-pro
      - name: Prepare bin dir for goreleaser
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GOOS: ${{ inputs.os }}
          GOARCH: ${{ inputs.arch }}
        run: ./scripts/prep-for-goreleaser.sh local
      - name: Show files and permissions
        if: ${{ runner.os != 'macOS'}}
        run: find bin -type f -printf "%M    %p/"\\n
      - name: Show files and permissions
        if: ${{ runner.os == 'macOS'}}
        run: |
          brew install findutils
          gfind bin -type f -printf "%M    %p/"\\n
      - name: Package
        shell: bash
        env:
          GORELEASER_CURRENT_TAG: v${{ inputs.version }}
          PULUMI_VERSION: ${{ inputs.dev-version || inputs.version }}
          PULUMI_BUILD_MODE: ${{ inputs.enable-coverage && inputs.os == 'linux' && 'coverage' || 'normal' }}
          PULUMI_ENABLE_RACE_DETECTION: ${{ inputs.enable-race-detection && 'true' || 'false' }}
        run: |
          set -euxo pipefail
          # Spurious, this command requires piping via stdin
          # shellcheck disable=SC2002
          cat .goreleaser.yml \
            | go run github.com/t0yv0/goreleaser-filter@v0.3.0 -goos ${{ inputs.os }} -goarch ${{ inputs.arch }} \
            | goreleaser release -f - -p 5 --skip=validate --clean --snapshot
      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
        if: ${{ inputs.os != 'js' }}
        with:
          name: artifacts-cli-${{ inputs.os }}-${{ inputs.arch }}${{ inputs.artifact-suffix || ''}}
          overwrite: true
          retention-days: 7
          path: |
            goreleaser/*.tar.gz
            goreleaser/*.zip
ci-build-sdks perms .github/workflows/ci-build-sdks.yml
Triggers
workflow_call
Runs on
ubuntu-latest, ubuntu-latest
Jobs
build_python_sdk, build_node_sdk
Actions
astral-sh/setup-uv
Commands
  • ./scripts/versions.sh | tee -a "${GITHUB_ENV}"
  • cd sdk/python sed -i.bak "s/^version = .*/version = \"${PYPI_VERSION}\"/g" pyproject.toml && rm pyproject.toml.bak make build_package
  • ./scripts/versions.sh | tee -a "${GITHUB_ENV}"
  • npm install -g yarn
  • cd sdk/nodejs mkdir -p bin # shellcheck disable=SC2230 # need to locate echo binary ln -s "$(which echo)" bin/go
  • cd sdk/nodejs PATH=./bin:$PATH make ensure
  • cd sdk/nodejs PATH=./bin:$PATH make build_package
  • cd sdk/nodejs/bin npm pack
View raw YAML
name: Build SDKs

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string

      version-set:
        required: false
        description: "Set of language versions to use for builds, lints, releases, etc."
        type: string
        # Example provided for illustration, this value is derived by scripts/get-job-matrix.py build
        default: |
          {
            "dotnet": "8.0.x",
            "go": "1.18.x",
            "nodejs": "20.x",
            "python": "3.9.x"
          }

defaults:
  run:
    shell: bash

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  PULUMI_VERSION: ${{ inputs.version }}

jobs:
  build_python_sdk:
    name: python
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Setup versioning env vars
        env:
          version: ${{ inputs.version }}
        run: |
          ./scripts/versions.sh | tee -a "${GITHUB_ENV}"
      - name: Set up uv
        uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
        with:
          enable-cache: true
          cache-dependency-glob: sdk/python/uv.lock
      - name: Set up Python ${{ fromJson(inputs.version-set).python }}
        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
        with:
          python-version: ${{ fromJson(inputs.version-set).python }}
      - name: Build Pulumi Python SDK wheel
        run: |
          cd sdk/python
          sed -i.bak "s/^version = .*/version = \"${PYPI_VERSION}\"/g" pyproject.toml && rm pyproject.toml.bak
          make build_package
      - name: Upload pulumi.whl
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
        with:
          name: artifacts-python-sdk
          path: sdk/python/build/*.whl
          retention-days: 1
          if-no-files-found: error

  build_node_sdk:
    name: nodejs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Setup versioning env vars
        env:
          version: ${{ inputs.version }}
        run: |
          ./scripts/versions.sh | tee -a "${GITHUB_ENV}"
      - name: Set up Node ${{ fromJson(inputs.version-set).nodejs }}
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: ${{ fromJson(inputs.version-set).nodejs }}
          cache: yarn
          cache-dependency-path: sdk/nodejs/yarn.lock
      - name: Install yarn
        run: |
          npm install -g yarn
      # TODO something in `cd sdk/nodejs && make ensure` executes Go
      # downloads, which is unfortunate and wasteful in this context.
      # When this is fixed the no-op Go command can be removed.
      - name: Make no-op Go command to avoid Go builds
        run: |
           cd sdk/nodejs
           mkdir -p bin
           # shellcheck disable=SC2230 # need to locate echo binary
           ln -s "$(which echo)" bin/go
      - name: Ensure installed dependencies
        run: |
          cd sdk/nodejs
          PATH=./bin:$PATH make ensure
      - name: Build the Node SDK package
        run: |
          cd sdk/nodejs
          PATH=./bin:$PATH make build_package
      - name: Pack the Node SDK
        run: |
          cd sdk/nodejs/bin
          npm pack
      - name: Upload pulumi-node-sdk.tgz
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
        with:
          name: artifacts-nodejs-sdk
          path: sdk/nodejs/bin/*.tgz
          retention-days: 1
          if-no-files-found: error
ci-dev-release matrix perms .github/workflows/ci-dev-release.yml
Triggers
workflow_call
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
gather-info, matrix, build-release, build-sdks, sign, sdk-check-release, nodejs-dev-sdk-release, python-dev-sdk-release, s3-blobs
Matrix
arch, build-platform, os→ amd64, arm64, darwin, linux, ubuntu-latest, windows
Actions
proudust/gh-describe, jdx/mise-action, astral-sh/setup-uv, aws-actions/configure-aws-credentials
Commands
  • short_sha="x${{ steps.ghd.outputs.short-sha }}" version="${{ inputs.version }}" version="${version#v}-alpha.${short_sha}" echo dev-version="$version" >>"${GITHUB_OUTPUT}"
  • SDKS='' make install
  • echo "::group::Version set variable" VERSION_SET=$(./scripts/get-job-matrix.py \ generate-version-set \ --version-set current ) echo "::endgroup::" echo "::group::Version set" echo "$VERSION_SET" | yq -P '.' echo "::endgroup::" echo "::group::Set outputs" ./.github/scripts/set-output version-set "${VERSION_SET}" echo "::endgroup::"
  • # We need to fetch one more commit to compare to git fetch --deepen 1 if ! git diff --exit-code HEAD~...HEAD sdk/nodejs; then echo "nodejs-release=true" >>"${GITHUB_OUTPUT}" else echo "nodejs-release=false" >>"${GITHUB_OUTPUT}" fi if ! git diff --exit-code HEAD~...HEAD sdk/python; then echo "python-release=true" >>"${GITHUB_OUTPUT}" else echo "python-release=false" >>"${GITHUB_OUTPUT}" fi
  • mkdir -p artifacts.tmp
  • mkdir -p artifacts ( cd artifacts.tmp/artifacts-nodejs-sdk version="${{ inputs.version }}" for file in *"${version}"-alpha*.tgz ; do mv -vT "$file" "../../artifacts/sdk-nodejs-${file}" done )
  • find artifacts make -C sdk/nodejs publish
  • mkdir -p artifacts.tmp
View raw YAML
name: Create dev release

permissions:
  contents: read

  # To sign artifacts.
  id-token: write

on:
  workflow_call:
    inputs:
      version:
        required: true
        description: "Version to use for the release"
        type: string
      ref:
        required: true
        description: "GitHub ref to use"
        type: string

jobs:
  gather-info:
    name: gather-info
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}

      - name: Git describe
        id: ghd
        uses: proudust/gh-describe@v1
      - name: strip prefix
        id: strip-prefix
        # Always prefix the short_sha with a letter to ensure it's a valid semver prerelease,
        # see https://github.com/pulumi/pulumi/issues/15471 for context.
        run: |
          short_sha="x${{ steps.ghd.outputs.short-sha }}"
          version="${{ inputs.version }}"
          version="${version#v}-alpha.${short_sha}"
          echo dev-version="$version" >>"${GITHUB_OUTPUT}"
    outputs:
      dev-version: ${{ steps.strip-prefix.outputs.dev-version }}
      version: ${{ inputs.version }}

  matrix:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          cache: true
          cache-dependency-path: pkg/go.sum
          go-version-file: pkg/go.mod
      - uses: jdx/mise-action@v2
        with:
          experimental: true
      - name: Install CLI
        run: SDKS='' make install
      - name: build matrix
        id: matrix
        run: |
          echo "::group::Version set variable"
          VERSION_SET=$(./scripts/get-job-matrix.py \
            generate-version-set \
            --version-set current
          )
          echo "::endgroup::"

          echo "::group::Version set"
          echo "$VERSION_SET" | yq -P '.'
          echo "::endgroup::"

          echo "::group::Set outputs"
          ./.github/scripts/set-output version-set "${VERSION_SET}"
          echo "::endgroup::"
    outputs:
      version-set: "${{ fromJson(steps.matrix.outputs.version-set) }}"

  build-release:
    name: build-release
    needs: [gather-info, matrix]
    strategy:
      fail-fast: true
      matrix:
        os: ["linux", "darwin", "windows"]
        arch: ["amd64", "arm64"]
        build-platform: ["ubuntu-latest"]
    uses: ./.github/workflows/ci-build-binaries.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      dev-version: ${{ needs.gather-info.outputs.dev-version }}
      os: ${{ matrix.os }}
      arch: ${{ matrix.arch }}
      build-platform: ${{ matrix.build-platform }}
      version-set: ${{ needs.matrix.outputs.version-set }}
      enable-coverage: false
    secrets: inherit

  build-sdks:
    name: Build SDKs
    needs: [matrix, gather-info]
    uses: ./.github/workflows/ci-build-sdks.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ needs.gather-info.outputs.dev-version }}
      version-set: ${{ needs.matrix.outputs.version-set }}
    secrets: inherit

  sign:
    name: sign
    needs: [build-release, build-sdks]
    uses: ./.github/workflows/sign.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}

  # Check if we need to create a new SDK dev release
  sdk-check-release:
    name: sdk-check-release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

      - name: Check for changes
        id: check-changes
        run: |
          # We need to fetch one more commit to compare to
          git fetch --deepen 1
          if ! git diff --exit-code HEAD~...HEAD sdk/nodejs; then
            echo "nodejs-release=true" >>"${GITHUB_OUTPUT}"
          else
            echo "nodejs-release=false" >>"${GITHUB_OUTPUT}"
          fi

          if ! git diff --exit-code HEAD~...HEAD sdk/python; then
            echo "python-release=true" >>"${GITHUB_OUTPUT}"
          else
            echo "python-release=false" >>"${GITHUB_OUTPUT}"
          fi
    outputs:
      nodejs-release: ${{ steps.check-changes.outputs.nodejs-release }}
      python-release: ${{ steps.check-changes.outputs.python-release }}

  nodejs-dev-sdk-release:
    needs: [gather-info, build-sdks, sdk-check-release, matrix]
    runs-on: ubuntu-latest
    if: ${{ needs.sdk-check-release.outputs.nodejs-release == 'true' }}
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - name: Make artifacts directory
        run: |
          mkdir -p artifacts.tmp
      - name: Download artifacts from previous step
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          path: artifacts.tmp
      - name: Move artifacts to the right place
        run: |
          mkdir -p artifacts
          (
            cd artifacts.tmp/artifacts-nodejs-sdk
            version="${{ inputs.version }}"
            for file in *"${version}"-alpha*.tgz ; do
              mv -vT "$file" "../../artifacts/sdk-nodejs-${file}"
            done
          )
      - name: Set up Node ${{ fromJson(needs.matrix.outputs.version-set).nodejs }}
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: ${{ fromJson(needs.matrix.outputs.version-set).nodejs }}
          registry-url: https://registry.npmjs.org
          always-auth: true
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      - name: Publish nodejs release
        run: |
          find artifacts
          make -C sdk/nodejs publish
        env:
          PULUMI_VERSION: ${{ needs.gather-info.outputs.dev-version }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          GIT_REF: ${{ inputs.ref }}


  python-dev-sdk-release:
    needs: [gather-info, build-sdks, sdk-check-release, matrix]
    runs-on: ubuntu-latest
    if: ${{ needs.sdk-check-release.outputs.python-release == 'true' }}
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - name: Set up Python ${{ fromJson(needs.matrix.outputs.version-set).python }}
        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
        with:
          python-version: ${{ fromJson(needs.matrix.outputs.version-set).python }}
      - name: Set up uv
        uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
        with:
          enable-cache: true
          cache-dependency-glob: sdk/python/uv.lock
      - name: Make artifacts directory
        run: |
          mkdir -p artifacts.tmp
      - name: Download artifacts from previous step
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          path: artifacts.tmp
      - name: Move artifacts to the right place
        run: |
          mkdir -p artifacts
          version="${{ inputs.version }}"
          mkdir -p artifacts
          (
            cd artifacts.tmp/artifacts-python-sdk
            for file in *"${version}a"*.whl ; do
              mv -vT "$file" "../../artifacts/sdk-python-${file}"
            done
          )
      - name: Publish python release
        run: |
          find artifacts
          make -C sdk/python publish
        env:
          PYPI_USERNAME: __token__
          PYPI_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}

  s3-blobs:
    name: s3 blobs
    runs-on: ubuntu-latest
    needs: [sign, gather-info]
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-region: us-east-2
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          role-duration-seconds: 3600
          role-external-id: upload-pulumi-release
          role-session-name: pulumi@githubActions
          role-to-assume: ${{ secrets.AWS_UPLOAD_ROLE_ARN }}
      - name: Make artifacts directory
        run: |
          mkdir -p artifacts.tmp
      - name: Download artifacts from previous step
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          path: artifacts.tmp
      - name: Remove performance test artifacts
        run: rm -rf artifacts.tmp/*-perf
      - name: Remove integration test artifacts
        run: rm -rf artifacts.tmp/*-integration
      - name: Flatten artifact directories
        run: |
          find artifacts.tmp
          mkdir -p ./artifacts
          mv ./artifacts.tmp/artifacts-signatures/pulumi-*.tar.gz.sig ./artifacts
          mv ./artifacts.tmp/artifacts-signatures/pulumi-*.zip.sig ./artifacts
          mv ./artifacts.tmp/artifacts-signatures/pulumi-*.txt.sig ./artifacts
          mv ./artifacts.tmp/artifacts-signatures/pulumi-*.txt ./artifacts
          mv ./artifacts.tmp/artifacts-cli-*/pulumi-*.tar.gz ./artifacts
          mv ./artifacts.tmp/artifacts-cli-*/pulumi-*.zip ./artifacts

      - name: Find artifacts
        run: |
          find artifacts
      - name: Rename artifacts
        shell: bash
        run: |
          (
            cd artifacts
            version="${{ inputs.version }}"
            dev_version="${{ needs.gather-info.outputs.dev-version }}"
            for file in *; do
              mv "$file" "${file//$version/$dev_version}"
            done
          )
      - name: Find artifacts
        run: |
          find artifacts | sort

      - name: Publish Blobs
        run: |
          aws s3 sync artifacts s3://get.pulumi.com/releases/sdk --acl public-read
ci-info perms .github/workflows/ci-info.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
info
Commands
  • gh api -i repos/${{ github.repository }}/releases/latest
  • PLAIN_VERSION="$(./.github/scripts/get-version)" PULUMI_VERSION="${PLAIN_VERSION}" if [ "$IS_SNAPSHOT" = "true" ]; then TIMESTAMP=$(date +%s) PULUMI_VERSION="${PULUMI_VERSION%-*}-alpha.$TIMESTAMP" fi ./.github/scripts/set-output version "${PULUMI_VERSION}"
  • PREVIOUS_VERSION="$(./.github/scripts/get-previous-version)" CHANGELOG="$(./.github/scripts/get-changelog "${PREVIOUS_VERSION}" --version "${{ fromJSON(steps.version.outputs.version) }}")" ./.github/scripts/set-output release-notes "${CHANGELOG}"
  • PULUMI_VERSION="${{ fromJSON(steps.version.outputs.version) }}" ./.github/scripts/update-versions "${PULUMI_VERSION}" ERROR=false if [ -n "$(git status --porcelain)" ]; then ERROR=true echo "::error::Versions in files do not match expected version ${PULUMI_VERSION}." echo "::group::git diff" git diff echo "::endgroup::" fi if EXISTING_RELEASE_DRAFT="$(gh release view "v${PULUMI_VERSION}" --json isDraft --jq '.isDraft')"; then if [ "$EXISTING_RELEASE_DRAFT" != "true" ]; then echo "::error::This version has already been released!" echo "::group::Release ${PULUMI_VERSION}" echo "$EXISTING_RELEASE" echo "::endgroup::" else echo "::info Preparing to update draft release ${PULUMI_VERSION}" fi fi if $ERROR; then exit 1; fi
View raw YAML
name: Info

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      is-snapshot:
        required: false
        default: true
        description: "Is this a snapshot release?"
        type: boolean
    outputs:
      version:
        description: "Version to produce"
        value: ${{ jobs.info.outputs.version }}
      release-notes:
        description: "Release notes for CHANGELOG"
        value: ${{ jobs.info.outputs.release-notes }}

permissions:
  contents: read

defaults:
  run:
    shell: bash

jobs:
  info:
    name: gather
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      version: "${{ fromJSON(steps.version.outputs.version) }}"
      release-notes: "${{ fromJSON(steps.notes.outputs.release-notes) }}"
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
          fetch-depth: 0
      - name: Print rate limits
        continue-on-error: true
        run: gh api -i repos/${{ github.repository }}/releases/latest
      - name: Compute version
        id: version
        env:
          IS_SNAPSHOT: ${{ inputs.is-snapshot }}
        run: |
          PLAIN_VERSION="$(./.github/scripts/get-version)"
          PULUMI_VERSION="${PLAIN_VERSION}"

          if [ "$IS_SNAPSHOT" = "true" ]; then
            TIMESTAMP=$(date +%s)
            PULUMI_VERSION="${PULUMI_VERSION%-*}-alpha.$TIMESTAMP"
          fi

          ./.github/scripts/set-output version "${PULUMI_VERSION}"
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: '>=1.19.0' # decoupled from version sets, used by changelog tool
          cache: true
          cache-dependency-path: '.github/scripts/get-changelog'
      - name: Extract release notes
        id: notes
        run: |
          PREVIOUS_VERSION="$(./.github/scripts/get-previous-version)"
          CHANGELOG="$(./.github/scripts/get-changelog "${PREVIOUS_VERSION}" --version "${{ fromJSON(steps.version.outputs.version) }}")"
          ./.github/scripts/set-output release-notes "${CHANGELOG}"
      - name: Check version
        if: ${{ !inputs.is-snapshot }}
        run: |
          PULUMI_VERSION="${{ fromJSON(steps.version.outputs.version) }}"

          ./.github/scripts/update-versions "${PULUMI_VERSION}"

          ERROR=false
          if [ -n "$(git status --porcelain)" ]; then
            ERROR=true
            echo "::error::Versions in files do not match expected version ${PULUMI_VERSION}."
            echo "::group::git diff"
            git diff
            echo "::endgroup::"
          fi

          if EXISTING_RELEASE_DRAFT="$(gh release view "v${PULUMI_VERSION}" --json isDraft --jq '.isDraft')"; then
            if [ "$EXISTING_RELEASE_DRAFT" != "true" ]; then
              echo "::error::This version has already been released!"
              echo "::group::Release ${PULUMI_VERSION}"
              echo "$EXISTING_RELEASE"
              echo "::endgroup::"
            else
              echo "::info Preparing to update draft release ${PULUMI_VERSION}"
            fi
          fi

          if $ERROR; then
            exit 1;
          fi
ci-lint perms .github/workflows/ci-lint.yml
Triggers
workflow_call
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
golangci, tidy, gen, protobuf-lint, sdk-lint, actionlint, pulumi-json
Actions
golangci/golangci-lint-action, jdx/mise-action, astral-sh/setup-uv
Commands
  • go install go.abhg.dev/requiredfield/cmd/requiredfield@${{ env.REQUIREDFIELD_VERSION }}
  • make lint_golang
  • make tidy
  • cd sdk/go && make gen
  • if [ -n "$(git status --porcelain)" ]; then echo "::error Running 'make gen' in sdk/go resulted in changes" echo "::error Please run 'make gen' in sdk/go and commit the changes" exit 1 fi
  • make check_proto
  • python -m pip install --upgrade pip requests wheel urllib3 chardet
  • git config --global user.email "you@example.com" git config --global user.name "Your Name"
View raw YAML
name: Lint

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version-set:
        required: true
        description: "Version matrix to use"
        type: string

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  GOLANGCI_LINT_VERSION: v2.9.0
  REQUIREDFIELD_VERSION: v0.8.0

jobs:
  golangci:
    name: Lint Go
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
          # golangci-lint-action handles all the caching for Go.
          cache: false

      # We leverage the golangci-lint action to install
      # and maintain the cache,
      # but we want to run the command ourselves.
      # The action doesn't have an install-only mode,
      # so we'll ask it to print its help output instead.
      - name: Install golangci-lint
        uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8
        with:
          version: ${{ env.GOLANGCI_LINT_VERSION }}
          args: --help

      - name: Install requiredfield
        run: go install go.abhg.dev/requiredfield/cmd/requiredfield@${{ env.REQUIREDFIELD_VERSION }}

      - name: Run golangci-lint
        run: make lint_golang
  tidy:
    name: go mod tidy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
      - name: Run go mod tidy
        run: make tidy

  gen:
    name: Generate Go SDK
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
      - name: Run make gen
        run: cd sdk/go && make gen
      - name: Fail if there are changes
        run: |
          if [ -n "$(git status --porcelain)" ]; then
            echo "::error Running 'make gen' in sdk/go resulted in changes"
            echo "::error Please run 'make gen' in sdk/go and commit the changes"
            exit 1
          fi

  protobuf-lint:
    name: Lint Protobufs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - uses: jdx/mise-action@v2
        with:
          experimental: true
      - name: Check Protobufs
        run: make check_proto

  sdk-lint:
    name: Lint SDKs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
      - name: Set up uv
        uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
        with:
          enable-cache: true
          cache-dependency-glob: sdk/python/uv.lock
      - name: Set up Python ${{ fromJson(inputs.version-set).python }}
        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
        with:
          python-version: ${{ fromJson(inputs.version-set).python }}
      - name: Set up Node ${{ fromJson(inputs.version-set).nodejs }}
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: ${{ fromJson(inputs.version-set).nodejs }}
          cache: yarn
          cache-dependency-path: sdk/nodejs/yarn.lock
      - name: Install Python deps
        run: |
          python -m pip install --upgrade pip requests wheel urllib3 chardet
      - name: Setup git
        run: |
          git config --global user.email "you@example.com"
          git config --global user.name "Your Name"
      - name: Update path
        run: |
          echo "$RUNNER_TEMP/opt/pulumi/bin" >> "$GITHUB_PATH"
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set Go Dep path
        run: |
          echo "PULUMI_GO_DEP_ROOT=$(dirname "$(pwd)")" >> "$GITHUB_ENV"
      - name: Ensure
        run: |
          make ensure
      - name: Lint Node
        run: |
          cd sdk/nodejs && make lint
      - name: Lint Python
        run: |
          cd sdk/python && make lint

  actionlint:
    name: Lint GHA
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
      - run: |
          make lint_actions

  pulumi-json:
    name: Lint pulumi.json
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
      - name: Set up Node ${{ fromJson(inputs.version-set).nodejs }}
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: ${{ fromJson(inputs.version-set).nodejs }}
          cache: yarn
          cache-dependency-path: sdk/nodejs/yarn.lock
      - name: Ensure Node # We need to install Node.js deps so that biome is available
        run: |
          cd sdk/nodejs && make ensure
      - run: |
          make lint_pulumi_json
ci-performance-gate matrix perms .github/workflows/ci-performance-gate.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
matrix, build-binaries, performance-test
Matrix
target→ ${{ fromJson(needs.matrix.outputs.build-targets) }}
Actions
jdx/mise-action
Commands
  • SDKS='' make install
  • echo "::group::Test matrix variables" readarray -td' ' VERSION_SETS_TO_TEST < <(echo -n "$TEST_VERSION_SETS"); declare -p VERSION_SETS_TO_TEST; readarray -td' ' PERFORMANCE_TEST_PLATFORMS < <(echo -n "$INPUT_PERFORMANCE_TEST_PLATFORMS"); declare -p PERFORMANCE_TEST_PLATFORMS; BUILD_TARGETS='[ { "os": "linux", "arch": "amd64", "build-platform": "ubuntu-latest" }, { "os": "windows", "arch": "amd64", "build-platform": "ubuntu-latest" }, { "os": "darwin", "arch": "arm64", "build-platform": "ubuntu-latest" } ]' PERFORMANCE_TEST_MATRIX=$( ./scripts/get-job-matrix.py \ -vvv \ generate-matrix \ --kind performance-test \ --platform "${PERFORMANCE_TEST_PLATFORMS[@]}" \ --version-set "${VERSION_SETS_TO_TEST[@]}" ) echo "::endgroup::" echo "::group::Version set variable" VERSION_SET=$(./scripts/get-job-matrix.py \ generate-version-set \ --version-set current ) echo "::endgroup::" echo "::group::Performance test matrix" echo "$PERFORMANCE_TEST_MATRIX" | yq -P '.' echo "::endgroup::" echo "::group::Version set" echo "$VERSION_SET" | yq -P '.' echo "::endgroup::" echo "::group::Set outputs" ./.github/scripts/set-output performance-test-matrix "${PERFORMANCE_TEST_MATRIX}" ./.github/scripts/set-output version-set "${VERSION_SET}" ./.github/scripts/set-output build-targets "${BUILD_TARGETS}" echo "::endgroup::"
View raw YAML
# This workflow runs performance tests to ensure we do not introduce performance
# regressions. This runs for every PR, as well as on every merge to the master
# branch.
#
# The Pulumi CLI binaries used in this workflow are built without race detection
# or coverage instrumentation to ensure that the performance tests are not
# affected by these flags.

name: Performance Gate

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      test-version-sets:
        required: false
        default: minimum current
        description: Version sets on which to run integration tests
        type: string
      performance-test-platforms:
        required: false
        default: ubuntu-latest
        description: Platforms on which to run performance tests, as a space delimited list
        type: string
      fail-fast:
        required: false
        default: false
        description: "Fail all workflows whenever one of them fails"
        type: boolean
      test-retries:
        required: false
        default: 0
        description: "Retry tests n times if there are failures"
        type: number
    secrets:
      PULUMI_PROD_ACCESS_TOKEN:
        required: false
        description: "Pulumi access token, required to run tests against the service"
      AZURE_TENANT_ID:
        required: false
        description: "Azure tenant ID, required to run tests against Azure"
      AZURE_CLIENT_ID:
        required: false
        description: "Azure client ID, required to run tests against Azure"
      AZURE_CLIENT_SECRET:
        required: false
        description: "Azure clients secret, needs to be rotated before 2025-12-21 (see the pulumi-test user in Azure portal)"
      AZURE_STORAGE_SAS_TOKEN:
        required: false
        description: "Azure storage SAS token, required to run tests against Azure"
      GCP_SERVICE_ACCOUNT:
        required: false
        description: "GCP service account, required to run tests against GCP"

jobs:
  matrix:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          cache: true
          cache-dependency-path: pkg/go.sum
          go-version-file: pkg/go.mod
      - uses: jdx/mise-action@v2
        with:
          experimental: true
      - name: Install CLI
        run: SDKS='' make install
      - name: build matrix
        id: matrix
        env:
          TEST_VERSION_SETS: ${{ inputs.test-version-sets }}
          INPUT_PERFORMANCE_TEST_PLATFORMS: ${{ inputs.performance-test-platforms }}
        run: |
          echo "::group::Test matrix variables"
          readarray -td' ' VERSION_SETS_TO_TEST < <(echo -n "$TEST_VERSION_SETS"); declare -p VERSION_SETS_TO_TEST;
          readarray -td' ' PERFORMANCE_TEST_PLATFORMS < <(echo -n "$INPUT_PERFORMANCE_TEST_PLATFORMS"); declare -p PERFORMANCE_TEST_PLATFORMS;
          BUILD_TARGETS='[
              { "os": "linux",   "arch": "amd64", "build-platform": "ubuntu-latest" },
              { "os": "windows", "arch": "amd64", "build-platform": "ubuntu-latest" },
              { "os": "darwin",  "arch": "arm64", "build-platform": "ubuntu-latest" }
          ]'

          PERFORMANCE_TEST_MATRIX=$(
            ./scripts/get-job-matrix.py \
            -vvv \
            generate-matrix \
            --kind performance-test \
            --platform "${PERFORMANCE_TEST_PLATFORMS[@]}" \
            --version-set "${VERSION_SETS_TO_TEST[@]}"
          )
          echo "::endgroup::"

          echo "::group::Version set variable"
          VERSION_SET=$(./scripts/get-job-matrix.py \
            generate-version-set \
            --version-set current
          )
          echo "::endgroup::"

          echo "::group::Performance test matrix"
          echo "$PERFORMANCE_TEST_MATRIX" | yq -P '.'
          echo "::endgroup::"
          echo "::group::Version set"
          echo "$VERSION_SET" | yq -P '.'
          echo "::endgroup::"

          echo "::group::Set outputs"
          ./.github/scripts/set-output performance-test-matrix "${PERFORMANCE_TEST_MATRIX}"
          ./.github/scripts/set-output version-set "${VERSION_SET}"
          ./.github/scripts/set-output build-targets "${BUILD_TARGETS}"
          echo "::endgroup::"
    outputs:
      performance-test-matrix: "${{ fromJson(steps.matrix.outputs.performance-test-matrix) }}"
      version-set: "${{ fromJson(steps.matrix.outputs.version-set) }}"
      build-targets: "${{ fromJson(steps.matrix.outputs.build-targets) }}"

  build-binaries:
    name: build binaries
    needs: [matrix]
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix:
        target: ${{ fromJson(needs.matrix.outputs.build-targets) }}
    uses: ./.github/workflows/ci-build-binaries.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      os: ${{ matrix.target.os }}
      arch: ${{ matrix.target.arch }}
      build-platform: ${{ matrix.target.build-platform }}
      version-set: ${{ needs.matrix.outputs.version-set }}
      # For performance tests, we do not want coverage or race detection enabled.
      enable-coverage: false
      enable-race-detection: false
      # Suffix the artifacts so they do not clash with those of the main build.
      artifact-suffix: '-perf'
    secrets: inherit

  performance-test:
    # By putting a variable in the name, we remove GitHub's auto-generated matrix parameters from
    # appearing in the rendered title of the job name.
    name: Performance Test${{ matrix.platform && '' }}
    needs: [matrix, build-binaries]
    strategy:
      fail-fast: ${{ inputs.fail-fast }}
      matrix: ${{ fromJson(needs.matrix.outputs.performance-test-matrix) }}
    uses: ./.github/workflows/ci-run-test.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      platform: ${{ matrix.platform }}
      test-name: ${{ matrix.test-suite.name || matrix.test-suite.command }} on ${{ matrix.platform }}/${{ matrix.version-set.name }}
      test-command: ${{ matrix.test-suite.command }}
      is-performance-test: true
      enable-coverage: false
      test-retries: ${{ inputs.test-retries }}
      version-set: ${{ toJson(matrix.version-set) }}
    secrets: inherit
ci-prepare-release perms .github/workflows/ci-prepare-release.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
sign, publish
Actions
ncipollo/release-action
Commands
  • SHA=$(git rev-parse HEAD) ./.github/scripts/set-output sha "$SHA"
  • rm -rf artifacts.tmp/*-perf
  • rm -rf artifacts.tmp/*-integration
  • ( cd artifacts.tmp/artifacts-python-sdk for file in *.whl ; do mv -vT "$file" "sdk-python-$file" done ) ( cd artifacts.tmp/artifacts-nodejs-sdk for file in *.tgz ; do mv -vT "$file" "sdk-nodejs-$file" done )
  • mkdir -p ./artifacts mv ./artifacts.tmp/artifacts-*/* ./artifacts
View raw YAML
name: Prepare

permissions:
  # To create a draft release
  contents: write
  # To sign artifacts.
  id-token: write

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      project:
        required: true
        description: "Project name, e.g.: the repository name"
        type: string
      release-notes:
        required: true
        description: "Release notes"
        type: string
      prerelease:
        required: false
        default: true
        description: "Whether to create a prerelease"
        type: boolean
      draft:
        required: false
        default: true
        description: "Whether to create a draft release"
        type: boolean

env:
  PULUMI_VERSION: ${{ inputs.version }}

jobs:
  sign:
    name: sign
    uses: ./.github/workflows/sign.yml
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}

  publish:
    name: release
    needs: [sign]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Get commit hash
        id: commit-info
        run: |
          SHA=$(git rev-parse HEAD)
          ./.github/scripts/set-output sha "$SHA"
      - name: Download all artifacts
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          path: artifacts.tmp
      - name: Remove performance test artifacts
        run: rm -rf artifacts.tmp/*-perf
      - name: Remove integration test artifacts
        run: rm -rf artifacts.tmp/*-integration
      - name: Rename SDKs
        # This step must match the rename SDKs step in the "sign" job above.
        run: |
          (
            cd artifacts.tmp/artifacts-python-sdk
            for file in *.whl ; do
              mv -vT "$file" "sdk-python-$file"
            done
          )
          (
            cd artifacts.tmp/artifacts-nodejs-sdk
            for file in *.tgz ; do
              mv -vT "$file" "sdk-nodejs-$file"
            done
          )
      - name: Flatten artifact directories
        run: |
          mkdir -p ./artifacts
          mv ./artifacts.tmp/artifacts-*/* ./artifacts
      - uses: ncipollo/release-action@3d2de22e3d0beab188d8129c27f103d8e91bf13a
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          name: v${{ inputs.version }}
          tag: v${{ inputs.version }}
          commit: "${{ fromJSON(steps.commit-info.outputs.sha) }}"
          draft: ${{ inputs.draft }}
          prerelease: ${{ inputs.prerelease }}
          allowUpdates: true

          body: |
            ${{ inputs.release-notes }}

          removeArtifacts: true
          replacesArtifacts: true
          artifactErrorsFailBuild: true
          artifacts: |
            artifacts/*
ci-run-test perms .github/workflows/ci-run-test.yml
Triggers
workflow_call
Runs on
${{ inputs.platform }}
Jobs
test
Actions
jlumbroso/free-disk-space, astral-sh/setup-uv, gradle/actions/setup-gradle, oven-sh/setup-bun, jaxxstorm/action-install-gh-release, jaxxstorm/action-install-gh-release, codecov/test-results-action
Commands
  • HASH=$(echo '${{ inputs.test-name }}-${{ inputs.is-integration-test && 'integration' || 'unit' }}' | git hash-object --literally --stdin | awk '{ print $1 }') echo "TEST_HASH_ID=${HASH}" >> "$GITHUB_ENV"
  • set -x mkdir -p "${TOOL_BIN}" cp "C:/Program Files/Git/usr/bin/tar.exe" "${TOOL_BIN}" PATH="${TOOL_BIN}:${PATH}" echo "$TOOL_BIN" | tee -a "$GITHUB_PATH" command -v tar tar --version
  • { echo "GO_TEST_PARALLELISM=4" echo "GO_TEST_PKG_PARALLELISM=1" echo "GO_TEST_RACE=false" } >> "$GITHUB_ENV" # For debugging: ps aux
  • npm install typescript -g
  • set -x brew install coreutils echo "/usr/local/opt/coreutils/libexec/gnubin" | tee -a "$GITHUB_PATH" command -v bash bash --version
  • ./scripts/versions.sh | tee -a "$GITHUB_ENV"
  • echo "PULUMI_TEST_COVERAGE_PATH=$(pwd)/coverage" >> "$GITHUB_ENV" # Post integration test coverage to a temporary directory. # This will be merged at a later step. Note that we can't # use $GOCOVERDIR here, because Go overwrites that env # variable when the '-cover' flag is used. Use # $PULUMI_GOCOVERDIR instead, which the integration tests # then turn into $GOCOVERDIR. See also https://github.com/golang/go/issues/66225. # # Also set `GOCOVERDIR` for tests that don't use `go test` (e.g. # automation API tests) coverdir="$(mktemp -d)" echo "PULUMI_GOCOVERDIR=$coverdir" >> "$GITHUB_ENV" echo "GOCOVERDIR=$coverdir" >> "$GITHUB_ENV"
  • echo "$CACHE_KEY" > .gocache.tmp
View raw YAML
name: Test

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      platform:
        description: "OS to run tests on, e.g.: ubuntu-latest"
        required: true
        type: string

      test-name:
        description: "Name of the test to run"
        required: true
        type: string
      test-command:
        description: Test command to run
        required: true
        type: string
      is-integration-test:
        description: Whether to download and install build artifacts
        required: false
        default: false
        type: boolean
      is-performance-test:
        description: Whether to download and install build artifacts for performance tests
        required: false
        default: false
        type: boolean
      enable-coverage:
        description: "Collects coverage stats; requires cov-enabled builds"
        default: false
        required: false
        type: boolean
      test-retries:
        description: "How often tests are retried"
        default: 0
        required: false
        type: number

      version-set:
        required: false
        description: "Set of language versions to use for builds, lints, releases, etc."
        type: string
        # Example provided for illustration, this value is derived by scripts/get-job-matrix.py build
        default: |
          {
            "dotnet": "8.0.x",
            "go": "1.18.x",
            "nodejs": "20.x",
            "python": "3.9.x"
          }
      continue-on-error:
        description: "Whether to continue running the job if the step fails"
        required: false
        default: false
        type: boolean

defaults:
  run:
    shell: bash

env:
  PULUMI_VERSION: ${{ inputs.version }}
  PULUMI_TEST_OWNER: "moolumi"
  PULUMI_TEST_ORG: "moolumi"
  PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_PROD_ACCESS_TOKEN }}
  # Release builds use the service, PR checks and snapshots will use the local backend if possible.
  PULUMI_TEST_USE_SERVICE: ${{ !contains(inputs.version, '-') }}
  # We're hitting a lot of github limits because of deploytest trying to auto install plugins, skip that for now.
  PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION: "true"
  PYTHON: python
  GO_TEST_PARALLELISM: 8
  GO_TEST_PKG_PARALLELISM: 2
  GO_TEST_SHUFFLE: off
  PULUMI_TEST_RETRIES: ${{ inputs.test-retries }}
  DOTNET_CLI_TELEMETRY_OPTOUT: "true"
  DOTNET_ROLL_FORWARD: "Major"
  SEGMENT_DOWNLOAD_TIMEOUT_MIN: 10
  OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}

jobs:
  test:
    name: ${{ inputs.test-name }}
    env:
      PULUMI_HOME: ${{ github.workspace }}/home
      TEST_ALL_DEPS: ""
      # Point $TMP and $TEMP to the value of `runner.temp` on Windows. This ensures that our Go tests which use
      # os.MkdirTemp create their test environments in this directory. This directory is on the D: drive, as opposed to
      # the C: drive for the default temp directory, and IO seems to be massively faster on that drive.
      # Note: Windows will first use $TMP, then fallback to $TEMP. We set both here for consistency.
      # Similarly, we set GOPATH and GOCACHE to be on the D: drive, so ProgramTest with the Go language runtime will
      # also run on the D: drive, see pkg/testing/integration/program.go#L1990.
      TMP: ${{ contains(inputs.platform, 'windows') && 'D:/a/_temp' || '' }}
      TEMP: ${{ contains(inputs.platform, 'windows') && 'D:/a/_temp' || '' }}
      GOPATH: ${{ contains(inputs.platform, 'windows') && 'D:/go' || '' }}
      GOCACHE: ${{ contains(inputs.platform, 'windows') && 'D:/go-build-cache' || '' }}

    runs-on: ${{ inputs.platform }}

    timeout-minutes: 70
    continue-on-error: ${{ inputs.continue-on-error }}
    steps:
      - if: contains(inputs.platform, 'ubuntu')
        name: Free Disk Space (Ubuntu)
        uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
        with:
          tool-cache: false
          swap-storage: false
          large-packages: false
          dotnet: false

      # Create a coverage file to register a testing job was started.
      # This artifact will be overwritten with "OK" at the end of the job.
      - name: Write test started file
        shell: bash
        run: |
          HASH=$(echo '${{ inputs.test-name }}-${{ inputs.is-integration-test && 'integration' || 'unit' }}' | git hash-object --literally --stdin | awk '{ print $1 }')
          echo "TEST_HASH_ID=${HASH}" >> "$GITHUB_ENV"
      - name: "Windows cache workaround"
        # https://github.com/actions/cache/issues/752#issuecomment-1222415717
        # but only modify the path by adding tar.exe
        if: ${{ runner.os == 'Windows' }}
        env:
          TOOL_BIN: ${{ runner.temp }}/tar-bin
        run: |
          set -x
          mkdir -p "${TOOL_BIN}"
          cp "C:/Program Files/Git/usr/bin/tar.exe" "${TOOL_BIN}"
          PATH="${TOOL_BIN}:${PATH}"
          echo "$TOOL_BIN" | tee -a "$GITHUB_PATH"
          command -v tar
          tar --version
      - name: Reduce Windows test parallelism
        if: ${{ runner.os == 'Windows' }}
        run: |
          {
            echo "GO_TEST_PARALLELISM=4"
            echo "GO_TEST_PKG_PARALLELISM=1"
            echo "GO_TEST_RACE=false"
          } >> "$GITHUB_ENV"
          # For debugging:
          ps aux
      - name: Install tsc on windows and macos
        if: ${{ runner.os == 'windows' || runner.os == 'macOS' }}
        run: |
          npm install typescript -g
      - name: "macOS use coreutils"
        if: ${{ runner.os == 'macOS' }}
        run: |
          set -x
          brew install coreutils
          echo "/usr/local/opt/coreutils/libexec/gnubin" | tee -a "$GITHUB_PATH"
          command -v bash
          bash --version
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Setup versioning env vars
        env:
          version: ${{ inputs.version }}
        run: |
          ./scripts/versions.sh | tee -a "$GITHUB_ENV"
      - name: Enable code coverage
        if: ${{ inputs.enable-coverage }}
        run: |
          echo "PULUMI_TEST_COVERAGE_PATH=$(pwd)/coverage" >> "$GITHUB_ENV"
          # Post integration test coverage to a temporary directory.
          # This will be merged at a later step. Note that we can't
          # use $GOCOVERDIR here, because Go overwrites that env
          # variable when the '-cover' flag is used. Use
          # $PULUMI_GOCOVERDIR instead, which the integration tests
          # then turn into $GOCOVERDIR.  See also https://github.com/golang/go/issues/66225.
          #
          # Also set `GOCOVERDIR` for tests that don't use `go test` (e.g.
          # automation API tests)
          coverdir="$(mktemp -d)"
          echo "PULUMI_GOCOVERDIR=$coverdir" >> "$GITHUB_ENV"
          echo "GOCOVERDIR=$coverdir" >> "$GITHUB_ENV"
      - name: Configure Go Cache Key
        env:
          CACHE_KEY: "${{ fromJson(inputs.version-set).go }}-${{ runner.os }}-${{ runner.arch }}"
        run: echo "$CACHE_KEY" > .gocache.tmp
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        id: setup-go
        env:
          SEGMENT_DOWNLOAD_TIMEOUT_MINS: 2
        with:
          go-version: ${{ fromJson(inputs.version-set).go }}
          check-latest: true
          cache: true
          cache-dependency-path: |
            pkg/go.sum
            .gocache.tmp
      - name: Prime Go cache
        if: ${{ ! steps.setup-go.outputs.cache-hit }}
        # Compile every test to ensure we populate a good cache entry.
        run: |
          ( cd sdk && go test -run "_________" ./... )
          ( cd pkg && go test -run "_________" ./... )
      - name: Install delve
        run: |
          go install github.com/go-delve/delve/cmd/dlv@latest
      - name: Set up uv
        uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
        with:
          enable-cache: true
          cache-dependency-glob: sdk/python/uv.lock
      - name: Set up Python ${{ fromJson(inputs.version-set).python }}
        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
        with:
          python-version: ${{ fromJson(inputs.version-set).python }}
      - name: Set up DotNet ${{ fromJson(inputs.version-set).dotnet }}
        uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4
        with:
          dotnet-version: ${{ fromJson(inputs.version-set).dotnet }}
          dotnet-quality: ga
      - name: Set up Node ${{ fromJson(inputs.version-set).nodejs }}
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: ${{ fromJson(inputs.version-set).nodejs }}
          cache: yarn
          cache-dependency-path: sdk/nodejs/yarn.lock
      - name: Set up JDK 11
        uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
        with:
          java-version: '11'
          distribution: 'temurin'
      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3
        with:
          gradle-version: "7.6"
      - name: Uninstall pre-installed Pulumi (windows)
        if: inputs.platform == 'windows-latest'
        run: |
          if command -v pulumi.exe; then
            echo "Deleting pulumi"
            rm -rf "$(command -v pulumi.exe)/../pulumi*"
          fi
      - name: Install yarn and pnpm
        run: |
          npm install -g yarn pnpm
      - name: Install bun
        uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2
      - name: Install Python deps
        run: |
          python -m pip install --upgrade pip requests wheel urllib3 chardet build
      - name: Install Poetry
        run: python -m pip install poetry
      - name: Setup git
        run: |
          git config --global user.email "you@example.com"
          git config --global user.name "Your Name"
      - name: Set Go Dep path
        run: |
          echo "PULUMI_GO_DEP_ROOT=$(dirname "$(pwd)")" | tee -a "${GITHUB_ENV}"
      - name: Install gotestsum
        uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          repo: gotestyourself/gotestsum
          tag: v1.8.1
          cache: enable
      - name: Install goteststats
        uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          repo: pulumi/goteststats
          tag: v0.0.7
          cache: enable
      - name: Generate artifact name
        if: ${{ inputs.is-integration-test || inputs.is-performance-test }}
        id: goenv
        shell: bash
        run: |
          echo "CLI-TARGET=$(go env GOOS)-$(go env GOARCH)" >> "${GITHUB_OUTPUT}"

      # Ensure tests do not rely on pre-installed packages in CI. Unit tests must run absent a local
      # Pulumi install, and integration tests must only test the version built by CI.
      - name: Remove Pre-installed Pulumi
        env:
          RUNNER_OS: ${{ runner.os }}
        run: |
          EXT=""
          if [ "$RUNNER_OS" == "Windows" ]; then
            EXT=".exe"
          fi

          if command -v "pulumi${EXT}"; then
            PULUMI_INSTALL_DIR=$(dirname "$(command -v "pulumi${EXT}")")
            echo "Deleting Pulumi"
            rm -v "$PULUMI_INSTALL_DIR"/pulumi*
          fi

      # Integration and performance test only steps:
      - name: Download pulumi-${{ steps.goenv.outputs.cli-target }}
        if: ${{ inputs.is-integration-test }}
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          name: artifacts-cli-${{ steps.goenv.outputs.cli-target }}-integration
          path: artifacts/cli
      - name: Download pulumi-${{ steps.goenv.outputs.cli-target }}
        if: ${{ inputs.is-performance-test }}
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          name: artifacts-cli-${{ steps.goenv.outputs.cli-target }}-perf
          path: artifacts/cli
      - name: Install Pulumi Go Binaries
        if: ${{ inputs.is-integration-test || inputs.is-performance-test }}
        run: |
          echo "Checking contents of $PWD/artifacts/cli"
          find "$PWD/artifacts/cli"
          TMPDIR="$(mktemp -d)"

          mkdir -p bin

          # Extract files to temporary directory:
          find "$PWD/artifacts/cli" -name '*.zip' -print0 -exec unzip {} -d "$TMPDIR" \;
          find "$PWD/artifacts/cli" -name '*.tar.gz' -print0 -exec tar -xzvf {} -C "$TMPDIR" \;

          # Windows .zip files have an extra "bin" path part, support both:
          if [ -d "$TMPDIR/pulumi/bin" ]; then
            mv "${TMPDIR}/pulumi/bin/"* "$PWD/bin/"
          else
            mv "${TMPDIR}/pulumi/"* "$PWD/bin/"
          fi

          echo "Checking contents of $PWD/bin"
          find "$PWD/bin"

          LOCAL_PATH=$(./scripts/normpath "${{ github.workspace }}/bin")
          echo "Adding LOCAL_PATH=$LOCAL_PATH to PATH"
          echo "$LOCAL_PATH" >> "$GITHUB_PATH"

        # /end integration and performance test steps
      - name: Verify Pulumi Version
        run: |
          command -v pulumi || echo "no pulumi"
          pulumi version    || echo "no pulumi"
      - name: Ensure dependencies for the Node SDK
        run: |
          cd sdk/nodejs
          make ensure
      - name: Build the Node SDK
        run: |
          cd sdk/nodejs
          make build_package
          cd bin
          yarn link
          bun link
      - name: Ensure dependencies for the Python SDK
        run: |
          cd sdk/python
          make ensure
      - name: Install Python SDK
        run: |
          cd sdk/python
          make build_package
      - name: Set PULUMI_ACCEPT if version-set is not current
        if: ${{ fromJson(inputs.version-set).name != 'current' }}
        run: echo "PULUMI_ACCEPT=TRUE" >> "${GITHUB_ENV}"
      - name: Create GCP service account key file
        run: |
          echo -n '${{ secrets.GCP_SERVICE_ACCOUNT }}' > '${{ runner.temp }}/application_default_credentials.json'
      - name: run tests "${{ inputs.test-command }}"
        id: test
        run: ${{ inputs.test-command }}
        continue-on-error: ${{ inputs.continue-on-error }}
        env:
          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
          AZURE_STORAGE_SAS_TOKEN: ${{ secrets.AZURE_STORAGE_SAS_TOKEN }}
          PULUMI_NODE_MODULES: ${{ runner.temp }}/opt/pulumi/node_modules
          PULUMI_ROOT: ${{ runner.temp }}/opt/pulumi
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GOOGLE_APPLICATION_CREDENTIALS: ${{ runner.temp }}/application_default_credentials.json
          AWS_ACCESS_KEY: ${{ secrets.AWS_CI_ACCESS_KEY }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_CI_ACCESS_SECRET }}
          DOTNET_VERSION: ${{ fromJson(inputs.version-set).dotnet }}
      - name: Convert Node coverage data
        if: ${{ inputs.platform != 'windows-latest' }}
        run: |
          cd sdk/nodejs
          if [ -e .nyc_output ]; then
            UUID=$(python -c "import uuid; print(str(uuid.uuid4()).replace('-', '').lower())")
            COVERAGE_PATH="${PULUMI_TEST_COVERAGE_PATH:-./coverage}"
            yarn run nyc report -r cobertura --report-dir "$COVERAGE_PATH"
            mv "$COVERAGE_PATH/cobertura-coverage.xml" "$COVERAGE_PATH/cobertura-coverage-$UUID.xml"
          fi
      - name: Merge integration test code coverage
        if: ${{ inputs.enable-coverage }}
        run: |
          # Merge coverage data from coverage-instrumented binaries
          # if available.
          if [ -n "$(ls -A "$PULUMI_GOCOVERDIR")" ]; then
            # Cross-platform way to get milliseconds since Unix epoch.
            UUID=$(python -c "import uuid; print(str(uuid.uuid4()).replace('-', '').lower())")

            # First merge coverage data to resolve incompatibilities between different coverage files
            MERGED_DIR=$(mktemp -d)
            if go tool covdata merge -i="$PULUMI_GOCOVERDIR" -o="$MERGED_DIR" 2>/dev/null; then
              # If merge succeeds, convert merged data to text format
              go tool covdata textfmt -i="$MERGED_DIR" -o="$PULUMI_TEST_COVERAGE_PATH/integration-$UUID.cov"
            else
              # If merge fails (e.g., incompatible coverage data), try direct conversion
              # and if that also fails, skip coverage collection for this run
              go tool covdata textfmt -i="$PULUMI_GOCOVERDIR" -o="$PULUMI_TEST_COVERAGE_PATH/integration-$UUID.cov" 2>/dev/null
            fi
            rm -rf "$MERGED_DIR"
          fi
      - name: Upload code coverage
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
        if: ${{ inputs.enable-coverage }}
        with:
          name: coverage-${{ env.TEST_HASH_ID }}
          path: |
            coverage/*
            !coverage/.gitkeep
      - name: Upload codecov test results
        uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1
        with:
          directory: junit/
          fail_ci_if_error: false
          override_branch: ${{ github.event_name == 'merge_group' && 'master' || github.head_ref }}
          verbose: true
          token: ${{ secrets.CODECOV_TOKEN }}
      - name: Summarize Test Time by Package
        continue-on-error: true
        env:
          RUNNER_OS: ${{ runner.os }}
        run: |
          mkdir -p test-results
          touch test-results/empty.json # otherwise goteststats fails below when no files match
          # Remove output lines, they make analysis slower & could leak logs:
          if [ "$RUNNER_OS" == "macOS" ]; then
            # It's just another case of BSD sed, GNU sed.
            sed -i '' -e '/"Action":"output"/d' ./test-results/*.json
          else
            sed -i'' -e '/"Action":"output"/d' ./test-results/*.json
          fi

          goteststats -statistic pkg-time test-results/*.json
      - name: Summarize Test Times by Individual Test
        continue-on-error: true
        run: |
          goteststats -statistic test-time test-results/*.json | head -n 100
          exit_status=$?
          # Ignore SIGPIPE (exit status 141)
          if [[ exit_status -eq 0 || exit_status -eq 141 ]]; then true; else exit $exit_status; fi
      - name: Upload artifacts
        if: ${{ always() }}
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
        with:
          name: gotestsum-test-results-${{ env.TEST_HASH_ID }}
          path: test-results/*.json
command-dispatch .github/workflows/command-dispatch.yml
Triggers
issue_comment
Runs on
ubuntu-latest
Jobs
command-dispatch
Actions
peter-evans/slash-command-dispatch
View raw YAML
name: Command Dispatch for PR events
on:
  issue_comment:
    types: [created]

# Enables maintainers with "write" permission to trigger jobs on external pull requests.

jobs:
  command-dispatch:
    runs-on: ubuntu-latest
    steps:
      - name: Dispatch command
        uses: peter-evans/slash-command-dispatch@40877f718dce0101edfc7aea2b3800cc192f9ed5 # v2
        with:
          token: ${{ secrets.PULUMI_BOT_TOKEN }}
          reaction-token: ${{ secrets.GITHUB_TOKEN }}
          permission: write
          issue-type: pull-request
          repository: pulumi/pulumi
          commands: |
            run-acceptance-tests
            run-docs-gen
            run-codegen
cron-direct-build .github/workflows/cron-direct-build.yml
Triggers
schedule
Runs on
ubuntu-latest, ubuntu-latest
Jobs
pkg, sdk
Actions
jdx/mise-action, pulumi/actions
Commands
  • GOPROXY=direct SDKS="" make build
  • mkdir test cd test pulumi new random-go --generate-only --yes go mod edit -replace github.com/pulumi/pulumi/sdk/v3=../sdk GOPROXY=direct pulumi install
View raw YAML
name: Direct build

on:
  schedule:
  # 1030 UTC every weekday
  - cron: "30 10 * * 1-5"

jobs:
  pkg:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: "1.24"
      - uses: jdx/mise-action@v2
        with:
          experimental: true
      - name: Build
        shell: bash
        run: GOPROXY=direct SDKS="" make build
  sdk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: "1.24"

      - uses: pulumi/actions@v6
        with:
          pulumi-version: dev

      - name: Build
        shell: bash
        run: |
          mkdir test
          cd test
          pulumi new random-go --generate-only --yes
          go mod edit -replace github.com/pulumi/pulumi/sdk/v3=../sdk
          GOPROXY=direct pulumi install
cron-test-all perms .github/workflows/cron-test-all.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
info, ci, performance-gate, ci-ok
Commands
  • exit 1
  • exit 0
View raw YAML
name: Run full language matrix of tests daily

permissions:
  contents: read
  id-token: write

on:
  schedule:
    - cron: "27 5 * * *"
  workflow_dispatch: {}

jobs:
  info:
    name: info
    uses: ./.github/workflows/ci-info.yml
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      is-snapshot: true
    secrets: inherit

  ci:
    name: CI
    needs: [info]
    uses: ./.github/workflows/ci.yml
    permissions:
      contents: read
      id-token: write
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
      lint: true
      test-version-sets: 'all'
      integration-test-platforms: ubuntu-latest
      acceptance-test-platforms: 'macos-latest windows-latest'
      # Disable coverage in daily runs.  This is unfortunately flaky
      # on windows, and the daily cron job runs the most extensive set
      # of tests, leading to quite a bit of flakyness.  We get coverage
      # data on every merge to main, so getting it in the daily cro
      # job is not important.
      enable-coverage: false
    secrets: inherit

  performance-gate:
    name: Performance Gate
    needs: [info]
    uses: ./.github/workflows/ci-performance-gate.yml
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
      test-version-sets: 'all'
      performance-test-platforms: ubuntu-latest
    secrets: inherit

  ci-ok:
    name: ci-ok
    needs: [ci, performance-gate]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - name: CI failed
        if: ${{ needs.ci.result != 'success' }}
        run: exit 1
      - name: CI succeeded
        run: exit 0
download-pulumi-cron matrix .github/workflows/download-pulumi-cron.yml
Triggers
workflow_dispatch, schedule
Runs on
macos-13, macos-13, macos-13, ubuntu-latest, ubuntu-latest, windows-latest, windows-latest, windows-latest, windows-latest, windows-latest, ${{ matrix.os }}
Jobs
macos-homebrew-install, macOS-direct-install, macos-verify-download-link, linux-direct-install, linux-verify-download-link, windows-choco-install, windows-winget-install, windows-direct-install, windows-verify-download-link, windows-verify-msi-download-link, install-via-gha
Matrix
os→ macos-13, ubuntu-latest, windows-latest
Actions
Cyberboss/install-winget, pulumi/action-install-pulumi-cli
Commands
  • rm /usr/local/bin/go || true rm /usr/local/bin/gofmt || true
  • brew update
  • brew install pulumi
  • # shellcheck disable=SC2129 echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}" echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}" echo "previous-version=$(curl -sS https://raw.githubusercontent.com/pulumi/docs/master/data/versions.json | jq -r '.[1].version')" >> "${GITHUB_OUTPUT}"
  • echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}" exit 1
  • curl -fsSL https://get.pulumi.com | sh
  • echo "/Users/runner/.pulumi/bin" >> "${GITHUB_PATH}"
  • echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}" echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
View raw YAML
name: Download Pulumi Cron
"on":
  workflow_dispatch: {}
  schedule:
    - cron: 0 8 * * *

defaults:
  run:
    shell: bash

jobs:
  macos-homebrew-install:
    name: Install Pulumi with Homebrew on macOS
    runs-on: macos-13
    steps:
      # Workaround for https://github.com/pulumi/pulumi/issues/13938
      - name: Delete default golang installed on the runner
        run: |
          rm /usr/local/bin/go || true
          rm /usr/local/bin/gofmt || true
      - name: homedate homebrew formulae
        run: brew update
      - name: homebrew install
        run: brew install pulumi
      - name: Pulumi Version Details
        id: vars
        run: |
          # shellcheck disable=SC2129
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
          echo "previous-version=$(curl -sS https://raw.githubusercontent.com/pulumi/docs/master/data/versions.json | jq -r '.[1].version')" >> "${GITHUB_OUTPUT}"
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version && steps.vars.outputs.previous-version != steps.vars.outputs.installed-version}}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
  macOS-direct-install:
    name: Install Pulumi via script on macOS
    runs-on: macos-13
    steps:
      - run: curl -fsSL https://get.pulumi.com | sh
      - run: echo "/Users/runner/.pulumi/bin" >> "${GITHUB_PATH}"
      - name: Pulumi Version Details
        id: vars
        run: |
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
      - run: command -v pulumi
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version }}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
  macos-verify-download-link:
    name: Verify Direct Download link on macOS
    runs-on: macos-13
    steps:
      - name: Direct Download
        run: curl -L -o pulumi.tar.gz "https://get.pulumi.com/releases/sdk/pulumi-v$(curl -sS https://www.pulumi.com/latest-version)-darwin-x64.tar.gz"
      - run: ls -la
  linux-direct-install:
    name: Install Pulumi via script on Ubuntu
    runs-on: ubuntu-latest
    steps:
      - name: Remove existing version
        run: sudo rm /usr/local/bin/pulumi
      - run: curl -fsSL https://get.pulumi.com | sh
      - run: echo "/home/runner/.pulumi/bin" >> "${GITHUB_PATH}"
      - name: Pulumi Version Details
        id: vars
        run: |
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
      - run: command -v pulumi
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version }}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
  linux-verify-download-link:
    name: Verify Direct Download link on Linux
    runs-on: ubuntu-latest
    steps:
      - name: Direct Download
        run: curl -L -o pulumi.tar.gz "https://get.pulumi.com/releases/sdk/pulumi-v$(curl -sS https://www.pulumi.com/latest-version)-linux-x64.tar.gz"
      - run: ls -la
  windows-choco-install:
    name: Install Pulumi with Chocolatey on Windows
    runs-on: windows-latest
    steps:
      - name: choco install
        run: choco upgrade pulumi
      - name: Pulumi Version Details
        id: vars
        shell: bash
        run: |
          # shellcheck disable=SC2129
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
          echo "previous-version=$(curl -sS https://raw.githubusercontent.com/pulumi/docs/master/data/versions.json | jq -r '.[1].version')" >> "${GITHUB_OUTPUT}"
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version && steps.vars.outputs.previous-version != steps.vars.outputs.installed-version}}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
  windows-winget-install:
    name: Install Pulumi with WinGet on Windows
    runs-on: windows-latest
    steps:
      - name: Remove Pre-installed Pulumi
        shell: bash
        run: |
          if command -v "pulumi.exe"; then
            PULUMI_INSTALL_DIR=$(dirname "$(command -v "pulumi.exe")")
            echo "Deleting Pulumi"
            rm -v "$PULUMI_INSTALL_DIR"/pulumi*
          fi
      - name: Install winget
        uses: Cyberboss/install-winget@1c6f189175e9f015bf1aa113cd1cc6c73efb9d47 # v1
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Install Pulumi Using WinGet
        run: winget install pulumi --disable-interactivity --accept-source-agreements --verbose
      - run: echo "C:/Program Files (x86)/Pulumi" >> "${GITHUB_PATH}"
        shell: bash
      - name: Pulumi Version Details
        id: vars
        shell: bash
        run: |
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version }}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
  windows-direct-install:
    name: Install Pulumi via script on Windows
    runs-on: windows-latest
    steps:
      - run: '[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; iex ((New-Object System.Net.WebClient).DownloadString("https://get.pulumi.com/install.ps1")) && SET \"PATH=%PATH%;%USERPROFILE%\.pulumi\bin\"'
        shell: pwsh
      - run: echo "C:/Users/runneradmin/.pulumi/bin" >> "${GITHUB_PATH}"
        shell: bash
      - name: Pulumi Version Details
        id: vars
        shell: bash
        run: |
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version }}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
  windows-verify-download-link:
    name: Verify Direct Download link on Windows
    runs-on: windows-latest
    steps:
      - name: Direct Download
        shell: pwsh
        run: |
          $latestVersion = (Invoke-WebRequest -UseBasicParsing https://www.pulumi.com/latest-version).Content.Trim()
          $downloadUrl = "https://get.pulumi.com/releases/sdk/pulumi-v${latestVersion}-windows-x64.zip"
          $tempZip = New-Item -Type File (Join-Path $env:TEMP ([System.IO.Path]::ChangeExtension(([System.IO.Path]::GetRandomFileName()), "zip")))
          Invoke-WebRequest https://get.pulumi.com/releases/sdk/pulumi-v${latestVersion}-windows-x64.zip -OutFile $tempZip
      - run: ls -la
        shell: bash
  windows-verify-msi-download-link:
    name: Verify Direct MSI Download link on Windows
    runs-on: windows-latest
    steps:
      - name: Direct Download
        shell: pwsh
        run: |
          $latestVersion = (Invoke-WebRequest -UseBasicParsing https://www.pulumi.com/latest-version).Content.Trim()
          $tempMsi = New-Item -Type File (Join-Path $env:TEMP ([System.IO.Path]::ChangeExtension(([System.IO.Path]::GetRandomFileName()), "msi")))
          Invoke-WebRequest https://github.com/pulumi/pulumi-winget/releases/download/v${latestVersion}/pulumi-${latestVersion}-windows-x64.msi -OutFile $tempMsi
      - run: ls -la
        shell: bash
  install-via-gha:
    name: Install via GHA on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: ["ubuntu-latest", "windows-latest", "macos-13"]
    steps:
      - name: Install Pulumi CLI
        uses: pulumi/action-install-pulumi-cli@v1.0.1
      - name: Pulumi Version Details
        id: vars
        run: |
          echo "installed-version=$(pulumi version)" >> "${GITHUB_OUTPUT}"
          echo "expected-version=v$(curl -sS https://www.pulumi.com/latest-version)" >> "${GITHUB_OUTPUT}"
      - name: Error if incorrect version found
        if: ${{ steps.vars.outputs.expected-version != steps.vars.outputs.installed-version }}
        run: |
          echo "Expected version ${{ steps.vars.outputs.expected-version }} but found ${{ steps.vars.outputs.installed-version }}"
          exit 1
on-community-pr perms .github/workflows/on-community-pr.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
comment-on-pr
Actions
thollander/actions-comment-pull-request
View raw YAML
# SECURITY: This PR run on untrusted branches.
#
# Changes to "permissions" and "secrets" should be narrowly scoped and carefully reviewed.
#
# Reusable workflows, "uses" jobs, *must* specify the main branch.

name: Community Pull Request
on:
  pull_request_target:

permissions:
  contents: read
  # Only required for the PR and changelog comment.
  pull-requests: write

jobs:
  comment-on-pr:
    name: Maintainer comment
    # We only care about commenting on a PR if the PR is from a fork
    if: github.event.pull_request.head.repo.full_name != github.repository
    runs-on: ubuntu-latest
    steps:
      - name: Comment PR
        uses: thollander/actions-comment-pull-request@71efef56b184328c7ef1f213577c3a90edaa4aff # 1.0.1
        with:
          message: |
            PR is now waiting for a maintainer to take action.

            **Note for the maintainer:**  Commands available:

            * `/run-acceptance-tests` - used to test run the acceptance tests for the project
            * `/run-codegen` - used to test the Pull Request against downstream codegen
            * `/run-docs-gen` - used to test the Pull Request against documentation generation
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
on-merge perms .github/workflows/on-merge.yml
Triggers
merge_group
Runs on
ubuntu-latest
Jobs
info, ci, performance-gate, prepare-release, ci-ok
Commands
  • exit 1
  • exit 1
  • exit 0
View raw YAML
name: Merge

permissions:
  # To create a draft release.
  contents: write
  # To sign artifacts.
  id-token: write

on:
  merge_group:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

defaults:
  run:
    shell: bash

jobs:
  info:
    name: info
    uses: ./.github/workflows/ci-info.yml
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      is-snapshot: false
    secrets: inherit

  ci:
    name: CI
    needs: [info]
    uses: ./.github/workflows/ci.yml
    strategy:
      fail-fast: true
    permissions:
      contents: read
      # To sign artifacts.
      id-token: write
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
      enable-coverage: true
      fail-fast: true
      test-retries: 2
      acceptance-test-platforms: 'macos-latest'
      fuzz-test-optional: true
    secrets: inherit

  performance-gate:
    name: Performance Gate
    needs: [info]
    uses: ./.github/workflows/ci-performance-gate.yml
    strategy:
      fail-fast: true
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
      test-version-sets: 'minimum current'
      fail-fast: true
      test-retries: 2
      performance-test-platforms: ubuntu-latest
    secrets: inherit

  prepare-release:
    name: prepare
    needs: [info, ci]
    uses: ./.github/workflows/ci-prepare-release.yml
    permissions:
      contents: write
      # To sign artifacts.
      id-token: write
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
      release-notes: ${{ needs.info.outputs.release-notes }}
      project: ${{ github.repository }}
    secrets: inherit

  ci-ok:
    name: ci-ok
    needs: [ci, performance-gate, prepare-release]
    if: always() # always report a status
    runs-on: ubuntu-latest
    steps:
      - name: CI failed
        if: ${{ needs.ci.result != 'success' }}
        run: exit 1
      - name: Release failed
        if: ${{ needs.prepare-release.result != 'success' }}
        run: exit 1
      - name: CI succeeded
        run: exit 0
on-pr perms .github/workflows/on-pr.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
info, ci, performance-gate, ci-ok
Commands
  • exit 1
  • exit 0
View raw YAML
name: Pull Request

permissions:
  # To create a draft release.
  contents: write
  # To comment on PRs.
  pull-requests: write
  # To sign artifacts.
  id-token: write

on:
  pull_request:
    paths-ignore:
      - "sdk/.version"

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref }}
  cancel-in-progress: true

# The jobs in this workflow are only run on branches. The `on-community-pr.yml` job provides
# commands for running workflows from forks.

jobs:
  info:
    name: info
    if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
    uses: ./.github/workflows/ci-info.yml
    permissions:
      contents: read
    with:
      ref: ${{ github.head_ref }}
      is-snapshot: true
    secrets: inherit

  ci:
    name: CI
    if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
    needs: [info]
    uses: ./.github/workflows/ci.yml
    permissions:
      contents: read
      # To sign artifacts.
      id-token: write
    with:
      ref: ${{ github.head_ref }}
      version: ${{ needs.info.outputs.version }}
      lint: true
      # codegen tests are not the fastest, but we want to run them
      # on PR to get correct coverage numbers.
      test-version-sets: >- # No newlines or trailing newline.
        ${{
          contains(github.event.pull_request.labels.*.name, 'ci/test')
          && 'minimum current'
          || 'current'
        }}
      integration-test-platforms: ubuntu-latest
      acceptance-test-platforms: >- # No newlines or trailing newline.
        ${{
          contains(github.event.pull_request.labels.*.name, 'ci/test')
          && 'macos-latest windows-latest'
          || 'windows-latest'
        }}
      enable-coverage: true
    secrets: inherit

  performance-gate:
    name: Performance Gate
    if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
    needs: [info]
    uses: ./.github/workflows/ci-performance-gate.yml
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
      test-version-sets: 'minimum current'
      performance-test-platforms: ubuntu-latest
    secrets: inherit

  ci-ok:
    name: ci-ok
    needs: [ci, performance-gate]
    if: always()
    runs-on: ubuntu-latest
    steps:
      # If the PR is a community PR, we don't run the usual checks, but instead
      # require maintainers to run them manually by commenting with
      # /run-acceptance-tests. Since the checks then run outside of the PR,
      # ci-ok is not a useful status in these cases. We thus want to skip this
      # job for community PRs. We detect community contributions by checking if
      # the head repository is different to the base repository.
      - name: CI failed
        if: ${{ github.event.pull_request.head.repo.full_name == github.repository && needs.ci.result != 'success' }}
        run: exit 1
      - name: CI succeeded
        run: exit 0
on-pr-close .github/workflows/on-pr-close.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
cleanup
Commands
  • for url in $(gh search prs --json url --owner pulumi --state open --match body "This is a downstream codegen test for pulumi/pulumi#${{ github.event.pull_request.number }}." | jq -r '.[].url'); do gh pr close "$url" done
View raw YAML
name: On PR Close

on:
  pull_request:
    types: [ closed ]

jobs:
    cleanup:
      name: Remove Existing Codegen PRs
      runs-on: ubuntu-latest
      continue-on-error: true
      env:
        GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
      steps:
        - name: "Close existing Downstream PRs"
          run: |
            for url in $(gh search prs --json url --owner pulumi --state open --match body "This is a downstream codegen test for pulumi/pulumi#${{ github.event.pull_request.number }}." | jq -r '.[].url'); do
                gh pr close "$url"
            done
on-pr-default .github/workflows/on-pr-default.yml
Triggers
pull_request
Runs on
ubuntu-latest, ubuntu-latest
Jobs
no-op, ci-ok
Commands
  • echo 'No need to run CI tests when only .version changes'
  • exit 0
View raw YAML
# This file fires for the same events as `on-pr.yml`,
# except where `on-pr.yml` skips over changes in paths-ignore,
# this event fires on the inverse.
# This is an officially blessed pattern for handling skipped but
# required status checks. See
# https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
# for more information.
name: Pull Request

on:
  pull_request:
    paths-ignore:
      - "**" # Skip all files…
      - "!sdk/.version" # …except if only this file changes and nothing else.
jobs:
  no-op:
    name: Skip CI on .version changes
    runs-on: ubuntu-latest
    steps:
      - name: Skip CI on .version changes
        run: echo 'No need to run CI tests when only .version changes'

  ci-ok:
    name: ci-ok
    runs-on: ubuntu-latest
    steps:
      - name: CI succeeded
        run: exit 0
on-push perms .github/workflows/on-push.yml
Triggers
push
Runs on
ubuntu-latest, ubuntu-latest
Jobs
info, dev-release, update-dev-version, tag-pkg
Actions
jaxxstorm/action-install-gh-release, proudust/gh-describe
Commands
  • if [ "$(git ls-remote https://github.com/pulumi/pulumi HEAD | cut -f 1)" = "${{ github.sha }}" ]; then short_sha="x${{ steps.ghd.outputs.short-sha }}" version="${{ needs.info.outputs.version }}" version="${version#v}-alpha.${short_sha}" pulumictl dispatch -c pulumi-cli-dev-version -r pulumi/docs dev_version="$version" else echo "Not updating latest version as there has been a new push to the main branch" fi
  • title=$(git show --pretty=format:%s -s HEAD) if [[ $title == "Changelog and go.mod updates for"* ]]; then pkg_version="${title#*updates for }" pkg_version="${pkg_version% \(*}" git tag "pkg/${pkg_version}" git push origin "pkg/${pkg_version}" fi
View raw YAML
name: On Push

permissions:
  # To push the tag
  contents: write

on:
  push:
    branches:
      - 'master'

jobs:
  info:
    name: info
    uses: ./.github/workflows/ci-info.yml
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      is-snapshot: false
    secrets: inherit

  dev-release:
    name: dev-release
    needs: [info]
    uses: ./.github/workflows/ci-dev-release.yml
    permissions:
      contents: write
      # To sign artifacts.
      id-token: write
    with:
      ref: ${{ github.ref }}
      version: ${{ needs.info.outputs.version }}
    secrets: inherit

  update-dev-version:
    name: update-dev-version
    needs: [dev-release, info]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ github.ref }}
      - name: Install Pulumictl
        uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          repo: pulumi/pulumictl
          tag: v0.0.46
          cache: enable
      - name: Git describe
        id: ghd
        uses: proudust/gh-describe@v1
      - name: Dispatch event to docs repo
        env:
          GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
        # Always prefix the short_sha with a letter to ensure it's a valid semver prerelease,
        # see https://github.com/pulumi/pulumi/issues/15471 for context.
        run: |
          if [ "$(git ls-remote https://github.com/pulumi/pulumi HEAD | cut -f 1)" = "${{ github.sha }}" ]; then
            short_sha="x${{ steps.ghd.outputs.short-sha }}"
            version="${{ needs.info.outputs.version }}"
            version="${version#v}-alpha.${short_sha}"
            pulumictl dispatch -c pulumi-cli-dev-version -r pulumi/docs dev_version="$version"
          else
            echo "Not updating latest version as there has been a new push to the main branch"
          fi

  tag-pkg:
    name: tag-pkg
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - name: Tag and push pkg version if necessary
        run: |
          title=$(git show --pretty=format:%s -s HEAD)
          if [[ $title == "Changelog and go.mod updates for"* ]]; then
            pkg_version="${title#*updates for }"
            pkg_version="${pkg_version% \(*}"
            git tag "pkg/${pkg_version}"
            git push origin "pkg/${pkg_version}"
          fi
on-release perms .github/workflows/on-release.yml
Triggers
release
Runs on
ubuntu-latest
Jobs
info, release
Commands
  • TAG="${{ github.event.release.tag_name }}" PULUMI_VERSION="${TAG#v}" # remove prefix ./.github/scripts/set-output version "${PULUMI_VERSION}"
View raw YAML
name: Release

permissions:
  # To create the follow-up PR.
  contents: write
  pull-requests: write

on:
  release:
    types:
      - released

concurrency: release

jobs:
  info:
    name: gather
    runs-on: ubuntu-latest
    outputs:
      version: "${{ fromJSON(steps.version.outputs.version) }}"
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        # Uses release ref (tag)
      - name: Info
        id: version
        run: |
          TAG="${{ github.event.release.tag_name }}"
          PULUMI_VERSION="${TAG#v}" # remove prefix

          ./.github/scripts/set-output version "${PULUMI_VERSION}"

  release:
    name: release
    needs: [info]
    uses: ./.github/workflows/release.yml
    with:
      ref: ${{ github.event.release.tag_name }}
      version: ${{ needs.info.outputs.version }}
      release-notes: ${{ github.event.release.body }}
      queue-merge: true
      run-dispatch-commands: true
    secrets: inherit
pr-test-acceptance-on-dispatch perms .github/workflows/pr-test-acceptance-on-dispatch.yml
Triggers
repository_dispatch
Runs on
ubuntu-latest
Jobs
info, comment-notification, ci
Actions
peter-evans/create-or-update-comment
View raw YAML
# SECURITY: This PR run on untrusted branches when a maintainer comments "/run-acceptance-tests".
#
# Changes "permissions" and "secrets" should be narrowly scoped and carefully reviewed.
#
# Reusable workflows, "uses" jobs, *must* specify the main branch.

name: dispatched-acceptance-test

on:
  repository_dispatch:
    types: [run-acceptance-tests-command]

permissions:
  contents: read
  # Only the 'changelog-comment' job should use this permission.
  pull-requests: write
  # To sign artifacts.
  id-token: write

concurrency:
  group: ${{ github.workflow }}-${{ github.event.client_payload.pull_request.number }}
  cancel-in-progress: true

jobs:
  info:
    name: info
    uses: pulumi/pulumi/.github/workflows/ci-info.yml@master
    permissions:
      contents: read
    with:
      ref: ${{ github.ref }}
      is-snapshot: true
    secrets: inherit

  comment-notification:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'repository_dispatch' }}
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Update with Result
        uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
        with:
          token: ${{ secrets.PULUMI_BOT_TOKEN }}
          repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
          comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
          issue-number: ${{ github.event.client_payload.github.payload.issue.number }}
          body: |
            Please view the results of the acceptance tests [Here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})

  ci:
    name: CI
    needs: [info]
    uses: pulumi/pulumi/.github/workflows/ci.yml@master
    permissions:
      contents: read
      # To sign artifacts.
      id-token: write
    with:
      ref: refs/pull/${{ github.event.client_payload.pull_request.number }}/merge
      version: ${{ needs.info.outputs.version }}
      lint: true
      test-version-sets: current
      integration-test-platforms: ubuntu-latest
      acceptance-test-platforms: 'windows-latest'
      # We'll only upload coverage artifacts with the periodic-coverage cron workflow.
      enable-coverage: false
    secrets:
      # Scope secrets to the minimum required:
      PULUMI_PROD_ACCESS_TOKEN: ${{ secrets.PULUMI_PROD_ACCESS_TOKEN }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
      AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
      AZURE_STORAGE_SAS_TOKEN: ${{ secrets.AZURE_STORAGE_SAS_TOKEN }}
      GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
rebase .github/workflows/rebase.yml
Triggers
issue_comment
Runs on
ubuntu-latest
Jobs
rebase
Actions
cirrus-actions/rebase
View raw YAML
name: Automatic Rebase
on:
  issue_comment:
    types: [created]
jobs:  
  rebase:
    name: Rebase
    runs-on: ubuntu-latest
    if: >-
      contains(fromJSON('["COLLABORATOR", "MEMBER", "OWNER"]'), github.event.comment.author_association) &&
      github.event.issue.pull_request != '' && 
      (
        contains(github.event.comment.body, '/rebase') || 
        contains(github.event.comment.body, '/autosquash')
      )
    steps:
      - name: Checkout the latest code
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          token: ${{ secrets.PULUMI_BOT_TOKEN }}
          fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
      - name: Automatic Rebase
        uses: cirrus-actions/rebase@50007412be906b9cc222db3dfc469f325031f1b2
        with:
          autosquash: ${{ contains(github.event.comment.body, '/autosquash') || contains(github.event.comment.body, '/rebase-autosquash') }}
        env:
          GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
release matrix perms .github/workflows/release.yml
Triggers
workflow_call
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
sdks, s3-blobs, pr, dispatch, update-homebrew-tap
Matrix
job, job.name, job.run-command, language→ Build Package Docs, Chocolatey Update, Docker containers, Homebrew, Update Templates Version, Winget Update, go, nodejs, pulumictl create choco-deploy "${PULUMI_VERSION}", pulumictl create cli-docs-build "${PULUMI_VERSION}", pulumictl create homebrew-bump "${PULUMI_VERSION}" "$(git rev-parse HEAD)", pulumictl dispatch -r pulumi/pulumi-docker-containers -c release-build "${PULUMI_VERSION}", pulumictl dispatch -r pulumi/templates -c update-templates "${PULUMI_VERSION}", pulumictl winget-deploy, python
Actions
astral-sh/setup-uv, aws-actions/configure-aws-credentials, jaxxstorm/action-install-gh-release
Commands
  • mkdir -p artifacts gh release download "v${PULUMI_VERSION}" --dir ./artifacts --pattern 'sdk-${{ matrix.language }}-*' find artifacts
  • make -C sdk/${{ matrix.language}} publish
  • mkdir -p artifacts gh release download "v${PULUMI_VERSION}" --dir ./artifacts --pattern 'pulumi-*' find artifacts
  • aws s3 sync artifacts s3://get.pulumi.com/releases/sdk --acl public-read
  • ${{ matrix.job.run-command }}
View raw YAML
name: Release Actions

permissions:
  # To create a PR
  contents: write
  pull-requests: write

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      branch_from_ref:
        required: false
        description: "Commit to branch from, if not the tag"
        type: string
      release-notes:
        required: true
        description: "Release notes to publish"
        type: string
      queue-merge:
        required: false
        default: false
        description: "Whether to queue the release for immediate merge"
        type: boolean
      run-dispatch-commands:
        required: false
        default: false
        # If version contains a '-', i.e.: a prerelease build, these commands are disabled until further notice.
        description: "Whether to run dispatch commands"
        type: boolean
      version-set:
        required: false
        description: "Set of language versions to use for builds, lints, releases, etc."
        type: string
        # Example provided for illustration, this value is derived by scripts/get-job-matrix.py build
        default: |
          {
            "dotnet": "8.0.x",
            "go": "1.18.x",
            "nodejs": "20.x",
            "python": "3.9.x"
          }

env:
  PULUMI_VERSION: ${{ inputs.version }}
  GIT_REF: ${{ inputs.ref }}
  GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
  PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_PROD_ACCESS_TOKEN }}
  PULUMI_TEST_OWNER: "moolumi"
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
  PYPI_USERNAME: __token__
  PYPI_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}

jobs:
  sdks:
    name: ${{ matrix.language }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        language: ["nodejs", "python", "go"]
    steps:
      - name: Checkout Repo
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Set up uv
        if: ${{ matrix.language == 'python' }}
        uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
        with:
          enable-cache: true
          cache-dependency-glob: sdk/python/uv.lock
      - name: Set up Python ${{ fromJson(inputs.version-set).python }}
        if: ${{ matrix.language == 'python' }}
        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
        with:
          python-version: ${{ fromJson(inputs.version-set).python }}
      - name: Set up Node ${{ fromJson(inputs.version-set).nodejs }}
        if: ${{ matrix.language == 'nodejs' }}
        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: ${{ fromJson(inputs.version-set).nodejs }}
          registry-url: https://registry.npmjs.org
          always-auth: true
      - name: Download release artifacts
        if: ${{ matrix.language != 'go' }}
        run: |
          mkdir -p artifacts
          gh release download "v${PULUMI_VERSION}" --dir ./artifacts --pattern 'sdk-${{ matrix.language }}-*'
          find artifacts
      - name: Publish Packages
        run: |
          make -C sdk/${{ matrix.language}} publish

  s3-blobs:
    name: s3 blobs
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-region: us-east-2
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          role-duration-seconds: 3600
          role-external-id: upload-pulumi-release
          role-session-name: pulumi@githubActions
          role-to-assume: ${{ secrets.AWS_UPLOAD_ROLE_ARN }}
      - name: Download release artifacts
        run: |
          mkdir -p artifacts
          gh release download "v${PULUMI_VERSION}" --dir ./artifacts --pattern 'pulumi-*'
          find artifacts
      - name: Publish Blobs
        run: |
          aws s3 sync artifacts s3://get.pulumi.com/releases/sdk --acl public-read

  pr:
    # Relies on the Go SDK being published to update pkg
    name: PR
    needs: [sdks]
    uses: ./.github/workflows/release-pr.yml
    permissions:
      contents: write
      pull-requests: write
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      release-notes: ${{ inputs.release-notes }}
      queue-merge: ${{ inputs.queue-merge }}
    secrets: inherit

  dispatch:
    name: ${{ matrix.job.name }}
    if: inputs.run-dispatch-commands && !contains(inputs.version, '-')
    runs-on: ubuntu-latest
    needs: [pr]
    strategy:
      fail-fast: false
      matrix:
        job:
          - name: Update Templates Version
            run-command: pulumictl dispatch -r pulumi/templates -c update-templates "${PULUMI_VERSION}"
          - name: Chocolatey Update
            run-command: pulumictl create choco-deploy "${PULUMI_VERSION}"
          - name: Winget Update
            run-command: pulumictl winget-deploy
          - name: Build Package Docs
            run-command: pulumictl create cli-docs-build "${PULUMI_VERSION}"
          - name: Homebrew
            run-command: pulumictl create homebrew-bump "${PULUMI_VERSION}" "$(git rev-parse HEAD)"
          - name: Docker containers
            run-command: pulumictl dispatch -r pulumi/pulumi-docker-containers -c release-build "${PULUMI_VERSION}"
    steps:
      - name: Checkout Repo
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - name: Install Pulumictl
        uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0
        env:
          GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
        with:
          repo: pulumi/pulumictl
          tag: v0.0.42
          cache: enable
      - name: Repository Dispatch
        run: ${{ matrix.job.run-command }}


  update-homebrew-tap:
    name: Update Homebrew Tap
    if: inputs.run-dispatch-commands && !contains(inputs.version, '-')
    needs: [dispatch]
    uses: ./.github/workflows/release-homebrew-tap.yml
    permissions:
      contents: read
    with:
      ref: ${{ inputs.ref }}
      version: ${{ inputs.version }}
      dry-run: false
    secrets: inherit
release-homebrew-tap perms .github/workflows/release-homebrew-tap.yml
Triggers
workflow_call, workflow_dispatch
Runs on
ubuntu-latest
Jobs
update-homebrew-tap
Commands
  • set -euo pipefail # Can simulate this by cloning pulumi/pulumi & pulumi/homebrew-tap to adacent directories # and running from their parent: ./pulumi/.github/scripts/generate-homebrew-tap \ "${PULUMI_VERSION}" ./pulumi/.github/scripts/pulumi-tap-template.rb \ > ./homebrew-tap/Formula/pulumi.rb
  • set -euo pipefail git config user.name pulumi-bot git config user.email bot@pulumi.com git add Formula/pulumi.rb echo "::group::git diff" git --no-pager diff echo "::endgroup::" git commit -m "Brew formula update for Pulumi version ${PULUMI_VERSION}"
  • set -euo pipefail git push origin HEAD:main
View raw YAML
name: Post-Release Homebrew Tap

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      dry-run:
        required: false
        default: true
        description: "Whether to run in dry-run mode and skip pushing the commit"
        type: boolean
  workflow_dispatch:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      dry-run:
        required: false
        default: true
        description: "Whether to run in dry-run mode and skip pushing the commit"
        type: boolean

env:
  PULUMI_VERSION: ${{ inputs.version }}
  GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}

jobs:
  update-homebrew-tap:
    name: Update Homebrew Tap
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
          path: pulumi
      - name: Checkout tap repo
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          repository: pulumi/homebrew-tap
          path: homebrew-tap
          token: ${{ secrets.PULUMI_BOT_TOKEN }}
      - name: Update Homebrew Tap
        run: |
          set -euo pipefail

          # Can simulate this by cloning pulumi/pulumi & pulumi/homebrew-tap to adacent directories
          # and running from their parent:

          ./pulumi/.github/scripts/generate-homebrew-tap \
            "${PULUMI_VERSION}" ./pulumi/.github/scripts/pulumi-tap-template.rb \
            > ./homebrew-tap/Formula/pulumi.rb
      - name: Commit updated formula
        working-directory: homebrew-tap
        run: |
          set -euo pipefail

          git config user.name pulumi-bot
          git config user.email bot@pulumi.com
          git add Formula/pulumi.rb
          echo "::group::git diff"
          git  --no-pager diff
          echo "::endgroup::"
          git commit -m "Brew formula update for Pulumi version ${PULUMI_VERSION}"
      - name: Push formula
        working-directory: homebrew-tap
        if: ${{ !inputs.dry-run }}
        run: |
          set -euo pipefail

          git push origin HEAD:main
release-pr perms .github/workflows/release-pr.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
version-bump
Commands
  • set -euo pipefail git switch --create "automation/release-v${PULUMI_VERSION}" echo -en "# Changelog\n\n${RELEASE_NOTES}\n\n$(tail -n+3 CHANGELOG.md)" > ./CHANGELOG.md git config user.name github-actions git config user.email github-actions@github.com rm ./changelog/pending/*.yaml || true git add -A git commit -m "chore: changelog for v${PULUMI_VERSION}" # Update go module dependencies ( cd pkg go get -u "github.com/pulumi/pulumi/sdk/v3@v${PULUMI_VERSION}" ) make tidy_fix git add -A git commit -m "chore: post-release go.mod updates" git push -u origin HEAD # Note that the title of the PR is used in the on-push workflow. If the title needs to # change here, please also check on-push.yml PR=$(gh pr create --title "Changelog and go.mod updates for v${PULUMI_VERSION}" --body "") if [ "${QUEUE_MERGE}" = "true" ]; then gh pr merge --auto --squash "${PR}" fi
View raw YAML
name: Post-Release PR

permissions:
  # To create a PR
  contents: write
  pull-requests: write

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string
      branch_from_ref:
        required: false
        description: "Commit to branch from, if not the tag"
        type: string
      release-notes:
        required: true
        description: "Release notes to publish"
        type: string
      queue-merge:
        required: false
        default: false
        description: "Whether to queue the release for immediate merge"
        type: boolean

jobs:
  version-bump:
    name: version bump
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}
      - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
        with:
          go-version: '>=1.19.0' # decoupled from version sets, only used by changelog tool
      - name: Create PR
        env:
          PULUMI_VERSION: ${{ inputs.version }}
          RELEASE_NOTES: ${{ inputs.release-notes }}
          QUEUE_MERGE: ${{ inputs.queue-merge }}
          GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
        run: |
          set -euo pipefail
          git switch --create "automation/release-v${PULUMI_VERSION}"

          echo -en "# Changelog\n\n${RELEASE_NOTES}\n\n$(tail -n+3 CHANGELOG.md)" > ./CHANGELOG.md

          git config user.name github-actions
          git config user.email github-actions@github.com

          rm ./changelog/pending/*.yaml || true
          git add -A

          git commit -m "chore: changelog for v${PULUMI_VERSION}"

          # Update go module dependencies
          (
            cd pkg
            go get -u "github.com/pulumi/pulumi/sdk/v3@v${PULUMI_VERSION}"
          )
          make tidy_fix
          git add -A
          git commit -m "chore: post-release go.mod updates"

          git push -u origin HEAD

          # Note that the title of the PR is used in the on-push workflow.  If the title needs to
          # change here, please also check on-push.yml
          PR=$(gh pr create --title "Changelog and go.mod updates for v${PULUMI_VERSION}" --body "")

          if [ "${QUEUE_MERGE}" = "true" ]; then
            gh pr merge --auto --squash "${PR}"
          fi
sign perms .github/workflows/sign.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
sign
Actions
baptiste0928/cargo-install, sigstore/cosign-installer
Commands
  • rm -rf artifacts.tmp/*-perf
  • rm -rf artifacts.tmp/*-integration
  • ( cd artifacts.tmp/artifacts-python-sdk for file in *.whl ; do mv -vT "$file" "sdk-python-$file" done ) ( cd artifacts.tmp/artifacts-nodejs-sdk for file in *.tgz ; do mv -vT "$file" "sdk-nodejs-$file" done )
  • mkdir -p ./artifacts mv ./artifacts.tmp/artifacts-*/* ./artifacts
  • # Extract pulumi binary to bintest rather than pollute artifacts directory. mkdir './bintest' && tar -xvf ./artifacts/pulumi-*-linux-x64.tar.gz -C './bintest/.' # Ensure pulumi binary exists. stat './bintest/pulumi/pulumi' || exit 1 # Check binary not built with coverage. if ./bintest/pulumi/pulumi version 2>&1 | grep coverage; then echo 'Aborting! Pulumi binary built with coverage data.' exit 2 else echo 'Pulumi binary OK!' fi
  • mkdir -p ./sums.tmp ./sigs.tmp
  • sha256sum ./pulumi-*.{tar.gz,zip} | sed 's/.\///' | tee "../sums.tmp/pulumi-${version}-checksums.txt"
  • b3sum ./* | sed 's/.\///' | tee ../sums.tmp/B3SUMS
View raw YAML
name: Sign

permissions:
  # To sign artifacts.
  id-token: write

on:
  workflow_call:
    inputs:
      ref:
        required: true
        description: "GitHub ref to use"
        type: string
      version:
        required: true
        description: "Version to produce"
        type: string

jobs:
  sign:
    name: sign
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          ref: ${{ inputs.ref }}

      - name: Install b3sum
        uses: baptiste0928/cargo-install@b687c656bda5733207e629b50a22bf68974a0305 # v3
        with:
          crate: b3sum
          version: 1.3.0

      - uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2

      - name: Download all artifacts
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
        with:
          path: artifacts.tmp
      - name: Remove performance test artifacts
        run: rm -rf artifacts.tmp/*-perf
      - name: Remove integration test artifacts
        run: rm -rf artifacts.tmp/*-integration
      - name: Rename SDKs
        # This step must match the rename SDKs step in the "publish" job below.
        run: |
          (
            cd artifacts.tmp/artifacts-python-sdk
            for file in *.whl ; do
              mv -vT "$file" "sdk-python-$file"
            done
          )
          (
            cd artifacts.tmp/artifacts-nodejs-sdk
            for file in *.tgz ; do
              mv -vT "$file" "sdk-nodejs-$file"
            done
          )
      - name: Flatten artifact directories
        run: |
          mkdir -p ./artifacts
          mv ./artifacts.tmp/artifacts-*/* ./artifacts

      - name: Ensure coverage not enabled on release
        run: |
          # Extract pulumi binary to bintest rather than pollute artifacts directory.
          mkdir './bintest' && tar -xvf ./artifacts/pulumi-*-linux-x64.tar.gz -C './bintest/.'

          # Ensure pulumi binary exists.
          stat './bintest/pulumi/pulumi' || exit 1

          # Check binary not built with coverage.
          if ./bintest/pulumi/pulumi version 2>&1 | grep coverage; then
            echo 'Aborting! Pulumi binary built with coverage data.'
            exit 2
          else
            echo 'Pulumi binary OK!'
          fi

      - name: Create sums.tmp
        run: mkdir -p ./sums.tmp ./sigs.tmp

        # Each of these commands strips the ./ prefix to match existing (<=3.39) formatting.
      - name: Checksums with SHA256
        working-directory: artifacts
        env:
          version: ${{ inputs.version }}
        run: sha256sum ./pulumi-*.{tar.gz,zip} | sed 's/.\///' | tee "../sums.tmp/pulumi-${version}-checksums.txt"

      - name: Checksums with BLAKE3
        working-directory: artifacts
        run: b3sum ./* | sed 's/.\///' | tee ../sums.tmp/B3SUMS

      - name: Checksums with SHA512
        working-directory: artifacts
        run: sha512sum ./* | sed 's/.\///' | tee ../sums.tmp/SHA512SUMS

      - name: Sign binaries and checksums
        shell: bash
        env:
          version: ${{ inputs.version }}
        run: |
          ls -la
          # Sign all artifacts and checksums:
          for dir in "artifacts" "sums.tmp"; do
            pushd "$dir"
            for file in ./*; do
                echo "$file"
                COSIGN_EXPERIMENTAL=1 cosign sign-blob --yes \
                  --bundle="../sigs.tmp/${file}".sig  \
                  "${file}"
            done
            popd
          done

          # flatten to a single directory to upload:
          mv sums.tmp/* sigs.tmp

      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
        with:
          name: artifacts-signatures
          retention-days: 1
          path: |
            sigs.tmp/*
          if-no-files-found: error
trigger-homebrew-event .github/workflows/trigger-homebrew-event.yml
Triggers
repository_dispatch
Runs on
ubuntu-latest
Jobs
homebrew
Actions
dawidd6/action-homebrew-bump-formula
Commands
  • echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> "${GITHUB_PATH}"
View raw YAML
env:
  GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
  VERSION: ${{ github.event.client_payload.ref }}
  COMMIT_SHA: ${{ github.event.client_payload.commitSha }}

on:
  repository_dispatch:
    types:
      - homebrew-bump

jobs:
  homebrew:
    name: Bump Homebrew formula
    runs-on: ubuntu-latest
    steps:
      - name: Add Homebrew to the PATH
        run: |
          echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> "${GITHUB_PATH}"
      - uses: dawidd6/action-homebrew-bump-formula@1446dca236b0440c6f02723a3f14f13be2c04ab0 # v7
        with:
          token: ${{secrets.PULUMI_BOT_HOMEBREW_TOKEN}}
          formula: pulumi
          tag: v${{env.VERSION}}
          revision: ${{env.COMMIT_SHA}}
trigger-release-docs-event .github/workflows/trigger-release-docs-event.yml
Triggers
repository_dispatch
Runs on
ubuntu-latest
Jobs
docs
Commands
  • ./ci-scripts/ci/build-package-docs.sh "pulumi"
View raw YAML
env:
  GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
  VERSION: ${{ github.event.client_payload.ref }}
  COMMIT_SHA: ${{ github.event.client_payload.commitSha }}

on:
  repository_dispatch:
    types:
      - docs

jobs:
  docs:
    name: Build Package Docs
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - name: Checkout Scripts Repo
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          path: ci-scripts
          repository: pulumi/scripts
      - name: Trigger Docs Build
        run: |
          ./ci-scripts/ci/build-package-docs.sh "pulumi"
        env:
          TRAVIS: true
          PULUMI_BOT_GITHUB_API_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
          TRAVIS_TAG: ${{ env.VERSION }}