From 9295bdcdc8e7b5380a05b29d74c290a99a7f98a4 Mon Sep 17 00:00:00 2001
From: Ringo De Smet <ringo@de-smet.name>
Date: Thu, 28 Nov 2024 09:03:27 +0100
Subject: [PATCH] Regenerate workflows for pulumi-acme (#93)

Co-authored-by: pulumi-bot <bot@pulumi.com>
---
 .github/actions/download-bin/action.yml     |   2 +-
 .github/actions/download-sdk/action.yml     |   2 +-
 .github/actions/setup-tools/action.yml      |  18 +-
 .github/actions/upload-bin/action.yml       |   2 +-
 .github/actions/upload-sdk/action.yml       |   2 +-
 .github/workflows/build_provider.yml        |  13 +-
 .github/workflows/build_sdk.yml             |  10 +-
 .github/workflows/license.yml               |   2 +-
 .github/workflows/lint.yml                  |   6 +-
 .github/workflows/main.yml                  |  15 +-
 .github/workflows/prerelease.yml            |   9 +-
 .github/workflows/prerequisites.yml         |  22 +-
 .github/workflows/publish.yml               |  12 +-
 .github/workflows/pull-request.yml          |   4 +-
 .github/workflows/pull-workflow-changes.yml |  40 ---
 .github/workflows/release.yml               |   9 +-
 .github/workflows/resync-build.yml          |   6 +-
 .github/workflows/run-acceptance-tests.yml  |  15 +-
 .github/workflows/upgrade-bridge.yml        |   6 +-
 .github/workflows/upgrade-provider.yml      |   2 +-
 .github/workflows/verify-release.yml        |   2 +-
 .gitignore                                  |   5 +-
 Makefile                                    | 271 +++++++++++++-------
 23 files changed, 266 insertions(+), 209 deletions(-)
 delete mode 100644 .github/workflows/pull-workflow-changes.yml

diff --git a/.github/actions/download-bin/action.yml b/.github/actions/download-bin/action.yml
index 84891f9..c6f85c5 100644
--- a/.github/actions/download-bin/action.yml
+++ b/.github/actions/download-bin/action.yml
@@ -5,7 +5,7 @@ runs:
   using: "composite"
   steps:
     - name: Download provider + tfgen binaries
-      uses: actions/download-artifact@v4
+      uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
       with:
         name: acme-provider.tar.gz
         path: ${{ github.workspace }}/bin
diff --git a/.github/actions/download-sdk/action.yml b/.github/actions/download-sdk/action.yml
index 1fd5484..ec5a2f3 100644
--- a/.github/actions/download-sdk/action.yml
+++ b/.github/actions/download-sdk/action.yml
@@ -10,7 +10,7 @@ runs:
   using: "composite"
   steps:
     - name: Download ${{ inputs.language }} SDK
-      uses: actions/download-artifact@v4
+      uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
       with:
         name: ${{ inputs.language }}-sdk.tar.gz
         path: ${{ github.workspace}}/sdk/
diff --git a/.github/actions/setup-tools/action.yml b/.github/actions/setup-tools/action.yml
index 642d1d2..6a711d4 100644
--- a/.github/actions/setup-tools/action.yml
+++ b/.github/actions/setup-tools/action.yml
@@ -20,7 +20,7 @@ runs:
   steps:
     - name: Install Go
       if: inputs.tools == 'all' || contains(inputs.tools, 'go')
-      uses: actions/setup-go@v5
+      uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5
       with:
         go-version: "1.21.x"
         cache-dependency-path: |
@@ -30,45 +30,45 @@ runs:
 
     - name: Install pulumictl
       if: inputs.tools == 'all' || contains(inputs.tools, 'pulumictl')
-      uses: jaxxstorm/action-install-gh-release@v1.11.0
+      uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0
       with:
         tag: v0.0.46
         repo: pulumi/pulumictl
 
     - name: Install Pulumi CLI
       if: inputs.tools == 'all' || contains(inputs.tools, 'pulumicli')
-      uses: pulumi/actions@v5
+      uses: pulumi/actions@c7fad9e2f0b79653172b36538b8b34b3c0291952 # v6
       with:
         pulumi-version: "dev"
 
     - name: Install Schema Tools
       if: inputs.tools == 'all' || contains(inputs.tools, 'schema-tools')
-      uses: jaxxstorm/action-install-gh-release@v1.11.0
+      uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0
       with:
         repo: pulumi/schema-tools
 
     - name: Setup Node
       if: inputs.tools == 'all' || contains(inputs.tools, 'nodejs')
-      uses: actions/setup-node@v4
+      uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
       with:
         node-version: 20.x
         registry-url: https://registry.npmjs.org
 
     - name: Setup DotNet
       if: inputs.tools == 'all' || contains(inputs.tools, 'dotnet')
-      uses: actions/setup-dotnet@v4
+      uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4
       with:
         dotnet-version: 6.0.x
 
     - name: Setup Python
       if: inputs.tools == 'all' || contains(inputs.tools, 'python')
-      uses: actions/setup-python@v5
+      uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5
       with:
         python-version: 3.11.8
 
     - name: Setup Java
       if: inputs.tools == 'all' || contains(inputs.tools, 'java')
-      uses: actions/setup-java@v4
+      uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4
       with:
         cache: gradle
         distribution: temurin
@@ -76,6 +76,6 @@ runs:
 
     - name: Setup Gradle
       if: inputs.tools == 'all' || contains(inputs.tools, 'java')
-      uses: gradle/gradle-build-action@v3
+      uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3
       with:
         gradle-version: 7.6
diff --git a/.github/actions/upload-bin/action.yml b/.github/actions/upload-bin/action.yml
index c3cd198..5399166 100644
--- a/.github/actions/upload-bin/action.yml
+++ b/.github/actions/upload-bin/action.yml
@@ -8,7 +8,7 @@ runs:
       shell: bash
       run: tar -zcf ${{ github.workspace }}/bin/provider.tar.gz -C ${{ github.workspace }}/bin/ pulumi-resource-acme pulumi-tfgen-acme
     - name: Upload artifacts
-      uses: actions/upload-artifact@v4
+      uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
       with:
         name: acme-provider.tar.gz
         path: ${{ github.workspace }}/bin/provider.tar.gz
diff --git a/.github/actions/upload-sdk/action.yml b/.github/actions/upload-sdk/action.yml
index 77d4849..b0dd140 100644
--- a/.github/actions/upload-sdk/action.yml
+++ b/.github/actions/upload-sdk/action.yml
@@ -13,7 +13,7 @@ runs:
       shell: bash
       run: tar -zcf sdk/${{ inputs.language }}.tar.gz -C sdk/${{ inputs.language }} .
     - name: Upload artifacts
-      uses: actions/upload-artifact@v4
+      uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
       with:
         name: ${{ inputs.language  }}-sdk.tar.gz
         path: ${{ github.workspace}}/sdk/${{ inputs.language }}.tar.gz
diff --git a/.github/workflows/build_provider.yml b/.github/workflows/build_provider.yml
index 9c7853b..40e1a2c 100644
--- a/.github/workflows/build_provider.yml
+++ b/.github/workflows/build_provider.yml
@@ -30,28 +30,29 @@ jobs:
             arch: amd64
     steps:
       - name: Checkout Repo
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           persist-credentials: false
       - name: Setup tools
         uses: ./.github/actions/setup-tools
         with:
           tools: pulumictl, go
+      - name: Prepare local workspace before restoring previously built
+        run: make prepare_local_workspace
       - name: Download schema-embed.json
-        uses: actions/download-artifact@v4
+        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
         with:
           # Use a pattern to avoid failing if the artifact doesn't exist
           pattern: schema-embed.*
           # Avoid creating directories for each artifact
           merge-multiple: true
           path: provider/cmd/pulumi-resource-acme/schema-embed.json
-      - name: Prepare for build
-        # This installs plugins and prepares upstream
-        run: make upstream
+      - name: Restore makefile progress
+        run: make --touch provider schema
       - name: Build & package provider
         run: make provider_dist-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
       - name: Upload artifacts
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: pulumi-resource-acme-v${{ inputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz
           path: bin/pulumi-resource-acme-v${{ inputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz
diff --git a/.github/workflows/build_sdk.yml b/.github/workflows/build_sdk.yml
index ae54177..a6407cb 100644
--- a/.github/workflows/build_sdk.yml
+++ b/.github/workflows/build_sdk.yml
@@ -40,11 +40,11 @@ jobs:
         - python
     steps:
       - name: Checkout Repo
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           persist-credentials: false
       - name: Cache examples generation
-        uses: actions/cache@v4
+        uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
         with:
           path: |
             .pulumi/examples-cache
@@ -53,12 +53,14 @@ jobs:
         uses: ./.github/actions/setup-tools
         with:
           tools: pulumictl, pulumicli, ${{ matrix.language }}
+      - name: Prepare local workspace
+        run: make prepare_local_workspace
       - name: Download bin
         uses: ./.github/actions/download-bin
-      - name: Install plugins
-        run: make install_plugins
       - name: Update path
         run: echo "${{ github.workspace }}/bin" >> "$GITHUB_PATH"
+      - name: Restore makefile progress
+        run: make --touch provider schema
       - name: Build SDK
         run: make build_${{ matrix.language }}
       - name: Check worktree clean
diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml
index 1e8c462..5bfa6aa 100644
--- a/.github/workflows/license.yml
+++ b/.github/workflows/license.yml
@@ -30,7 +30,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Repo
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           persist-credentials: false
       - name: Setup tools
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 8f58bec..059766e 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -30,11 +30,11 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Install go
-      uses: actions/setup-go@v5
+      uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5
       with:
         # The versions of golangci-lint and setup-go here cross-depend and need to update together.
         go-version: 1.23
@@ -48,7 +48,7 @@ jobs:
       continue-on-error: true
       run: make upstream
     - name: golangci-lint
-      uses: golangci/golangci-lint-action@v6
+      uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6
       with:
         version: v1.60
         working-directory: provider
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e51fb11..d5af0a7 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -50,16 +50,16 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Free Disk Space (Ubuntu)
-      uses: jlumbroso/free-disk-space@v1.3.1
+      uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
       with:
         tool-cache: false
         swap-storage: false
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Configure AWS Credentials
-      uses: aws-actions/configure-aws-credentials@v4
+      uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
       with:
         aws-access-key-id: ${{ secrets.AWS_CORP_S3_UPLOAD_ACCESS_KEY_ID }}
         aws-region: us-west-2
@@ -137,22 +137,23 @@ jobs:
       PROVIDER_VERSION: ${{ needs.prerequisites.outputs.version }}
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Setup tools
       uses: ./.github/actions/setup-tools
       with:
         tools: pulumictl, pulumicli, ${{ matrix.language }}
+    - name: Prepare local workspace
+      run: make prepare_local_workspace
     - name: Download bin
       uses: ./.github/actions/download-bin
-    - name: Add NuGet source
-      if: matrix.language == 'dotnet'
-      run: dotnet nuget add source ${{ github.workspace }}/nuget
     - name: Download SDK
       uses: ./.github/actions/download-sdk
       with:
         language: ${{ matrix.language }}
+    - name: Restore makefile progress
+      run: make --touch provider schema build_${{ matrix.language }}
     - name: Update path
       run: echo "${{ github.workspace }}/bin" >> "$GITHUB_PATH"
     - name: Install Python deps
diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml
index 07a7a7c..fd4e668 100644
--- a/.github/workflows/prerelease.yml
+++ b/.github/workflows/prerelease.yml
@@ -79,22 +79,23 @@ jobs:
       PROVIDER_VERSION: ${{ needs.prerequisites.outputs.version }}
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Setup tools
       uses: ./.github/actions/setup-tools
       with:
         tools: pulumictl, pulumicli, dotnet, go, nodejs, python
+    - name: Prepare local workspace
+      run: make prepare_local_workspace
     - name: Download bin
       uses: ./.github/actions/download-bin
-    - name: Add NuGet source
-      if: matrix.language == 'dotnet'
-      run: dotnet nuget add source ${{ github.workspace }}/nuget
     - name: Download SDK
       uses: ./.github/actions/download-sdk
       with:
         language: ${{ matrix.language }}
+    - name: Restore makefile progress
+      run: make --touch provider schema build_${{ matrix.language }}
     - name: Update path
       run: echo "${{ github.workspace }}/bin" >> "$GITHUB_PATH"
     - name: Install Python deps
diff --git a/.github/workflows/prerequisites.yml b/.github/workflows/prerequisites.yml
index 36e9c47..61d49b3 100644
--- a/.github/workflows/prerequisites.yml
+++ b/.github/workflows/prerequisites.yml
@@ -43,33 +43,29 @@ jobs:
       version: ${{ steps.provider-version.outputs.version }}
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
-    - uses: pulumi/provider-version-action@v1
+    - uses: pulumi/provider-version-action@0391d47b9b0d865d33dd0a295b1fcf9f7021dd4c # v1.5.3
       id: provider-version
       with:
         set-env: 'PROVIDER_VERSION'
     - name: Cache examples generation
-      uses: actions/cache@v4
+      uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
       with:
         path: |
           .pulumi/examples-cache
         key: ${{ runner.os }}-${{ hashFiles('provider/go.sum') }}
-    - name: Prepare upstream code
-      run: make upstream
     - name: Setup tools
       uses: ./.github/actions/setup-tools
       with:
         tools: go, pulumictl, pulumicli, schema-tools
-    - name: Build schema generator binary
-      run: make tfgen_build_only
-    - name: Install plugins
-      run: make install_plugins
+    - name: Prepare local workspace before restoring previously built files
+      run: make prepare_local_workspace
     - name: Generate schema
-      run: make tfgen_no_deps
+      run: make schema
     - name: Build provider binary
-      run: make provider_no_deps
+      run: make provider
     - name: Unit-test provider code
       run: make test_provider
     - if: inputs.is_pr
@@ -83,7 +79,7 @@ jobs:
         } >> "$GITHUB_ENV"
     - if: inputs.is_pr && inputs.is_automated == false
       name: Comment on PR with Details of Schema Check
-      uses: thollander/actions-comment-pull-request@v2
+      uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # v2.5.0
       with:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         comment_tag: schemaCheck
@@ -97,7 +93,7 @@ jobs:
       uses: ./.github/actions/upload-bin
 
     - name: Upload schema-embed.json
-      uses: actions/upload-artifact@v4
+      uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
       with:
         name: schema-embed.json
         path: provider/cmd/pulumi-resource-acme/schema-embed.json
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 307d3f5..bde97eb 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -46,7 +46,7 @@ jobs:
       if: inputs.skipGoSdk && inputs.isPrerelease == false
       run: echo "Can't skip Go SDK for stable releases. This is likely a bug in the calling workflow." && exit 1
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Setup tools
@@ -56,7 +56,7 @@ jobs:
     - name: Create dist directory
       run: mkdir -p dist
     - name: Download provider assets
-      uses: actions/download-artifact@v4
+      uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
       with:
         pattern: pulumi-resource-acme-v${{ inputs.version }}-*
         path: dist
@@ -79,7 +79,7 @@ jobs:
           echo 'EOF'
         } >> "$GITHUB_OUTPUT"
     - name: Create GH Release
-      uses: softprops/action-gh-release@v2
+      uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2
       if: inputs.isPrerelease == false
       with:
         tag_name: v${{ inputs.version }}
@@ -98,7 +98,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         # Persist credentials so we can push back to the repo
         persist-credentials: true
@@ -107,7 +107,7 @@ jobs:
       with:
         tools: pulumictl, pulumicli, dotnet, go, nodejs, python
     - name: Publish SDKs
-      uses: pulumi/pulumi-package-publisher@v0.0.20
+      uses: pulumi/pulumi-package-publisher@1c0359ba74243cf6651efacfd839c751d8ff87e2 # v0.0.20
       with:
         sdk: all,!java
         version: ${{ inputs.version }}
@@ -139,7 +139,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Clean up release labels
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 1f209a8..732be73 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -24,11 +24,11 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Comment PR
-      uses: thollander/actions-comment-pull-request@v2
+      uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # v2.5.0
       with:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         message: >
diff --git a/.github/workflows/pull-workflow-changes.yml b/.github/workflows/pull-workflow-changes.yml
deleted file mode 100644
index 72994b8..0000000
--- a/.github/workflows/pull-workflow-changes.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: "Pull Workflow Changes"
-
-on:
-  schedule:
-    # 3 AM UTC ~ 8 PM PDT / 7 PM PST every Tuesday. Time chosen to run during off hours.
-    - cron: 0 3 * * * #TUE Temporarily running every day for fast feedback.
-
-permissions:
-  contents: write
-  pull-requests: write
-
-env:
-  GITHUB_TOKEN: ${{ secrets.PULUMI_PROVIDER_AUTOMATION_TOKEN || secrets.PULUMI_BOT_TOKEN || secrets.GITHUB_TOKEN }}
-
-jobs:
-  upgrade_provider:
-    name: pull-workflow-changes
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout Repo
-        uses: actions/checkout@v4
-        with:
-          # Persist credentials so pull-workflow-changes can push a new branch.
-          persist-credentials: true
-      - name: Regenerate the workflow files via https://github.com/pulumi/ci-mgmt
-        run: |
-          make ci-mgmt
-      - name: Create PR (no linked issue)
-        uses: peter-evans/create-pull-request@v3.12.0
-        with:
-          author: pulumi-bot <bot@pulumi.com>
-          base: main
-          body: This pull request was generated automatically by the resync-build workflow
-            in this repository.
-          branch: chore/resync-${{ github.run_id }}
-          commit-message: Regenerate workflows for pulumi-acme
-          committer: pulumi-bot <bot@pulumi.com>
-          labels: impact/no-changelog-required
-          title: Regenerate Github Actions workflows for pulumi-acme
-          token: ${{ env.GITHUB_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 173db15..bada405 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -85,22 +85,23 @@ jobs:
       PROVIDER_VERSION: ${{ needs.prerequisites.outputs.version }}
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Setup tools
       uses: ./.github/actions/setup-tools
       with:
         tools: pulumictl, pulumicli, ${{ matrix.language }}
+    - name: Prepare local workspace
+      run: make prepare_local_workspace
     - name: Download bin
       uses: ./.github/actions/download-bin
-    - name: Add NuGet source
-      if: matrix.language == 'dotnet'
-      run: dotnet nuget add source ${{ github.workspace }}/nuget
     - name: Download SDK
       uses: ./.github/actions/download-sdk
       with:
         language: ${{ matrix.language }}
+    - name: Restore makefile progress
+      run: make --touch provider schema build_${{ matrix.language }}
     - name: Update path
       run: echo "${{ github.workspace }}/bin" >> "$GITHUB_PATH"
     - name: Install Python deps
diff --git a/.github/workflows/resync-build.yml b/.github/workflows/resync-build.yml
index 14b2f0c..e60043f 100644
--- a/.github/workflows/resync-build.yml
+++ b/.github/workflows/resync-build.yml
@@ -25,12 +25,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         # Persist credentials so we can push a new branch.
         persist-credentials: true
     - name: Checkout repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         path: ci-mgmt
         repository: pulumi/ci-mgmt
@@ -65,7 +65,7 @@ jobs:
     - name: Build
       run: make build
     - name: Create PR (no linked issue)
-      uses: peter-evans/create-pull-request@v3.12.0
+      uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
       with:
         author: pulumi-bot <bot@pulumi.com>
         base: main
diff --git a/.github/workflows/run-acceptance-tests.yml b/.github/workflows/run-acceptance-tests.yml
index 8a5f45d..d9de347 100644
--- a/.github/workflows/run-acceptance-tests.yml
+++ b/.github/workflows/run-acceptance-tests.yml
@@ -75,7 +75,7 @@ jobs:
       name: Create URL to the run output
       run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT"
     - name: Update with Result
-      uses: peter-evans/create-or-update-comment@v1
+      uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
       with:
         body: "Please view the PR build: ${{ steps.run-url.outputs.run-url }}"
         issue-number: ${{ github.event.client_payload.github.payload.issue.number }}
@@ -100,7 +100,7 @@ jobs:
     - lint
     runs-on: ubuntu-latest
     steps:
-    - uses: guibranco/github-status-action-v2@0849440ec82c5fa69b2377725b9b7852a3977e76
+    - uses: guibranco/github-status-action-v2@0849440ec82c5fa69b2377725b9b7852a3977e76 # v1.1.13
       with:
         authToken: ${{secrets.GITHUB_TOKEN}}
         # Write an explicit status check called "Sentinel" which will only pass if this code really runs.
@@ -127,13 +127,13 @@ jobs:
       PROVIDER_VERSION: ${{ needs.prerequisites.outputs.version }}
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         ref: ${{ env.PR_COMMIT_SHA }}
         persist-credentials: false
     - name: Checkout p/examples
       if: matrix.testTarget == 'pulumiExamples'
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         repository: pulumi/examples
         path: p-examples
@@ -141,15 +141,16 @@ jobs:
       uses: ./.github/actions/setup-tools
       with:
         tools: pulumictl, pulumicli, ${{ matrix.language }}
+    - name: Prepare local workspace
+      run: make prepare_local_workspace
     - name: Download bin
       uses: ./.github/actions/download-bin
-    - name: Add NuGet source
-      if: matrix.language == 'dotnet'
-      run: dotnet nuget add source ${{ github.workspace }}/nuget
     - name: Download SDK
       uses: ./.github/actions/download-sdk
       with:
         language: ${{ matrix.language }}
+    - name: Restore makefile progress
+      run: make --touch provider schema build_${{ matrix.language }}
     - name: Update path
       run: echo "${{ github.workspace }}/bin" >> "$GITHUB_PATH"
     - name: Install Python deps
diff --git a/.github/workflows/upgrade-bridge.yml b/.github/workflows/upgrade-bridge.yml
index 165ed0b..224fafb 100644
--- a/.github/workflows/upgrade-bridge.yml
+++ b/.github/workflows/upgrade-bridge.yml
@@ -65,7 +65,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Checkout Repo
-      uses: actions/checkout@v4
+      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
       with:
         persist-credentials: false
     - name: Setup tools
@@ -74,7 +74,7 @@ jobs:
         tools: pulumictl, pulumicli, dotnet, go, nodejs, python
     - name: Call upgrade provider action
       if: github.event_name == 'workflow_dispatch'
-      uses: pulumi/pulumi-upgrade-provider-action@v0.0.12
+      uses: pulumi/pulumi-upgrade-provider-action@a1d9f03fbfd923f787427c1d9e99c2356711d483 # v0.0.13
       with:
         kind: ${{ inputs.kind }}
         email: bot@pulumi.com
@@ -87,7 +87,7 @@ jobs:
         pr-title-prefix: ${{ inputs.pr-title-prefix }}
     - name: Call upgrade provider action
       if: github.event_name == 'repository_dispatch'
-      uses: pulumi/pulumi-upgrade-provider-action@v0.0.12
+      uses: pulumi/pulumi-upgrade-provider-action@a1d9f03fbfd923f787427c1d9e99c2356711d483 # v0.0.13
       with:
         kind: ${{ github.event.client_payload.kind || 'bridge' }}
         email: bot@pulumi.com
diff --git a/.github/workflows/upgrade-provider.yml b/.github/workflows/upgrade-provider.yml
index 2ad5981..4c30f13 100644
--- a/.github/workflows/upgrade-provider.yml
+++ b/.github/workflows/upgrade-provider.yml
@@ -37,7 +37,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Repo
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           # Persist credentials so upgrade-provider can push a new branch.
           persist-credentials: true
diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml
index 79fc0f6..56d259c 100644
--- a/.github/workflows/verify-release.yml
+++ b/.github/workflows/verify-release.yml
@@ -69,7 +69,7 @@ jobs:
     runs-on: ${{ matrix.runner }}
     steps:
       - name: Checkout Repo
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           persist-credentials: false
       - name: Setup tools
diff --git a/.gitignore b/.gitignore
index 08e3308..2a14dd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,4 +27,7 @@ provider/**/schema-embed.json
 __pycache__
 venv
 sdk/python/build
-sdk/python/*.egg-info
\ No newline at end of file
+sdk/python/*.egg-info
+
+# Ignore local build tracking directory
+.make
diff --git a/Makefile b/Makefile
index 2d91fc3..1c138e7 100644
--- a/Makefile
+++ b/Makefile
@@ -27,146 +27,237 @@ LDFLAGS_UPSTREAM_VERSION=
 LDFLAGS_EXTRAS=
 LDFLAGS=$(LDFLAGS_PROJ_VERSION) $(LDFLAGS_UPSTREAM_VERSION) $(LDFLAGS_EXTRAS) $(LDFLAGS_STRIP_SYMBOLS)
 
-development: install_plugins provider build_sdks install_sdks
+# Create a `.make` directory for tracking targets which don't generate a single file output. This should be ignored by git.
+# For targets which either don't generate a single file output, or the output file is committed, we use a "sentinel"
+# file within `.make/` to track the staleness of the target and only rebuild when needed. 
+# For each phony target, we create an internal target with the same name, but prefixed with `.make/` where the work is performed.
+# At the end of each internal target we run `@touch $@` to update the file which is the name of the target.
 
-build: install_plugins provider build_sdks install_sdks
-
-build_sdks: build_dotnet build_go build_nodejs build_python 
-
-install_go_sdk:
-
-install_java_sdk:
+# Ensure all directories exist before evaluating targets to avoid issues with `touch` creating directories.
+_ := $(shell mkdir -p .make bin .pulumi/bin)
 
-install_python_sdk:
+# Build the provider and all SDKs and install ready for testing
+build: install_plugins provider build_sdks install_sdks
+# Keep aliases for old targets to ensure backwards compatibility
+development: build
+only_build: build
+# Prepare the workspace for building the provider and SDKs
+# Importantly this is run by CI ahead of restoring the bin directory and resuming SDK builds
+prepare_local_workspace: install_plugins upstream
+# Creates all generated files which need to be committed
+generate: generate_sdks schema
+generate_sdks: generate_dotnet generate_go generate_nodejs generate_python
+build_sdks: build_dotnet build_go build_nodejs build_python
+install_sdks: install_dotnet_sdk install_go_sdk install_nodejs_sdk install_python_sdk
+.PHONY: development only_build build generate generate_sdks build_sdks install_sdks
 
-install_sdks: install_dotnet_sdk install_python_sdk install_nodejs_sdk install_java_sdk
+help:
+	@echo "Usage: make [target]"
+	@echo ""
+	@echo "Main Targets"
+	@echo "  build (default)     Build the provider and all SDKs and install for testing"
+	@echo "  generate            Generate all SDKs, documentation and schema"
+	@echo "  provider            Build the local provider binary"
+	@echo "  lint_provider<.fix> Run the linter on the provider (& optionally fix)"
+	@echo "  test_provider       Run the provider tests"
+	@echo "  test                Run the example tests (must run 'build' first)"
+	@echo "  clean               Clean up generated files"
+	@echo ""
+	@echo "More Precise Targets"
+	@echo "  schema        Generate the schema"
+	@echo "  generate_sdks Generate all SDKs"
+	@echo "  build_sdks    Build all SDKs"
+	@echo "  install_sdks  Install all SDKs"
+	@echo "  provider_dist Build and package the provider for all platforms"
+	@echo ""
+	@echo "Tool Targets"
+	@echo "  ci-mgmt     Re-generate CI configuration from .ci-mgmt.yaml"
+	@echo "  debug_tfgen Start a debug server for tfgen"
+	@echo ""
+	@echo "Internal Targets (automatically run as dependencies of other targets)"
+	@echo "  prepare_local_workspace  Prepare for building"
+	@echo "  install_plugins          Install plugin dependencies"
+	@echo "  upstream                 Initialize the upstream submodule, if present"
+	@echo ""
+	@echo "Language-Specific Targets"
+	@echo "  generate_[language]    Generate the SDK files ready for committing"
+	@echo "  build_[language]       Build the SDK to check correctness"
+	@echo "  install_[language]_sdk Install the SDK ready for testing"
+	@echo ""
+	@echo "  [language] = dotnet go nodejs python"
+	@echo ""
+.PHONY: help
 
-only_build: build
+GEN_PULUMI_HOME := $(WORKING_DIR)/.pulumi
+GEN_PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(GEN_PULUMI_HOME)/examples-cache
+GEN_ENVS := PULUMI_HOME=$(GEN_PULUMI_HOME) PULUMI_CONVERT_EXAMPLES_CACHE_DIR=$(GEN_PULUMI_CONVERT_EXAMPLES_CACHE_DIR) PULUMI_CONVERT=$(PULUMI_CONVERT) PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION=$(PULUMI_CONVERT)
 
-build_dotnet: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-build_dotnet: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-build_dotnet: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
-build_dotnet: upstream
-	PULUMI_CONVERT=$(PULUMI_CONVERT) PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION=$(PULUMI_CONVERT) $(WORKING_DIR)/bin/$(TFGEN) dotnet --out sdk/dotnet/
+generate_dotnet: .make/generate_dotnet
+build_dotnet: .make/build_dotnet
+.make/generate_dotnet: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/generate_dotnet: bin/$(TFGEN)
+	$(GEN_ENVS) $(WORKING_DIR)/bin/$(TFGEN) dotnet --out sdk/dotnet/
 	cd sdk/dotnet/ && \
 		printf "module fake_dotnet_module // Exclude this directory from Go tools\n\ngo 1.17\n" > go.mod && \
-		echo "$(VERSION_GENERIC)" >version.txt && \
-		dotnet build
-
-build_go: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-build_go: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-build_go: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
-build_go: upstream
-	PULUMI_CONVERT=$(PULUMI_CONVERT) PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION=$(PULUMI_CONVERT) $(WORKING_DIR)/bin/$(TFGEN) go --out sdk/go/
+		echo "$(VERSION_GENERIC)" >version.txt
+	@touch $@
+.make/build_dotnet: .make/generate_dotnet
+	cd sdk/dotnet/ && dotnet build
+	@touch $@
+.PHONY: generate_dotnet build_dotnet
+
+generate_go: .make/generate_go
+build_go: .make/build_go
+.make/generate_go: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/generate_go: bin/$(TFGEN)
+	$(GEN_ENVS) $(WORKING_DIR)/bin/$(TFGEN) go --out sdk/go/
+	@touch $@
+.make/build_go: .make/generate_go
 	cd sdk && go list "$$(grep -e "^module" go.mod | cut -d ' ' -f 2)/go/..." | xargs -I {} bash -c 'go build {} && go clean -i {}'
-
-build_java: PACKAGE_VERSION := $(VERSION_GENERIC)
-build_java: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-build_java: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-build_java: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
-build_java: bin/pulumi-java-gen upstream
-	$(WORKING_DIR)/bin/$(JAVA_GEN) generate --schema provider/cmd/$(PROVIDER)/schema.json --out sdk/java  --build gradle-nexus
+	@touch $@
+.PHONY: generate_go build_go
+
+generate_java: .make/generate_java
+build_java: .make/build_java
+.make/generate_java: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/generate_java: PACKAGE_VERSION := $(VERSION_GENERIC)
+.make/generate_java: bin/pulumi-java-gen .make/schema
+	PULUMI_HOME=$(GEN_PULUMI_HOME) PULUMI_CONVERT_EXAMPLES_CACHE_DIR=$(GEN_PULUMI_CONVERT_EXAMPLES_CACHE_DIR) bin/$(JAVA_GEN) generate --schema provider/cmd/$(PROVIDER)/schema.json --out sdk/java  --build gradle-nexus
+	printf "module fake_java_module // Exclude this directory from Go tools\n\ngo 1.17\n" > sdk/java/go.mod
+	@touch $@
+.make/build_java: PACKAGE_VERSION := $(VERSION_GENERIC)
+.make/build_java: .make/generate_java
 	cd sdk/java/ && \
-		printf "module fake_java_module // Exclude this directory from Go tools\n\ngo 1.17\n" > go.mod && \
 		gradle --console=plain build && \
 		gradle --console=plain javadoc
-
-build_nodejs: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-build_nodejs: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-build_nodejs: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
-build_nodejs: upstream
-	PULUMI_CONVERT=$(PULUMI_CONVERT) PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION=$(PULUMI_CONVERT) $(WORKING_DIR)/bin/$(TFGEN) nodejs --out sdk/nodejs/
+	@touch $@
+.PHONY: generate_java build_java
+
+generate_nodejs: .make/generate_nodejs
+build_nodejs: .make/build_nodejs
+.make/generate_nodejs: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/generate_nodejs: bin/$(TFGEN)
+	$(GEN_ENVS) $(WORKING_DIR)/bin/$(TFGEN) nodejs --out sdk/nodejs/
+	printf "module fake_nodejs_module // Exclude this directory from Go tools\n\ngo 1.17\n" > sdk/nodejs/go.mod
+	@touch $@
+.make/build_nodejs: .make/generate_nodejs
 	cd sdk/nodejs/ && \
-		printf "module fake_nodejs_module // Exclude this directory from Go tools\n\ngo 1.17\n" > go.mod && \
 		yarn install && \
 		yarn run tsc && \
 		cp ../../README.md ../../LICENSE* package.json yarn.lock ./bin/
-
-build_python: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-build_python: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-build_python: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
-build_python: upstream
-	rm -rf sdk/python/
-	PULUMI_CONVERT=$(PULUMI_CONVERT) PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION=$(PULUMI_CONVERT) $(WORKING_DIR)/bin/$(TFGEN) python --out sdk/python/
+	@touch $@
+.PHONY: generate_nodejs build_nodejs
+
+generate_python: .make/generate_python
+build_python: .make/build_python
+.make/generate_python: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/generate_python: bin/$(TFGEN)
+	$(GEN_ENVS) $(WORKING_DIR)/bin/$(TFGEN) python --out sdk/python/
+	printf "module fake_python_module // Exclude this directory from Go tools\n\ngo 1.17\n" > sdk/python/go.mod
+	cp README.md sdk/python/
+	@touch $@
+.make/build_python: .make/generate_python
 	cd sdk/python/ && \
-		printf "module fake_python_module // Exclude this directory from Go tools\n\ngo 1.17\n" > go.mod && \
-		cp ../../README.md . && \
 		rm -rf ./bin/ ../python.bin/ && cp -R . ../python.bin && mv ../python.bin ./bin && \
 		rm ./bin/go.mod && \
 		python3 -m venv venv && \
 		./venv/bin/python -m pip install build==1.2.1 && \
 		cd ./bin && \
 		../venv/bin/python -m build .
+	@touch $@
+.PHONY: generate_python build_python
 
 clean:
 	rm -rf sdk/{dotnet,nodejs,go,python}
-
-cleanup:
-	rm -r $(WORKING_DIR)/bin
-	rm -f provider/cmd/$(PROVIDER)/schema.go
-
-help:
-	@grep '^[^.#]\+:\s\+.*#' Makefile | \
-	sed "s/\(.\+\):\s*\(.*\) #\s*\(.*\)/`printf "\033[93m"`\1`printf "\033[0m"`	\3 [\2]/" | \
-	expand -t20
-
-install_dotnet_sdk:
-	mkdir -p $(WORKING_DIR)/nuget
-	find . -name '*.nupkg' -print -exec cp -p {} $(WORKING_DIR)/nuget \;
-
-install_nodejs_sdk:
+	rm -rf bin/*
+	rm -rf .make/*
+	if dotnet nuget list source | grep "$(WORKING_DIR)/nuget"; then \
+		dotnet nuget remove source "$(WORKING_DIR)/nuget" \
+	; fi
+.PHONY: clean
+
+install_dotnet_sdk: .make/install_dotnet_sdk
+.make/install_dotnet_sdk: .make/build_dotnet
+	mkdir -p nuget
+	find sdk/dotnet/bin -name '*.nupkg' -print -exec cp -p "{}" ${WORKING_DIR}/nuget \;
+	if ! dotnet nuget list source | grep "${WORKING_DIR}/nuget"; then \
+		dotnet nuget add source "${WORKING_DIR}/nuget" --name "${WORKING_DIR}/nuget" \
+	; fi
+	@touch $@
+install_go_sdk:
+install_java_sdk:
+install_nodejs_sdk: .make/install_nodejs_sdk
+.make/install_nodejs_sdk: .make/build_nodejs
 	yarn link --cwd $(WORKING_DIR)/sdk/nodejs/bin
+	@touch $@
+install_python_sdk:
+.PHONY: install_dotnet_sdk install_go_sdk install_java_sdk install_nodejs_sdk install_python_sdk
 
-install_plugins: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-install_plugins: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-install_plugins: .pulumi/bin/pulumi
+# Install Pulumi plugins required for TFGen to resolve references
+install_plugins: .make/install_plugins
+.make/install_plugins: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
+.make/install_plugins: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/install_plugins: .pulumi/bin/pulumi
 	.pulumi/bin/pulumi plugin install converter terraform 1.0.19
+	@touch $@
+.PHONY: install_plugins
 
 lint_provider: provider
 	cd provider && golangci-lint run --path-prefix provider -c ../.golangci.yml
-
 # `lint_provider.fix` is a utility target meant to be run manually
 # that will run the linter and fix errors when possible.
 lint_provider.fix:
 	cd provider && golangci-lint run --path-prefix provider -c ../.golangci.yml --fix
+.PHONY: lint_provider lint_provider.fix
 
 # `make provider_no_deps` builds the provider binary directly, without ensuring that
 # `cmd/pulumi-resource-acme/schema.json` is valid and up to date.
 # To create a release ready binary, you should use `make provider`.
+build_provider_cmd = cd provider && go build $(PULUMI_PROVIDER_BUILD_PARALLELISM) -o $(WORKING_DIR)/bin/$(PROVIDER) -ldflags "$(LDFLAGS)" $(PROJECT)/$(PROVIDER_PATH)/cmd/$(PROVIDER)
+provider: bin/$(PROVIDER)
 provider_no_deps:
-	(cd provider && go build $(PULUMI_PROVIDER_BUILD_PARALLELISM) -o $(WORKING_DIR)/bin/$(PROVIDER) -ldflags "$(LDFLAGS)" $(PROJECT)/$(PROVIDER_PATH)/cmd/$(PROVIDER))
-
-provider: tfgen provider_no_deps
+	$(call build_provider_cmd)
+bin/$(PROVIDER): .make/schema
+	$(call build_provider_cmd)
+.PHONY: provider provider_no_deps
 
 test: export PATH := $(WORKING_DIR)/bin:$(PATH)
 test:
 	cd examples && go test -v -tags=all -parallel $(TESTPARALLELISM) -timeout 2h
+.PHONY: test
 
 test_provider:
-	@echo ""
-	@echo "== test_provider ==================================================================="
-	@echo ""
 	cd provider && go test -v -short ./... -parallel $(TESTPARALLELISM)
-
-tfgen: install_plugins upstream tfgen_no_deps
-
-tfgen_no_deps: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
-tfgen_no_deps: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
-tfgen_no_deps: export PULUMI_CONVERT := $(PULUMI_CONVERT)
-tfgen_no_deps: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
-tfgen_no_deps: export PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION := $(PULUMI_CONVERT)
-tfgen_no_deps: export PULUMI_MISSING_DOCS_ERROR := $(PULUMI_MISSING_DOCS_ERROR)
-tfgen_no_deps: tfgen_build_only
+.PHONY: test_provider
+
+tfgen: schema
+schema: .make/schema 
+# This does actually have dependencies, but we're keeping it around for backwards compatibility for now
+tfgen_no_deps: .make/schema
+.make/schema: export PULUMI_HOME := $(WORKING_DIR)/.pulumi
+.make/schema: export PATH := $(WORKING_DIR)/.pulumi/bin:$(PATH)
+.make/schema: export PULUMI_CONVERT := $(PULUMI_CONVERT)
+.make/schema: export PULUMI_CONVERT_EXAMPLES_CACHE_DIR := $(WORKING_DIR)/.pulumi/examples-cache
+.make/schema: export PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION := $(PULUMI_CONVERT)
+.make/schema: export PULUMI_MISSING_DOCS_ERROR := $(PULUMI_MISSING_DOCS_ERROR)
+.make/schema: bin/$(TFGEN) .make/install_plugins .make/upstream
 	$(WORKING_DIR)/bin/$(TFGEN) schema --out provider/cmd/$(PROVIDER)
 	(cd provider && VERSION=$(VERSION_GENERIC) go generate cmd/$(PROVIDER)/main.go)
-
-tfgen_build_only:
+	@touch $@
+tfgen_build_only: bin/$(TFGEN)
+bin/$(TFGEN): provider/*.go provider/go.* .make/upstream
 	(cd provider && go build $(PULUMI_PROVIDER_BUILD_PARALLELISM) -o $(WORKING_DIR)/bin/$(TFGEN) -ldflags "$(LDFLAGS_PROJ_VERSION) $(LDFLAGS_EXTRAS)" $(PROJECT)/$(PROVIDER_PATH)/cmd/$(TFGEN))
+.PHONY: tfgen schema tfgen_no_deps tfgen_build_only
 
-upstream:
+# Apply patches to the upstream submodule, if it exists
+upstream: .make/upstream
+# Re-run if the upstream commit or the patches change
+.make/upstream: $(wildcard patches/*) $(wildcard .git/modules/upstream/HEAD)
 ifneq ("$(wildcard upstream)","")
 	./upstream.sh init
 endif
+	@touch $@
+.PHONY: upstream
 
 bin/pulumi-java-gen: .pulumi-java-gen.version
 	pulumictl download-binary -n pulumi-language-java -v v$(shell cat .pulumi-java-gen.version) -r pulumi/pulumi-java
@@ -178,6 +269,7 @@ bin/pulumi-java-gen: .pulumi-java-gen.version
 #
 ci-mgmt: .ci-mgmt.yaml
 	go run github.com/pulumi/ci-mgmt/provider-ci@master generate
+.PHONY: ci-mgmt
 
 # Because some codegen depends on the version of the CLI used, we install a local CLI
 # version pinned to the same version as `provider/go.mod`.
@@ -188,6 +280,7 @@ ci-mgmt: .ci-mgmt.yaml
 .pulumi/bin/pulumi: .pulumi/version
 	@if [ -x .pulumi/bin/pulumi ] && [ "v$$(cat .pulumi/version)" = "$$(.pulumi/bin/pulumi version)" ]; then \
 		echo "pulumi/bin/pulumi version: v$$(cat .pulumi/version)"; \
+		touch $@; \
 	else \
 		curl -fsSL https://get.pulumi.com | \
 			HOME=$(WORKING_DIR) sh -s -- --version "$$(cat .pulumi/version)"; \
@@ -195,14 +288,12 @@ ci-mgmt: .ci-mgmt.yaml
 
 # Compute the version of Pulumi to use by inspecting the Go dependencies of the provider.
 .pulumi/version: provider/go.mod
-	@mkdir -p .pulumi
-	@cd provider && go list -f "{{slice .Version 1}}" -m github.com/pulumi/pulumi/pkg/v3 | tee ../$@
+	cd provider && go list -f "{{slice .Version 1}}" -m github.com/pulumi/pulumi/pkg/v3 | tee ../$@
 
 # Start debug server for tfgen
 debug_tfgen:
 	dlv  --listen=:2345 --headless=true --api-version=2  exec $(WORKING_DIR)/bin/$(TFGEN) -- schema --out provider/cmd/$(PROVIDER)
-
-.PHONY: development build build_sdks install_go_sdk install_java_sdk install_python_sdk install_sdks only_build build_dotnet build_go build_java build_nodejs build_python clean cleanup help install_dotnet_sdk install_nodejs_sdk install_plugins lint_provider provider provider_no_deps test tfgen upstream ci-mgmt test_provider debug_tfgen tfgen_build_only
+.PHONY: debug_tfgen
 
 # Provider cross-platform build & packaging