Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add plugins installation #812

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ on: # rebuild any PRs and main branch changes
- 'CHANGELOG.md'
- 'README.md'

env:
TEST_PLUGIN_NAME: "time"
TEST_PLUGIN_VERSION: "0.0.9"
TEST_PLUGIN_SERVER: "https://github.com/pulumiverse/pulumi-time/releases/download/v0.0.9"

jobs:
build-test: # make sure build/ci work properly
runs-on: ubuntu-latest
Expand Down Expand Up @@ -55,4 +60,8 @@ jobs:
upsert: true
work-dir: .github/test-stacks/golang
config-map: "{name: {value: test, secret: false}}"
plugins: "[{name: ${{ env.TEST_PLUGIN_NAME }}, version: ${{ env.TEST_PLUGIN_VERSION }}, server: ${{ env.TEST_PLUGIN_SERVER }}}]"
- run: echo 'The random string is `${{ steps.pulumi.outputs.name }}`'
- run: |
pulumi plugin ls | grep ${{ env.TEST_PLUGIN_NAME }} | grep ${{ env.TEST_PLUGIN_VERSION }}
exit $?
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# CHANGELOG

- feat: Add deletion of stack after destroy (remove flag)
- feat: add plugins installation

--

Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ The action can be configured with the following arguments:
values are `up` (update), `refresh`, `destroy` and `preview`.

- `stack-name` (required) - The name of the stack that Pulumi will be operating
on. Use the fully quaified org-name/stack-name when operating on a stack outside
of your individual account.
on. Use the fully quaified org-name/stack-name when operating on a stack
outside of your individual account.

- `work-dir` (optional) - The location of your Pulumi files. Defaults to `./`.

Expand All @@ -63,7 +63,7 @@ The action can be configured with the following arguments:
- `secrets-provider` - (optional) The type of the provider that should be used
to encrypt and decrypt secrets. Possible choices: `default`, `passphrase`,
`awskms`, `azurekeyvault`, `gcpkms`, `hashivault`. e.g.
`gcpkms://projects//locations/us-west1/keyRings/acmecorpsec/cryptoKeys/payroll `
`gcpkms://projects//locations/us-west1/keyRings/acmecorpsec/cryptoKeys/payroll`

- `color` - (optional) Colorize output. Choices are: always, never, raw, auto
(default "auto").
Expand Down Expand Up @@ -100,13 +100,16 @@ The action can be configured with the following arguments:
- `config-map` - (optional) Configuration of the stack. Format Yaml string:
`{<key | string>: {value: <value | string>, secret: <is_secret | boolean> },}`.

- `plugins` - (optional) Installation Pulumi plugins. Format Yaml string:
`[{name: <string>, version: <string>, kind?: <undefined | string>, server?: <undefined | string>}, ...]`.

- `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.
- `remove` - (optional) Removes the target stack if all resources are
destroyed. Used only with `destroy` command.
- `remove` - (optional) Removes the target stack if all resources are destroyed.
Used only with `destroy` command.
- `pulumi-version` - (optional) Install a specific version of the Pulumi CLI.
Defaults to "^3"

Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ inputs:
description: 'Config to use during the operations'
required: false
default: ''
plugins:
description: 'Plugins which will install'
required: false
default: '[]'
expect-no-changes:
description: 'Return an error if any changes occur during this update'
required: false
Expand Down
3 changes: 3 additions & 0 deletions src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ describe('config.ts', () => {
"targetDependents": undefined,
"userAgent": "pulumi/actions@v3",
},
"plugins": Array [],
"refresh": undefined,
"remove": undefined,
"secretsProvider": undefined,
Expand Down Expand Up @@ -118,6 +119,7 @@ describe('config.ts', () => {
"targetDependents": undefined,
"userAgent": "pulumi/actions@v3",
},
"plugins": Array [],
"refresh": undefined,
"remove": undefined,
"secretsProvider": undefined,
Expand Down Expand Up @@ -175,6 +177,7 @@ describe('config.ts', () => {
"targetDependents": undefined,
"userAgent": "pulumi/actions@v3",
},
"plugins": Array [],
"refresh": undefined,
"remove": undefined,
"secretsProvider": undefined,
Expand Down
15 changes: 13 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getInput } from '@actions/core';
import { context } from '@actions/github';
import * as rt from 'runtypes';
import { parseArray, parseBoolean, parseNumber } from './libs/utils';
import { parseArray, parseBoolean, parseNumber, parsePlugins } from './libs/utils';

export const command = rt.Union(
rt.Literal('up'),
Expand All @@ -10,9 +10,18 @@ export const command = rt.Union(
rt.Literal('destroy'),
rt.Literal('preview'),
);

export type Commands = rt.Static<typeof command>;

const plugin = rt.Record({
name: rt.String,
version: rt.String,
}).And(rt.Partial({
server: rt.String,
kind: rt.String
}));
export type Plugin = rt.Static<typeof plugin>;
export type Plugins = Plugin[];

export const options = rt.Partial({
parallel: rt.Number,
message: rt.String,
Expand Down Expand Up @@ -48,6 +57,7 @@ export const config = rt
upsert: rt.Boolean,
remove: rt.Boolean,
refresh: rt.Boolean,
plugins: rt.Array(plugin),
secretsProvider: rt.String,
commentOnPrNumber: rt.Number,
}),
Expand All @@ -69,6 +79,7 @@ export async function makeConfig(): Promise<Config> {
remove: parseBoolean(getInput('remove')),
refresh: parseBoolean(getInput('refresh')),
configMap: getInput('config-map'),
plugins: parsePlugins(getInput('plugins')),
isPullRequest: context?.payload?.pull_request !== undefined,
options: {
parallel: parseNumber(getInput('parallel')),
Expand Down
12 changes: 12 additions & 0 deletions src/libs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import YAML from 'yaml';
import { Plugin, Plugins } from '../config';

export function parseArray(input: string): string[] {
return parseUndefined(input)
? input.split(/\r?\n/).reduce<string[]>(
Expand All @@ -22,3 +25,12 @@ export function parseBoolean(input: string): boolean | undefined {
export function parseNumber(input: string): number | undefined {
return parseUndefined(input) ? Number(input) : undefined;
}

export function parsePlugins(input: string): Plugins {
if (parseUndefined(input)) {
const plugins = YAML.parse(input);
return plugins.map(plugin => plugin as Plugin) as Plugins;
} else {
return [] as Plugins;
}
}
13 changes: 13 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ const main = async () => {
await stack.setAllConfig(configMap);
}

if (config.plugins != []) {
for(const plugin of config.plugins) {
if (plugin.server) {
await stack.workspace.installPluginFromServer(plugin.name,
plugin.version,
plugin.server);
} else {
await stack.workspace.installPlugin(plugin.name, plugin.version,
plugin.kind || 'resource');
}
}
}

if (config.refresh) {
core.startGroup(`Refresh stack on ${config.stackName}`);
await stack.refresh({ onOutput });
Expand Down