Repository: pulumi/actions
Pull request #661 (2022-06-21 19:32:34)

Add `pulumi-version` option
This PR adds the `pulumi-version` option allowing pinning the CLI version that get's installed while running the action.
If the `pulumi-version` option is not set it will default to `^3` as this was the previously hardcoded value.

Moon1706: @lomholdt Hi!
As I know, additional functionality really slooooowly appended to this Action. I try to add configMap 2 month. So, if it's critical for you, please, use [my fork](https://github.com/terraform-gitlab-modules/actions) to add new features. I hope in the future it will be an append to the official action.

RobbieMcKinstry: Hi @lomholdt , thank you for your contribution! As I recall, we have a similar parameter in the Azure DevOps Pipeline CI integration, so adding the Pulumi version sounds like it makes sense here too.
RobbieMcKinstry: Also, it looks like there was some discussion on https://github.com/pulumi/actions/pull/661 about generating a warning if the CLI version number is incompatible with the automation API version number.
@lomholdt Would you add a warning if the version specified is beneath `v3`?
jonas-lomholdt: > Hi @lomholdt , thank you for your contribution! As I recall, we have a similar parameter in the Azure DevOps Pipeline CI integration, so adding the Pulumi version sounds like it makes sense here too.
> 
> 
> 
> I'm seeing this branch has some conflicts. Would you be able to rebase? 

Sure, I will fix that. Thanks 👍🏼
jonas-lomholdt: > Also, it looks like there was some discussion on https://github.com/pulumi/actions/pull/661 about generating a warning if the CLI version number is incompatible with the automation API version number.
> 
> @lomholdt Would you add a warning if the version specified is beneath `v3`? Thank you very much! :D
> 
> Please re-request my review when you've made these changes. I'm going to be away from my computer for a few days for the holiday, but I can take a look when I get back. :) 

Sure, that makes sense. I will give it a shot. Thanks. Have a nice holiday 👍🏼
RobbieMcKinstry: Would you also remove the `dist` file updates from your PR? I believe the TypeScript files are automatically recompiled by a GitHub Action once a commit lands on `master/main`.
lomholdt: > Hey @jonas-lomholdt, just following up on this. Let me know if you need any assistance with the remaining action items. :)

Hey, sorry I have been taking some vacation. I fixed the conflicts and need to warn if the version is less than 3. I would probably need to parse the input string somehow to get a semver representation of it that I can compare. Did you have any specific way in mind? low-fi by string splitting or pulling in a lib that does that? Thanks! 
RobbieMcKinstry: Hi there @lomholdt I hope you had a lovely vacation! It's well-deserved, I'm sure!
I would personally prefer using a library. I don't have a recommendation. The top Google result [looks decent](https://www.npmjs.com/package/semver-parser).
lomholdt: > Hi there @lomholdt I hope you had a lovely vacation! It's well-deserved, I'm sure! I would personally prefer using a library. I don't have a recommendation. The top Google result [looks decent](https://www.npmjs.com/package/semver-parser).

Hey @RobbieMcKinstry. I noticed there's already a `semver` package installed, and I think that will do the trick. I added a warning if the parsed semver is less than `3.0.0`. You probably have an opinion about what the message should say, but I just put something in there for now. Can you give it another look? Thanks! 
lomholdt: > LGTM! Thanks very much for your contribution!

Awesome! Thanks 😃 No problem, and sorry for the delay. 
RobbieMcKinstry: No need to apologize at all! I don't consider it a delay; vacations are important!

Patch:
diff --git a/.gitignore b/.gitignore
index 7d02a0a..e38ff10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,7 @@ build/
 
 # Misc
 .DS_Store
+
+# .NET
+**/obj
+**/bin
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e5d3db..2c6a628 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@
 
 - feat: add configuration of Pulumi stack by `config-map` field
 
+- enhancement: Add `pulumi-version` option to allow pinning the version of the
+  CLI [PR](https://github.com/pulumi/actions/pull/661) fixes
+  [#437 ](https://github.com/pulumi/actions/issues/437)
+
 ---
 
 ## 3.18.1 (2022-07-07)
@@ -25,7 +29,7 @@
 - fix: update PR comments correctly when `edit-pr-comment` is true (fixes
   [#633](https://github.com/pulumi/actions/issues/633))
 
-- bump to runtime to node 16
+- bump runtime to node 16
 
 ## 3.17.0 (2022-05-25)
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5bdae4e..b9d766d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,10 +1,13 @@
 # Contributing
 
-We :heart: PRs! If you have something you'd like to contribute, please open an issue first. We're happy to talk with you about your pull request before you get started.
+We :heart: PRs! If you have something you'd like to contribute, please open an
+issue first. We're happy to talk with you about your pull request before you get
+started.
 
 ## Release Process
 
-This section details the steps necessary to cut a new release. Suppose the latest release is `v3.18.1`, and you wish to cut `v.3.19.0`.
+This section details the steps necessary to cut a new release. Suppose the
+latest release is `v3.18.1`, and you wish to cut `v.3.19.0`.
 
 1. Checkout the default branch.
 
@@ -12,14 +15,17 @@ This section details the steps necessary to cut a new release. Suppose the lates
    $ git checkout master
    ```
 
-2. Open up `CHANGELOG.md`. Create a new h2 with the release version and the date of the release. Move the release notes from the `HEAD` section under the new heading, and add a note in the `HEAD` section indicating that it is currently empty. 
+2. Open up `CHANGELOG.md`. Create a new h2 with the release version and the date
+   of the release. Move the release notes from the `HEAD` section under the new
+   heading, and add a note in the `HEAD` section indicating that it is currently
+   empty.
 
    ```markdown
    # CHANGELOG
 
    ## HEAD (Unreleased)
 
-   __(none)__
+   **(none)**
 
    ---
 
@@ -29,21 +35,28 @@ This section details the steps necessary to cut a new release. Suppose the lates
    - bug: Fix XYZ
 
    ## 3.18.1 (2022-07-10)
+
    ...
    ```
 
-3. Commit your changes to  `CHANGELOG.md`, and open a PR. Once your changes have been approved and status checks have passed, merge your PR into the default branch, `master`. 
+3. Commit your changes to `CHANGELOG.md`, and open a PR. Once your changes have
+   been approved and status checks have passed, merge your PR into the default
+   branch, `master`.
 
 4. Wait for status checks on the default branch to pass.
 
-5. Navigate to the [Release page](https://github.com/pulumi/actions/releases) and select `Draft a new release`.
+5. Navigate to the [Release page](https://github.com/pulumi/actions/releases)
+   and select `Draft a new release`.
 
-6. Make sure `Publish this Action to GitHub Marketplace` is checked (it should be checked by default).
+6. Make sure `Publish this Action to GitHub Marketplace` is checked (it should
+   be checked by default).
 
-7. Under the `Choose a tag` dropdown, enter in the name of your new tag, which should the release name, `v3.19.0`.
+7. Under the `Choose a tag` dropdown, enter in the name of your new tag, which
+   should the release name, `v3.19.0`.
 
 8. Under `Release Title`, enter the name of your release, v3.19.0
 
-9. Press the button  `Geneate release notes`. Replace the section `What's New` with the changes you added to `CHANGELOG.md`.
+9. Press the button `Geneate release notes`. Replace the section `What's New`
+   with the changes you added to `CHANGELOG.md`.
 
 10. Press the `Publish release` button.
diff --git a/README.md b/README.md
index 7e9b786..7710292 100644
--- a/README.md
+++ b/README.md
@@ -64,23 +64,24 @@ The action can be configured with the following arguments:
   `awskms`, `azurekeyvault`, `gcpkms`, `hashivault`. e.g.
   `gcpkms://projects//locations/us-west1/keyRings/acmecorpsec/cryptoKeys/payroll `
 
-- `color` - (optional) Colorize output. Choices are: always, never, raw, auto (default "auto").
+- `color` - (optional) Colorize output. Choices are: always, never, raw, auto
+  (default "auto").
 
 ### Extra options
 
 - `parallel` - (optional) Allow P resource operations to run in parallel at once
   (1 for no parallelism). Defaults to unbounded.
 
-- `message` - (optional) Optional message to associate with the update operation.
+- `message` - (optional) Optional message to associate with the update
+  operation.
 
 - `expect-no-changes` - (optional) Return an error if any changes occur during
   this update.
 
 - `edit-pr-comment` - (optional) Edit previous PR comment instead of posting new
-  one.  
-  **PLEASE NOTE:** that as of 3.2.0 of the Action, this now defaults to `true`.
-  This is in an effort to reduce verbosity - if you want to have a comment per
-  PR run, please ensure that you set this to `false`.
+  one. **PLEASE NOTE:** that as of 3.2.0 of the Action, this now defaults to
+  `true`. This is in an effort to reduce verbosity - if you want to have a
+  comment per PR run, please ensure that you set this to `false`.
 
 - `diff` - (optional) Display operation as a rich diff showing the overall
   change.
@@ -89,18 +90,22 @@ The action can be configured with the following arguments:
   specified one per line (example: `<value | string>,...`).
 
 - `target` - (optional) Specify a single resource URN to update. Other resources
-  will not be updated. Multiple resources can be specified one per line (example: `<value | string>,...`).
+  will not be updated. Multiple resources can be specified one per line
+  (example: `<value | string>,...`).
 
 - `target-dependents` - (optional) Allows updating of dependent targets
   discovered but not specified in target.
 
-- `config-map` - (optional) Configuration of the stack. Format Yaml string: `{<key | string>: {value: <value | string>, secret: <is_secret | boolean> },}`.
+- `config-map` - (optional) Configuration of the stack. Format Yaml string:
+  `{<key | string>: {value: <value | string>, secret: <is_secret | boolean> },}`.
 
 - `upsert` - (optional) Allows the creation of the specified stack if it
-  currently doesn't exist.  
-  **PLEASE NOTE:** This will create a `Pulumi.<stack-name>.yaml` file that you
-  will need to add back to source control as part of the action if you wish to
-  perform any further tasks with that stack.
+  currently doesn't exist. **PLEASE NOTE:** This will create a
+  `Pulumi.<stack-name>.yaml` file that you will need to add back to source
+  control as part of the action if you wish to perform any further tasks with
+  that stack.
+- `pulumi-version` - (optional) Install a specific version of the Pulumi CLI.
+  Defaults to "^3"
 
 By default, this action will try to authenticate Pulumi with the
 [Pulumi SaaS](https://app.pulumi.com/). If you have not specified a
@@ -212,6 +217,10 @@ with:
 - run: pip install -r requirements
   working-directory: infra
 ```
+
 ## Release Cadence
 
-As of `v3.18`, we are intending to move to a monthly cadence for minor releases. Minor releases will be published around the beginning of the month. We may cut a patch release instead, if the changes are small enough not to warrant a minor release. We will also cut patch releases periodically as needed to address bugs.
+As of `v3.18`, we are intending to move to a monthly cadence for minor releases.
+Minor releases will be published around the beginning of the month. We may cut a
+patch release instead, if the changes are small enough not to warrant a minor
+release. We will also cut patch releases periodically as needed to address bugs.
diff --git a/action.yml b/action.yml
index 9480235..2249d90 100644
--- a/action.yml
+++ b/action.yml
@@ -77,6 +77,10 @@ inputs:
     description: 'Edit previous PR comment instead of posting new one'
     required: false
     default: 'true'
+  pulumi-version:
+    description: 'Install a specific version of the Pulumi CLI'
+    required: false
+    default: '^3'
   color:
     description: 'Colorize output. Choices are: always, never, raw, auto'
     required: false
diff --git a/package.json b/package.json
index 4b69748..e3ca10b 100644
--- a/package.json
+++ b/package.json
@@ -53,8 +53,8 @@
     "got": "^11.8.3",
     "runtypes": "^6.5.1",
     "semver": "^7.3.7",
+    "ts-invariant": "^0.10.3",
     "typescript": "~4.1.3",
-    "yaml": "~2.0.0",
-    "ts-invariant": "^0.10.3"
+    "yaml": "~2.0.0"
   }
 }
diff --git a/src/config.ts b/src/config.ts
index 5714929..0f5ca33 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -25,6 +25,7 @@ export const options = rt.Partial({
   targetDependents: rt.Boolean,
   editCommentOnPr: rt.Boolean,
   userAgent: rt.Literal('pulumi/actions@v3'),
+  pulumiVersion: rt.String,
 });
 
 export const config = rt
@@ -77,6 +78,7 @@ export async function makeConfig(): Promise<Config> {
       policyPackConfigs: parseArray(getInput('policyPackConfigs')),
       editCommentOnPr: parseBoolean(getInput('edit-pr-comment')),
       userAgent: 'pulumi/actions@v3',
+      pulumiVersion: getInput('pulumi-version') || "^3",
       color: getInput('color'),
     },
   });
diff --git a/src/libs/pulumi-cli.ts b/src/libs/pulumi-cli.ts
index 9404c04..a9a9696 100644
--- a/src/libs/pulumi-cli.ts
+++ b/src/libs/pulumi-cli.ts
@@ -3,6 +3,7 @@ import * as path from 'path';
 import * as core from '@actions/core';
 import * as io from '@actions/io';
 import * as tc from '@actions/tool-cache';
+import * as semver from 'semver'
 import * as exec from './exec';
 import { getVersionObject } from './libs/get-version';
 
@@ -42,8 +43,15 @@ export async function downloadCli(range: string): Promise<void> {
   core.info(`Configured range: ${range}`);
 
   const { version, downloads } = await getVersionObject(range);
+
   core.info(`Matched version: ${version}`);
 
+  const isUnsupportedVersion = semver.lt(version, '3.0.0');
+
+  if (isUnsupportedVersion) {
+    core.warning(`Using Pulumi CLI version less than 3.0.0 may cause unexpected behavior. Please consider migrating to 3.0.0 or higher. You can find our migration guide at https://www.pulumi.com/docs/get-started/install/migrating-3.0/`);
+  }
+
   const destination = path.join(os.homedir(), '.pulumi');
   core.info(`Install destination is ${destination}`)
 
diff --git a/src/main.ts b/src/main.ts
index e55d343..2e4316c 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -6,20 +6,18 @@ import {
   LocalWorkspace,
   LocalWorkspaceOptions,
 } from '@pulumi/pulumi/automation';
-import YAML from 'yaml';
 import invariant from 'ts-invariant';
+import YAML from 'yaml';
 import { Commands, makeConfig } from './config';
 import { environmentVariables } from './libs/envs';
 import { handlePullRequestMessage } from './libs/pr';
 import * as pulumiCli from './libs/pulumi-cli';
 
-const pulumiVersion = '^3';
-
 const main = async () => {
   const config = await makeConfig();
   core.debug('Configuration is loaded');
 
-  await pulumiCli.downloadCli(pulumiVersion);
+  await pulumiCli.downloadCli(config.options.pulumiVersion);
 
   if (environmentVariables.PULUMI_ACCESS_TOKEN !== '') {
     core.debug(`Logging into Pulumi`);


Test patch:
diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts
index e29c84f..20355ab 100644
--- a/src/__tests__/config.test.ts
+++ b/src/__tests__/config.test.ts
@@ -4,7 +4,7 @@ const defaultConfig: Record<string, string> = {
   'work-dir': './',
   'cloud-url': 'file://~',
   'github-token': 'n/a',
-  'pulumi-version': 'latest',
+  'pulumi-version': '^3',
 };
 
 describe('config.ts', () => {
@@ -46,6 +46,7 @@ describe('config.ts', () => {
           "parallel": undefined,
           "policyPackConfigs": undefined,
           "policyPacks": undefined,
+          "pulumiVersion": "^3",
           "replace": undefined,
           "target": undefined,
           "targetDependents": undefined,
@@ -108,6 +109,7 @@ describe('config.ts', () => {
           "parallel": undefined,
           "policyPackConfigs": undefined,
           "policyPacks": undefined,
+          "pulumiVersion": "^3",
           "replace": undefined,
           "target": undefined,
           "targetDependents": undefined,
@@ -162,6 +164,7 @@ describe('config.ts', () => {
           "parallel": undefined,
           "policyPackConfigs": undefined,
           "policyPacks": undefined,
+          "pulumiVersion": "^3",
           "replace": undefined,
           "target": undefined,
           "targetDependents": undefined,