2023-03-22 08:47:24 +00:00
// Copyright 2016-2023, Pulumi Corporation.
2020-09-18 00:17:34 +00:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2020-09-14 14:55:06 +00:00
import * as fs from "fs" ;
2020-10-06 15:42:15 +00:00
import * as yaml from "js-yaml" ;
2020-09-18 02:01:17 +00:00
import * as os from "os" ;
2021-03-23 06:04:36 +00:00
import * as semver from "semver" ;
2020-09-14 14:55:06 +00:00
import * as upath from "upath" ;
2020-09-19 21:07:02 +00:00
2020-09-18 00:17:34 +00:00
import { CommandResult , runPulumiCmd } from "./cmd" ;
2020-09-18 02:33:13 +00:00
import { ConfigMap , ConfigValue } from "./config" ;
2021-03-23 06:04:36 +00:00
import { minimumVersion } from "./minimumVersion" ;
2020-09-18 00:17:34 +00:00
import { ProjectSettings } from "./projectSettings" ;
2022-10-19 23:35:46 +00:00
import { RemoteGitProgramArgs } from "./remoteWorkspace" ;
2021-04-26 23:32:30 +00:00
import { OutputMap , Stack } from "./stack" ;
2021-04-12 23:49:49 +00:00
import { StackSettings , stackSettingsSerDeKeys } from "./stackSettings" ;
2022-12-14 02:08:18 +00:00
import { TagMap } from "./tag" ;
2023-03-22 08:47:24 +00:00
import { Deployment , PluginInfo , PulumiFn , StackSummary , WhoAmIResult , Workspace } from "./workspace" ;
2020-09-14 14:55:06 +00:00
2021-04-28 03:54:27 +00:00
const SKIP_VERSION_CHECK_VAR = "PULUMI_AUTOMATION_API_SKIP_VERSION_CHECK" ;
2020-10-07 07:25:36 +00:00
/ * *
* LocalWorkspace is a default implementation of the Workspace interface .
* A Workspace is the execution context containing a single Pulumi project , a program ,
* and multiple stacks . Workspaces are used to manage the execution environment ,
* providing various utilities such as plugin installation , environment configuration
* ( $PULUMI_HOME ) , and creation , deletion , and listing of Stacks .
* LocalWorkspace relies on Pulumi . yaml and Pulumi . < stack > . yaml as the intermediate format
* for Project and Stack settings . Modifying ProjectSettings will
* alter the Workspace Pulumi . yaml file , and setting config on a Stack will modify the Pulumi . < stack > . yaml file .
* This is identical to the behavior of Pulumi CLI driven workspaces .
*
* @alpha
* /
2020-09-18 02:33:13 +00:00
export class LocalWorkspace implements Workspace {
2020-10-07 07:25:36 +00:00
/ * *
* The working directory to run Pulumi CLI commands
* /
2020-10-02 21:29:47 +00:00
readonly workDir : string ;
2020-10-07 07:25:36 +00:00
/ * *
* The directory override for CLI metadata if set .
2020-10-08 02:00:03 +00:00
* This customizes the location of $PULUMI_HOME where metadata is stored and plugins are installed .
2020-10-07 07:25:36 +00:00
* /
2020-10-02 21:29:47 +00:00
readonly pulumiHome? : string ;
2020-10-07 07:25:36 +00:00
/ * *
* The secrets provider to use for encryption and decryption of stack secrets .
2022-09-21 00:10:02 +00:00
* See : https : //www.pulumi.com/docs/intro/concepts/secrets/#available-encryption-providers
2020-10-07 07:25:36 +00:00
* /
2020-10-02 21:29:47 +00:00
readonly secretsProvider? : string ;
2020-10-07 07:25:36 +00:00
/ * *
2020-10-08 02:00:03 +00:00
* The inline program ` PulumiFn ` to be used for Preview / Update operations if any .
* If none is specified , the stack will refer to ProjectSettings for this information .
2020-10-07 07:25:36 +00:00
* /
2020-10-08 18:12:43 +00:00
program? : PulumiFn ;
2020-10-07 07:25:36 +00:00
/ * *
* Environment values scoped to the current workspace . These will be supplied to every Pulumi command .
* /
2020-10-08 18:12:43 +00:00
envVars : { [ key : string ] : string } ;
2021-03-23 06:04:36 +00:00
private _pulumiVersion? : semver.SemVer ;
/ * *
* The version of the underlying Pulumi CLI / Engine .
2021-10-26 23:20:45 +00:00
*
* @returns A string representation of the version , if available . ` null ` otherwise .
2021-03-23 06:04:36 +00:00
* /
2021-03-23 22:09:50 +00:00
public get pulumiVersion ( ) : string {
2021-10-26 23:20:45 +00:00
if ( this . _pulumiVersion === undefined ) {
throw new Error ( ` Failed to get Pulumi version ` ) ;
}
return this . _pulumiVersion . toString ( ) ;
2021-03-23 06:04:36 +00:00
}
2020-10-02 21:29:47 +00:00
private ready : Promise < any [ ] > ;
2022-10-19 23:35:46 +00:00
/ * *
* Whether the workspace is a remote workspace .
* /
private remote? : boolean ;
/ * *
* Remote Git source info .
* /
private remoteGitProgramArgs? : RemoteGitProgramArgs ;
/ * *
* An optional list of arbitrary commands to run before the remote Pulumi operation is invoked .
* /
private remotePreRunCommands? : string [ ] ;
/ * *
* The environment variables to pass along when running remote Pulumi operations .
* /
private remoteEnvVars ? : { [ key : string ] : string | { secret : string } } ;
2022-12-18 03:31:44 +00:00
/ * *
* Whether to skip the default dependency installation step .
* /
private remoteSkipInstallDependencies? : boolean ;
2020-10-07 07:25:36 +00:00
/ * *
* Creates a workspace using the specified options . Used for maximal control and customization
* of the underlying environment before any stacks are created or selected .
*
* @param opts Options used to configure the Workspace
* /
2020-10-08 18:12:43 +00:00
static async create ( opts : LocalWorkspaceOptions ) : Promise < LocalWorkspace > {
2020-10-02 21:29:47 +00:00
const ws = new LocalWorkspace ( opts ) ;
await ws . ready ;
return ws ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Creates a Stack with a LocalWorkspace utilizing the local Pulumi CLI program from the specified workDir .
* This is a way to create drivers on top of pre - existing Pulumi programs . This Workspace will pick up
* any available Settings files ( Pulumi . yaml , Pulumi . < stack > . yaml ) .
*
2020-12-29 23:40:22 +00:00
* @param args A set of arguments to initialize a Stack with a pre - configured Pulumi CLI program that already exists on disk .
2020-10-07 07:25:36 +00:00
* @param opts Additional customizations to be applied to the Workspace .
* /
2020-10-08 18:12:43 +00:00
static async createStack ( args : LocalProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > ;
2020-10-07 07:25:36 +00:00
/ * *
* Creates a Stack with a LocalWorkspace utilizing the specified inline ( in process ) Pulumi program .
* This program is fully debuggable and runs in process . If no Project option is specified , default project settings
* will be created on behalf of the user . Similarly , unless a ` workDir ` option is specified , the working directory
* will default to a new temporary directory provided by the OS .
*
2020-12-29 23:40:22 +00:00
* @param args A set of arguments to initialize a Stack with and inline ` PulumiFn ` program that runs in process .
2020-10-07 07:25:36 +00:00
* @param opts Additional customizations to be applied to the Workspace .
* /
2020-10-08 18:12:43 +00:00
static async createStack ( args : InlineProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > ;
static async createStack ( args : InlineProgramArgs | LocalProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > {
2020-10-02 21:29:47 +00:00
if ( isInlineProgramArgs ( args ) ) {
return await this . inlineSourceStackHelper ( args , Stack . create , opts ) ;
} else if ( isLocalProgramArgs ( args ) ) {
return await this . localSourceStackHelper ( args , Stack . create , opts ) ;
}
throw new Error ( ` unexpected args: ${ args } ` ) ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Selects a Stack with a LocalWorkspace utilizing the local Pulumi CLI program from the specified workDir .
* This is a way to create drivers on top of pre - existing Pulumi programs . This Workspace will pick up
* any available Settings files ( Pulumi . yaml , Pulumi . < stack > . yaml ) .
*
2020-12-29 23:40:22 +00:00
* @param args A set of arguments to initialize a Stack with a pre - configured Pulumi CLI program that already exists on disk .
2020-10-07 07:25:36 +00:00
* @param opts Additional customizations to be applied to the Workspace .
* /
2020-10-08 18:12:43 +00:00
static async selectStack ( args : LocalProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > ;
2020-10-07 07:25:36 +00:00
/ * *
* Selects an existing Stack with a LocalWorkspace utilizing the specified inline ( in process ) Pulumi program .
* This program is fully debuggable and runs in process . If no Project option is specified , default project settings
* will be created on behalf of the user . Similarly , unless a ` workDir ` option is specified , the working directory
* will default to a new temporary directory provided by the OS .
*
2020-12-29 23:40:22 +00:00
* @param args A set of arguments to initialize a Stack with and inline ` PulumiFn ` program that runs in process .
2020-10-07 07:25:36 +00:00
* @param opts Additional customizations to be applied to the Workspace .
* /
2020-10-08 18:12:43 +00:00
static async selectStack ( args : InlineProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > ;
static async selectStack ( args : InlineProgramArgs | LocalProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > {
2020-10-02 21:29:47 +00:00
if ( isInlineProgramArgs ( args ) ) {
return await this . inlineSourceStackHelper ( args , Stack . select , opts ) ;
} else if ( isLocalProgramArgs ( args ) ) {
return await this . localSourceStackHelper ( args , Stack . select , opts ) ;
}
throw new Error ( ` unexpected args: ${ args } ` ) ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Creates or selects an existing Stack with a LocalWorkspace utilizing the specified inline ( in process ) Pulumi CLI program .
* This program is fully debuggable and runs in process . If no Project option is specified , default project settings
* will be created on behalf of the user . Similarly , unless a ` workDir ` option is specified , the working directory
* will default to a new temporary directory provided by the OS .
*
2020-12-29 23:40:22 +00:00
* @param args A set of arguments to initialize a Stack with a pre - configured Pulumi CLI program that already exists on disk .
2020-10-07 07:25:36 +00:00
* @param opts Additional customizations to be applied to the Workspace .
* /
2020-10-08 18:12:43 +00:00
static async createOrSelectStack ( args : LocalProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > ;
2020-10-07 07:25:36 +00:00
/ * *
* Creates or selects an existing Stack with a LocalWorkspace utilizing the specified inline Pulumi CLI program .
* This program is fully debuggable and runs in process . If no Project option is specified , default project settings will be created
* on behalf of the user . Similarly , unless a ` workDir ` option is specified , the working directory will default
* to a new temporary directory provided by the OS .
*
2020-12-29 23:40:22 +00:00
* @param args A set of arguments to initialize a Stack with and inline ` PulumiFn ` program that runs in process .
2020-10-07 07:25:36 +00:00
* @param opts Additional customizations to be applied to the Workspace .
* /
2020-10-08 18:12:43 +00:00
static async createOrSelectStack ( args : InlineProgramArgs , opts? : LocalWorkspaceOptions ) : Promise < Stack > ;
2023-04-28 22:27:10 +00:00
static async createOrSelectStack (
args : InlineProgramArgs | LocalProgramArgs ,
opts? : LocalWorkspaceOptions ,
) : Promise < Stack > {
2020-10-02 21:29:47 +00:00
if ( isInlineProgramArgs ( args ) ) {
return await this . inlineSourceStackHelper ( args , Stack . createOrSelect , opts ) ;
} else if ( isLocalProgramArgs ( args ) ) {
return await this . localSourceStackHelper ( args , Stack . createOrSelect , opts ) ;
}
throw new Error ( ` unexpected args: ${ args } ` ) ;
2020-09-22 06:10:43 +00:00
}
private static async localSourceStackHelper (
2023-04-28 22:27:10 +00:00
args : LocalProgramArgs ,
initFn : StackInitializer ,
opts? : LocalWorkspaceOptions ,
2020-09-22 06:10:43 +00:00
) : Promise < Stack > {
2020-10-02 21:29:47 +00:00
let wsOpts = { workDir : args.workDir } ;
2020-09-22 06:10:43 +00:00
if ( opts ) {
2020-10-02 21:29:47 +00:00
wsOpts = { . . . opts , workDir : args.workDir } ;
2020-09-22 06:10:43 +00:00
}
2020-09-24 02:06:26 +00:00
const ws = new LocalWorkspace ( wsOpts ) ;
2020-09-22 06:10:43 +00:00
await ws . ready ;
2020-10-02 21:29:47 +00:00
return await initFn ( args . stackName , ws ) ;
2020-09-22 06:10:43 +00:00
}
private static async inlineSourceStackHelper (
2023-04-28 22:27:10 +00:00
args : InlineProgramArgs ,
initFn : StackInitializer ,
opts? : LocalWorkspaceOptions ,
2020-09-22 06:10:43 +00:00
) : Promise < Stack > {
2020-10-02 21:29:47 +00:00
let wsOpts : LocalWorkspaceOptions = { program : args.program } ;
2020-09-22 06:10:43 +00:00
if ( opts ) {
2020-10-02 21:29:47 +00:00
wsOpts = { . . . opts , program : args.program } ;
2020-09-22 06:10:43 +00:00
}
if ( ! wsOpts . projectSettings ) {
2023-04-29 02:16:01 +00:00
if ( wsOpts . workDir ) {
2021-03-31 14:51:11 +00:00
try {
2021-03-31 18:00:11 +00:00
// Try to load the project settings.
loadProjectSettings ( wsOpts . workDir ) ;
2021-03-31 14:51:11 +00:00
} catch ( e ) {
2021-03-31 18:00:11 +00:00
// If it failed to find the project settings file, set a default project.
2021-03-31 14:51:11 +00:00
if ( e . toString ( ) . includes ( "failed to find project settings" ) ) {
wsOpts . projectSettings = defaultProject ( args . projectName ) ;
} else {
throw e ;
}
}
} else {
wsOpts . projectSettings = defaultProject ( args . projectName ) ;
}
2020-09-22 06:10:43 +00:00
}
2020-09-24 02:06:26 +00:00
const ws = new LocalWorkspace ( wsOpts ) ;
2020-09-22 06:10:43 +00:00
await ws . ready ;
2020-10-02 21:29:47 +00:00
return await initFn ( args . stackName , ws ) ;
2020-09-22 06:10:43 +00:00
}
2020-10-02 21:29:47 +00:00
private constructor ( opts? : LocalWorkspaceOptions ) {
2020-09-18 00:17:34 +00:00
let dir = "" ;
let envs = { } ;
2020-09-18 02:01:17 +00:00
2020-09-14 03:28:24 +00:00
if ( opts ) {
2023-04-28 22:27:10 +00:00
const {
workDir ,
pulumiHome ,
program ,
envVars ,
secretsProvider ,
remote ,
remoteGitProgramArgs ,
remotePreRunCommands ,
remoteEnvVars ,
remoteSkipInstallDependencies ,
} = opts ;
2020-09-18 00:17:34 +00:00
if ( workDir ) {
2023-06-24 18:53:23 +00:00
// Verify that the workdir exists.
if ( ! fs . existsSync ( workDir ) ) {
throw new Error ( ` Invalid workDir passed to local workspace: ' ${ workDir } ' does not exist ` ) ;
}
2020-09-18 00:17:34 +00:00
dir = workDir ;
}
2020-09-14 03:28:24 +00:00
this . pulumiHome = pulumiHome ;
this . program = program ;
2020-09-18 02:01:17 +00:00
this . secretsProvider = secretsProvider ;
2022-10-19 23:35:46 +00:00
this . remote = remote ;
this . remoteGitProgramArgs = remoteGitProgramArgs ;
this . remotePreRunCommands = remotePreRunCommands ;
this . remoteEnvVars = { . . . remoteEnvVars } ;
2022-12-18 03:31:44 +00:00
this . remoteSkipInstallDependencies = remoteSkipInstallDependencies ;
2020-09-18 02:01:17 +00:00
envs = { . . . envVars } ;
2020-09-18 00:17:34 +00:00
}
if ( ! dir ) {
2020-09-18 02:01:17 +00:00
dir = fs . mkdtempSync ( upath . joinSafe ( os . tmpdir ( ) , "automation-" ) ) ;
2020-09-14 03:28:24 +00:00
}
2020-09-18 00:17:34 +00:00
this . workDir = dir ;
this . envVars = envs ;
2020-09-18 02:01:17 +00:00
2021-03-23 06:04:36 +00:00
const readinessPromises : Promise < any > [ ] = [ this . getPulumiVersion ( minimumVersion ) ] ;
2020-09-18 02:01:17 +00:00
2023-04-29 02:16:01 +00:00
if ( opts ? . projectSettings ) {
2020-09-18 02:01:17 +00:00
readinessPromises . push ( this . saveProjectSettings ( opts . projectSettings ) ) ;
}
2023-04-29 02:16:01 +00:00
if ( opts ? . stackSettings ) {
2020-09-18 02:01:17 +00:00
for ( const [ name , value ] of Object . entries ( opts . stackSettings ) ) {
2020-10-07 07:25:36 +00:00
readinessPromises . push ( this . saveStackSettings ( name , value ) ) ;
2020-09-18 02:01:17 +00:00
}
}
this . ready = Promise . all ( readinessPromises ) ;
2020-09-14 03:28:24 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns the settings object for the current project if any
* LocalWorkspace reads settings from the Pulumi . yaml in the workspace .
* A workspace can contain only a single project at a time .
* /
2020-09-18 02:01:17 +00:00
async projectSettings ( ) : Promise < ProjectSettings > {
2021-03-31 14:51:11 +00:00
return loadProjectSettings ( this . workDir ) ;
2020-09-14 03:28:24 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Overwrites the settings object in the current project .
2021-01-13 00:55:59 +00:00
* There can only be a single project per workspace . Fails if new project name does not match old .
2020-10-07 07:25:36 +00:00
* LocalWorkspace writes this value to a Pulumi . yaml file in Workspace . WorkDir ( ) .
*
* @param settings The settings object to save to the Workspace .
* /
2020-09-18 02:01:17 +00:00
async saveProjectSettings ( settings : ProjectSettings ) : Promise < void > {
2020-09-14 16:10:02 +00:00
let foundExt = ".yaml" ;
2020-09-18 00:17:34 +00:00
for ( const ext of settingsExtensions ) {
2020-09-18 02:01:17 +00:00
const testPath = upath . joinSafe ( this . workDir , ` Pulumi ${ ext } ` ) ;
if ( fs . existsSync ( testPath ) ) {
foundExt = ext ;
break ;
}
2020-09-14 16:10:02 +00:00
}
const path = upath . joinSafe ( this . workDir , ` Pulumi ${ foundExt } ` ) ;
let contents ;
if ( foundExt === ".json" ) {
contents = JSON . stringify ( settings , null , 4 ) ;
2023-04-28 22:27:10 +00:00
} else {
2020-10-06 15:42:15 +00:00
contents = yaml . safeDump ( settings , { skipInvalid : true } ) ;
2020-09-14 16:10:02 +00:00
}
2020-10-02 21:29:47 +00:00
return fs . writeFileSync ( path , contents ) ;
2020-09-14 16:10:02 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns the settings object for the stack matching the specified stack name if any .
* LocalWorkspace reads this from a Pulumi . < stack > . yaml file in Workspace . WorkDir ( ) .
*
* @param stackName The stack to retrieve settings from .
* /
2020-09-18 02:01:17 +00:00
async stackSettings ( stackName : string ) : Promise < StackSettings > {
2020-09-16 15:39:44 +00:00
const stackSettingsName = getStackSettingsName ( stackName ) ;
2020-09-18 00:17:34 +00:00
for ( const ext of settingsExtensions ) {
2020-09-16 15:39:44 +00:00
const isJSON = ext === ".json" ;
const path = upath . joinSafe ( this . workDir , ` Pulumi. ${ stackSettingsName } ${ ext } ` ) ;
2023-04-28 22:27:10 +00:00
if ( ! fs . existsSync ( path ) ) {
continue ;
}
2020-09-16 15:39:44 +00:00
const contents = fs . readFileSync ( path ) . toString ( ) ;
2021-04-12 23:49:49 +00:00
let stackSettings : any ;
2020-09-16 15:39:44 +00:00
if ( isJSON ) {
2021-04-12 23:49:49 +00:00
stackSettings = JSON . parse ( contents ) ;
2020-09-16 15:39:44 +00:00
}
2021-04-12 23:49:49 +00:00
stackSettings = yaml . safeLoad ( contents ) as StackSettings ;
// Transform the serialized representation back to what we expect.
for ( const key of stackSettingsSerDeKeys ) {
if ( stackSettings . hasOwnProperty ( key [ 0 ] ) ) {
stackSettings [ key [ 1 ] ] = stackSettings [ key [ 0 ] ] ;
delete stackSettings [ key [ 0 ] ] ;
}
}
return stackSettings as StackSettings ;
2020-09-16 15:39:44 +00:00
}
2020-10-02 21:29:47 +00:00
throw new Error ( ` failed to find stack settings file in workdir: ${ this . workDir } ` ) ;
2020-09-16 15:39:44 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Overwrites the settings object for the stack matching the specified stack name .
* LocalWorkspace writes this value to a Pulumi . < stack > . yaml file in Workspace . WorkDir ( )
*
* @param stackName The stack to operate on .
* @param settings The settings object to save .
* /
async saveStackSettings ( stackName : string , settings : StackSettings ) : Promise < void > {
2020-09-16 15:39:44 +00:00
const stackSettingsName = getStackSettingsName ( stackName ) ;
let foundExt = ".yaml" ;
2020-09-18 00:17:34 +00:00
for ( const ext of settingsExtensions ) {
2020-09-18 02:01:17 +00:00
const testPath = upath . joinSafe ( this . workDir , ` Pulumi. ${ stackSettingsName } ${ ext } ` ) ;
if ( fs . existsSync ( testPath ) ) {
foundExt = ext ;
break ;
}
2020-09-16 15:39:44 +00:00
}
const path = upath . joinSafe ( this . workDir , ` Pulumi. ${ stackSettingsName } ${ foundExt } ` ) ;
2021-04-12 23:49:49 +00:00
const serializeSettings = settings as any ;
2020-09-16 15:39:44 +00:00
let contents ;
2021-04-12 23:49:49 +00:00
// Transform the keys to the serialized representation that we expect.
for ( const key of stackSettingsSerDeKeys ) {
if ( serializeSettings . hasOwnProperty ( key [ 1 ] ) ) {
serializeSettings [ key [ 0 ] ] = serializeSettings [ key [ 1 ] ] ;
delete serializeSettings [ key [ 1 ] ] ;
}
}
2020-09-16 15:39:44 +00:00
if ( foundExt === ".json" ) {
2021-04-12 23:49:49 +00:00
contents = JSON . stringify ( serializeSettings , null , 4 ) ;
2023-04-28 22:27:10 +00:00
} else {
2021-04-12 23:49:49 +00:00
contents = yaml . safeDump ( serializeSettings , { skipInvalid : true } ) ;
2020-09-16 15:39:44 +00:00
}
2020-10-02 21:29:47 +00:00
return fs . writeFileSync ( path , contents ) ;
2020-09-18 00:17:34 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Creates and sets a new stack with the stack name , failing if one already exists .
*
* @param stackName The stack to create .
* /
2020-09-18 02:01:17 +00:00
async createStack ( stackName : string ) : Promise < void > {
const args = [ "stack" , "init" , stackName ] ;
if ( this . secretsProvider ) {
args . push ( "--secrets-provider" , this . secretsProvider ) ;
}
2022-10-19 23:35:46 +00:00
if ( this . isRemote ) {
args . push ( "--no-select" ) ;
}
2020-10-02 21:29:47 +00:00
await this . runPulumiCmd ( args ) ;
2020-09-18 02:01:17 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Selects and sets an existing stack matching the stack name , failing if none exists .
*
* @param stackName The stack to select .
* /
2020-09-18 02:01:17 +00:00
async selectStack ( stackName : string ) : Promise < void > {
2022-10-19 23:35:46 +00:00
// If this is a remote workspace, we don't want to actually select the stack (which would modify global state);
// but we will ensure the stack exists by calling `pulumi stack`.
const args = [ "stack" ] ;
if ( ! this . isRemote ) {
args . push ( "select" ) ;
}
args . push ( "--stack" , stackName ) ;
await this . runPulumiCmd ( args ) ;
2020-09-18 02:01:17 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Deletes the stack and all associated configuration and history .
*
* @param stackName The stack to remove
* /
2020-09-18 02:01:17 +00:00
async removeStack ( stackName : string ) : Promise < void > {
2020-10-09 16:03:03 +00:00
await this . runPulumiCmd ( [ "stack" , "rm" , "--yes" , stackName ] ) ;
2020-09-18 02:01:17 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns the value associated with the specified stack name and key ,
* scoped to the current workspace . LocalWorkspace reads this config from the matching Pulumi . stack . yaml file .
*
* @param stackName The stack to read config from
* @param key The key to use for the config lookup
2023-10-22 06:19:25 +00:00
* @param path The key contains a path to a property in a map or list to get
2020-10-07 07:25:36 +00:00
* /
2023-10-22 06:19:25 +00:00
async getConfig ( stackName : string , key : string , path? : boolean ) : Promise < ConfigValue > {
const args = [ "config" , "get" ] ;
if ( path ) {
args . push ( "--path" ) ;
}
args . push ( key , "--json" , "--stack" , stackName ) ;
const result = await this . runPulumiCmd ( args ) ;
2020-12-29 23:40:22 +00:00
return JSON . parse ( result . stdout ) ;
2020-09-18 15:07:49 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns the config map for the specified stack name , scoped to the current workspace .
* LocalWorkspace reads this config from the matching Pulumi . stack . yaml file .
*
* @param stackName The stack to read config from
* /
2020-09-18 15:07:49 +00:00
async getAllConfig ( stackName : string ) : Promise < ConfigMap > {
2021-04-22 13:10:39 +00:00
const result = await this . runPulumiCmd ( [ "config" , "--show-secrets" , "--json" , "--stack" , stackName ] ) ;
2020-12-29 23:40:22 +00:00
return JSON . parse ( result . stdout ) ;
2020-09-18 15:07:49 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Sets the specified key - value pair on the provided stack name .
* LocalWorkspace writes this value to the matching Pulumi . < stack > . yaml file in Workspace . WorkDir ( ) .
*
* @param stackName The stack to operate on
* @param key The config key to set
* @param value The value to set
2023-10-22 06:19:25 +00:00
* @param path The key contains a path to a property in a map or list to set
2020-10-07 07:25:36 +00:00
* /
2023-10-22 06:19:25 +00:00
async setConfig ( stackName : string , key : string , value : ConfigValue , path? : boolean ) : Promise < void > {
const args = [ "config" , "set" ] ;
if ( path ) {
args . push ( "--path" ) ;
}
2020-09-19 21:40:23 +00:00
const secretArg = value . secret ? "--secret" : "--plaintext" ;
2023-10-22 06:19:25 +00:00
args . push ( key , "--stack" , stackName , secretArg , "--non-interactive" , "--" , value . value ) ;
await this . runPulumiCmd ( args ) ;
2020-09-18 15:07:49 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Sets all values in the provided config map for the specified stack name .
* LocalWorkspace writes the config to the matching Pulumi . < stack > . yaml file in Workspace . WorkDir ( ) .
*
* @param stackName The stack to operate on
2023-10-22 06:19:25 +00:00
* @param config The ` ConfigMap ` to upsert against the existing config
* @param path The keys contain a path to a property in a map or list to set
2020-10-07 07:25:36 +00:00
* /
2023-10-22 06:19:25 +00:00
async setAllConfig ( stackName : string , config : ConfigMap , path? : boolean ) : Promise < void > {
const args = [ "config" , "set-all" , "--stack" , stackName ] ;
if ( path ) {
args . push ( "--path" ) ;
}
2020-09-18 15:07:49 +00:00
for ( const [ key , value ] of Object . entries ( config ) ) {
2021-02-20 06:59:18 +00:00
const secretArg = value . secret ? "--secret" : "--plaintext" ;
2023-10-22 06:19:25 +00:00
args . push ( secretArg , ` ${ key } = ${ value . value } ` ) ;
2020-09-18 15:07:49 +00:00
}
2021-02-20 06:59:18 +00:00
await this . runPulumiCmd ( args ) ;
2020-09-18 15:07:49 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Removes the specified key - value pair on the provided stack name .
* It will remove any matching values in the Pulumi . < stack > . yaml file in Workspace . WorkDir ( ) .
*
* @param stackName The stack to operate on
* @param key The config key to remove
2023-10-22 06:19:25 +00:00
* @param path The key contains a path to a property in a map or list to remove
2020-10-07 07:25:36 +00:00
* /
2023-10-22 06:19:25 +00:00
async removeConfig ( stackName : string , key : string , path? : boolean ) : Promise < void > {
const args = [ "config" , "rm" , key , "--stack" , stackName ] ;
if ( path ) {
args . push ( "--path" ) ;
}
await this . runPulumiCmd ( args ) ;
2020-09-18 15:07:49 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
*
* Removes all values in the provided key list for the specified stack name
* It will remove any matching values in the Pulumi . < stack > . yaml file in Workspace . WorkDir ( ) .
*
* @param stackName The stack to operate on
* @param keys The list of keys to remove from the underlying config
2023-10-22 06:19:25 +00:00
* @param path The keys contain a path to a property in a map or list to remove
2020-10-07 07:25:36 +00:00
* /
2023-10-22 06:19:25 +00:00
async removeAllConfig ( stackName : string , keys : string [ ] , path? : boolean ) : Promise < void > {
const args = [ "config" , "rm-all" , "--stack" , stackName ] ;
if ( path ) {
args . push ( "--path" ) ;
}
args . push ( . . . keys ) ;
await this . runPulumiCmd ( args ) ;
2020-09-18 02:33:13 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Gets and sets the config map used with the last update for Stack matching stack name .
* It will overwrite all configuration in the Pulumi . < stack > . yaml file in Workspace . WorkDir ( ) .
*
* @param stackName The stack to refresh
* /
2020-09-18 15:07:49 +00:00
async refreshConfig ( stackName : string ) : Promise < ConfigMap > {
2021-04-22 13:10:39 +00:00
await this . runPulumiCmd ( [ "config" , "refresh" , "--force" , "--stack" , stackName ] ) ;
2020-09-18 15:07:49 +00:00
return this . getAllConfig ( stackName ) ;
2020-09-18 02:33:13 +00:00
}
2022-12-14 02:08:18 +00:00
/ * *
* Returns the value associated with the specified stack name and key ,
* scoped to the LocalWorkspace .
*
* @param stackName The stack to read tag metadata from .
* @param key The key to use for the tag lookup .
* /
async getTag ( stackName : string , key : string ) : Promise < string > {
const result = await this . runPulumiCmd ( [ "stack" , "tag" , "get" , key , "--stack" , stackName ] ) ;
return result . stdout . trim ( ) ;
}
/ * *
* Sets the specified key - value pair on the provided stack name .
*
* @param stackName The stack to operate on .
* @param key The tag key to set .
* @param value The tag value to set .
* /
async setTag ( stackName : string , key : string , value : string ) : Promise < void > {
await this . runPulumiCmd ( [ "stack" , "tag" , "set" , key , value , "--stack" , stackName ] ) ;
}
/ * *
* Removes the specified key - value pair on the provided stack name .
*
* @param stackName The stack to operate on .
* @param key The tag key to remove .
* /
async removeTag ( stackName : string , key : string ) : Promise < void > {
await this . runPulumiCmd ( [ "stack" , "tag" , "rm" , key , "--stack" , stackName ] ) ;
}
/ * *
* Returns the tag map for the specified tag name , scoped to the current LocalWorkspace .
*
* @param stackName The stack to read tag metadata from .
* /
async listTags ( stackName : string ) : Promise < TagMap > {
const result = await this . runPulumiCmd ( [ "stack" , "tag" , "ls" , "--json" , "--stack" , stackName ] ) ;
return JSON . parse ( result . stdout ) ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns the currently authenticated user .
* /
2020-10-06 16:30:47 +00:00
async whoAmI ( ) : Promise < WhoAmIResult > {
2023-03-22 08:47:24 +00:00
let ver = this . _pulumiVersion ;
if ( ver === undefined ) {
// Assume an old version. Doesn't really matter what this is as long as it's pre-3.58.
ver = semver . parse ( "3.0.0" ) ! ;
}
// 3.58 added the --json flag (https://github.com/pulumi/pulumi/releases/tag/v3.58.0)
if ( ver . compare ( "3.58.0" ) >= 0 ) {
const result = await this . runPulumiCmd ( [ "whoami" , "--json" ] ) ;
return JSON . parse ( result . stdout ) ;
2023-04-28 22:27:10 +00:00
} else {
2023-03-22 08:47:24 +00:00
const result = await this . runPulumiCmd ( [ "whoami" ] ) ;
2023-04-28 22:27:10 +00:00
return { user : result.stdout.trim ( ) } ;
2023-03-22 08:47:24 +00:00
}
2020-09-18 02:33:13 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns a summary of the currently selected stack , if any .
* /
2020-09-19 21:07:02 +00:00
async stack ( ) : Promise < StackSummary | undefined > {
const stacks = await this . listStacks ( ) ;
for ( const stack of stacks ) {
if ( stack . current ) {
2020-10-02 21:29:47 +00:00
return stack ;
2020-09-19 21:07:02 +00:00
}
}
2020-10-02 21:29:47 +00:00
return undefined ;
2020-09-18 02:33:13 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns all Stacks created under the current Project .
* This queries underlying backend and may return stacks not present in the Workspace ( as Pulumi . < stack > . yaml files ) .
* /
2020-09-19 21:07:02 +00:00
async listStacks ( ) : Promise < StackSummary [ ] > {
const result = await this . runPulumiCmd ( [ "stack" , "ls" , "--json" ] ) ;
2020-12-29 23:40:22 +00:00
return JSON . parse ( result . stdout ) ;
2020-09-18 02:33:13 +00:00
}
2020-10-09 16:03:03 +00:00
/ * *
* Installs a plugin in the Workspace , for example to use cloud providers like AWS or GCP .
*
* @param name the name of the plugin .
* @param version the version of the plugin e . g . "v1.0.0" .
* @param kind the kind of plugin , defaults to "resource"
* /
async installPlugin ( name : string , version : string , kind = "resource" ) : Promise < void > {
await this . runPulumiCmd ( [ "plugin" , "install" , kind , name , version ] ) ;
}
2022-10-07 01:40:02 +00:00
/ * *
* Installs a plugin in the Workspace , from a third party server .
*
* @param name the name of the plugin .
* @param version the version of the plugin e . g . "v1.0.0" .
* @param kind the kind of plugin , defaults to "resource"
* @param server the server to install the plugin from
* /
2022-10-11 14:51:32 +00:00
async installPluginFromServer ( name : string , version : string , server : string ) : Promise < void > {
await this . runPulumiCmd ( [ "plugin" , "install" , "resource" , name , version , "--server" , server ] ) ;
2022-10-07 01:40:02 +00:00
}
2020-10-09 16:03:03 +00:00
/ * *
* Removes a plugin from the Workspace matching the specified name and version .
*
* @param name the optional name of the plugin .
* @param versionRange optional semver range to check when removing plugins matching the given name
* e . g . "1.0.0" , ">1.0.0" .
* @param kind he kind of plugin , defaults to "resource" .
* /
async removePlugin ( name? : string , versionRange? : string , kind = "resource" ) : Promise < void > {
const args = [ "plugin" , "rm" , kind ] ;
if ( name ) {
args . push ( name ) ;
}
if ( versionRange ) {
args . push ( versionRange ) ;
}
args . push ( "--yes" ) ;
await this . runPulumiCmd ( args ) ;
}
/ * *
* Returns a list of all plugins installed in the Workspace .
* /
async listPlugins ( ) : Promise < PluginInfo [ ] > {
const result = await this . runPulumiCmd ( [ "plugin" , "ls" , "--json" ] ) ;
2020-12-29 23:40:22 +00:00
return JSON . parse ( result . stdout , ( key , value ) = > {
2020-10-09 16:03:03 +00:00
if ( key === "installTime" || key === "lastUsedTime" ) {
return new Date ( value ) ;
}
return value ;
} ) ;
}
2021-01-05 00:45:57 +00:00
/ * *
* exportStack exports the deployment state of the stack .
* This can be combined with Workspace . importStack to edit a stack ' s state ( such as recovery from failed deployments ) .
*
* @param stackName the name of the stack .
* /
async exportStack ( stackName : string ) : Promise < Deployment > {
2021-04-22 13:10:39 +00:00
const result = await this . runPulumiCmd ( [ "stack" , "export" , "--show-secrets" , "--stack" , stackName ] ) ;
2021-01-05 00:45:57 +00:00
return JSON . parse ( result . stdout ) ;
}
/ * *
* importStack imports the specified deployment state into a pre - existing stack .
* This can be combined with Workspace . exportStack to edit a stack ' s state ( such as recovery from failed deployments ) .
*
* @param stackName the name of the stack .
* @param state the stack state to import .
* /
async importStack ( stackName : string , state : Deployment ) : Promise < void > {
const randomSuffix = Math . floor ( 100000 + Math . random ( ) * 900000 ) ;
const filepath = upath . joinSafe ( os . tmpdir ( ) , ` automation- ${ randomSuffix } ` ) ;
const contents = JSON . stringify ( state , null , 4 ) ;
fs . writeFileSync ( filepath , contents ) ;
2021-04-22 13:10:39 +00:00
await this . runPulumiCmd ( [ "stack" , "import" , "--file" , filepath , "--stack" , stackName ] ) ;
2021-01-05 00:45:57 +00:00
fs . unlinkSync ( filepath ) ;
}
2021-04-26 23:32:30 +00:00
/ * *
* Gets the current set of Stack outputs from the last Stack . up ( ) .
* @param stackName the name of the stack .
* /
async stackOutputs ( stackName : string ) : Promise < OutputMap > {
// TODO: do this in parallel after this is fixed https://github.com/pulumi/pulumi/issues/6050
const maskedResult = await this . runPulumiCmd ( [ "stack" , "output" , "--json" , "--stack" , stackName ] ) ;
2023-04-28 22:27:10 +00:00
const plaintextResult = await this . runPulumiCmd ( [
"stack" ,
"output" ,
"--json" ,
"--show-secrets" ,
"--stack" ,
stackName ,
] ) ;
2021-04-26 23:32:30 +00:00
const maskedOuts = JSON . parse ( maskedResult . stdout ) ;
const plaintextOuts = JSON . parse ( plaintextResult . stdout ) ;
const outputs : OutputMap = { } ;
for ( const [ key , value ] of Object . entries ( plaintextOuts ) ) {
const secret = maskedOuts [ key ] === "[secret]" ;
outputs [ key ] = { value , secret } ;
}
return outputs ;
}
2020-10-07 07:25:36 +00:00
/ * *
* serializeArgsForOp is hook to provide additional args to every CLI commands before they are executed .
* Provided with stack name ,
* returns a list of args to append to an invoked command [ "--config=..." , ]
* LocalWorkspace does not utilize this extensibility point .
* /
2020-10-02 21:29:47 +00:00
async serializeArgsForOp ( _ : string ) : Promise < string [ ] > {
2020-10-07 07:25:36 +00:00
// LocalWorkspace does not utilize this extensibility point.
2020-10-08 02:00:03 +00:00
return [ ] ;
2020-09-18 00:17:34 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* postCommandCallback is a hook executed after every command . Called with the stack name .
* An extensibility point to perform workspace cleanup ( CLI operations may create / modify a Pulumi . stack . yaml )
* LocalWorkspace does not utilize this extensibility point .
* /
2020-10-02 21:29:47 +00:00
async postCommandCallback ( _ : string ) : Promise < void > {
2020-10-07 07:25:36 +00:00
// LocalWorkspace does not utilize this extensibility point.
2020-10-02 21:29:47 +00:00
return ;
2020-09-18 00:17:34 +00:00
}
2021-03-23 06:04:36 +00:00
private async getPulumiVersion ( minVersion : semver.SemVer ) {
const result = await this . runPulumiCmd ( [ "version" ] ) ;
2021-04-28 03:54:27 +00:00
const optOut = ! ! this . envVars [ SKIP_VERSION_CHECK_VAR ] || ! ! process . env [ SKIP_VERSION_CHECK_VAR ] ;
2021-10-28 03:54:23 +00:00
const version = parseAndValidatePulumiVersion ( minVersion , result . stdout . trim ( ) , optOut ) ;
2021-10-26 23:20:45 +00:00
if ( version != null ) {
this . _pulumiVersion = version ;
}
2022-10-19 23:35:46 +00:00
// If remote was specified, ensure the CLI supports it.
if ( ! optOut && this . isRemote ) {
// See if `--remote` is present in `pulumi preview --help`'s output.
const previewResult = await this . runPulumiCmd ( [ "preview" , "--help" ] ) ;
const previewOutput = previewResult . stdout . trim ( ) ;
if ( ! previewOutput . includes ( "--remote" ) ) {
throw new Error ( "The Pulumi CLI does not support remote operations. Please upgrade." ) ;
}
}
2021-03-23 06:04:36 +00:00
}
2023-04-28 22:27:10 +00:00
private async runPulumiCmd ( args : string [ ] ) : Promise < CommandResult > {
2020-09-19 21:40:23 +00:00
let envs : { [ key : string ] : string } = { } ;
if ( this . pulumiHome ) {
envs [ "PULUMI_HOME" ] = this . pulumiHome ;
}
2022-10-19 23:35:46 +00:00
if ( this . isRemote ) {
envs [ "PULUMI_EXPERIMENTAL" ] = "true" ;
}
2020-10-02 21:29:47 +00:00
envs = { . . . envs , . . . this . envVars } ;
2020-09-19 21:40:23 +00:00
return runPulumiCmd ( args , this . workDir , envs ) ;
2020-09-16 15:39:44 +00:00
}
2022-10-19 23:35:46 +00:00
/** @internal */
get isRemote ( ) : boolean {
return ! ! this . remote ;
}
/** @internal */
remoteArgs ( ) : string [ ] {
const args : string [ ] = [ ] ;
if ( ! this . isRemote ) {
return args ;
}
args . push ( "--remote" ) ;
if ( this . remoteGitProgramArgs ) {
2023-04-28 22:27:10 +00:00
const { url , projectPath , branch , commitHash , auth } = this . remoteGitProgramArgs ;
2022-10-19 23:35:46 +00:00
if ( url ) {
args . push ( url ) ;
}
if ( projectPath ) {
args . push ( "--remote-git-repo-dir" , projectPath ) ;
}
if ( branch ) {
args . push ( "--remote-git-branch" , branch ) ;
}
if ( commitHash ) {
args . push ( "--remote-git-commit" , commitHash ) ;
}
if ( auth ) {
const { personalAccessToken , sshPrivateKey , sshPrivateKeyPath , password , username } = auth ;
if ( personalAccessToken ) {
args . push ( "--remote-git-auth-access-token" , personalAccessToken ) ;
}
if ( sshPrivateKey ) {
args . push ( "--remote-git-auth-ssh-private-key" , sshPrivateKey ) ;
}
if ( sshPrivateKeyPath ) {
args . push ( "--remote-git-auth-ssh-private-key-path" , sshPrivateKeyPath ) ;
}
if ( password ) {
args . push ( "--remote-git-auth-password" , password ) ;
}
if ( username ) {
2023-02-24 03:31:49 +00:00
args . push ( "--remote-git-auth-username" , username ) ;
2022-10-19 23:35:46 +00:00
}
}
}
for ( const key of Object . keys ( this . remoteEnvVars ? ? { } ) ) {
const val = this . remoteEnvVars ! [ key ] ;
if ( typeof val === "string" ) {
args . push ( "--remote-env" , ` ${ key } = ${ val } ` ) ;
} else if ( "secret" in val ) {
args . push ( "--remote-env-secret" , ` ${ key } = ${ val . secret } ` ) ;
} else {
throw new Error ( ` unexpected env value ' ${ val } ' for key ' ${ key } ' ` ) ;
}
}
for ( const command of this . remotePreRunCommands ? ? [ ] ) {
args . push ( "--remote-pre-run-command" , command ) ;
}
2022-12-18 03:31:44 +00:00
if ( this . remoteSkipInstallDependencies ) {
args . push ( "--remote-skip-install-dependencies" ) ;
}
2022-10-19 23:35:46 +00:00
return args ;
}
2020-09-14 03:28:24 +00:00
}
2020-10-07 07:25:36 +00:00
/ * *
* Description of a stack backed by an inline ( in process ) Pulumi program .
* /
2020-10-02 21:29:47 +00:00
export interface InlineProgramArgs {
2020-10-07 07:25:36 +00:00
/ * *
* The name of the associated Stack
* /
2020-10-02 21:29:47 +00:00
stackName : string ;
2020-10-07 07:25:36 +00:00
/ * *
* The name of the associated project
* /
2020-10-02 21:29:47 +00:00
projectName : string ;
2020-10-07 07:25:36 +00:00
/ * *
2020-10-08 02:00:03 +00:00
* The inline ( in process ) Pulumi program to use with Update and Preview operations .
2020-10-07 07:25:36 +00:00
* /
2020-10-02 21:29:47 +00:00
program : PulumiFn ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Description of a stack backed by pre - existing local Pulumi CLI program .
* /
2020-10-02 21:29:47 +00:00
export interface LocalProgramArgs {
stackName : string ;
workDir : string ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Extensibility options to configure a LocalWorkspace ; e.g : settings to seed
* and environment variables to pass through to every command .
* /
2020-10-08 01:31:55 +00:00
export interface LocalWorkspaceOptions {
2020-10-07 07:25:36 +00:00
/ * *
* The directory to run Pulumi commands and read settings ( Pulumi . yaml and Pulumi . < stack > . yaml ) l .
* /
2020-10-08 01:31:55 +00:00
workDir? : string ;
2020-10-07 07:25:36 +00:00
/ * *
* The directory to override for CLI metadata
* /
2020-10-08 01:31:55 +00:00
pulumiHome? : string ;
2020-10-07 07:25:36 +00:00
/ * *
2020-10-08 02:00:03 +00:00
* The inline program ` PulumiFn ` to be used for Preview / Update operations if any .
* If none is specified , the stack will refer to ProjectSettings for this information .
2020-10-07 07:25:36 +00:00
* /
2020-10-08 01:31:55 +00:00
program? : PulumiFn ;
2020-10-07 07:25:36 +00:00
/ * *
* Environment values scoped to the current workspace . These will be supplied to every Pulumi command .
* /
2020-10-08 01:31:55 +00:00
envVars ? : { [ key : string ] : string } ;
2020-10-07 07:25:36 +00:00
/ * *
* The secrets provider to use for encryption and decryption of stack secrets .
2022-09-21 00:10:02 +00:00
* See : https : //www.pulumi.com/docs/intro/concepts/secrets/#available-encryption-providers
2020-10-07 07:25:36 +00:00
* /
2020-10-08 01:31:55 +00:00
secretsProvider? : string ;
2020-10-07 07:25:36 +00:00
/ * *
* The settings object for the current project .
* /
2020-10-08 01:31:55 +00:00
projectSettings? : ProjectSettings ;
2020-10-07 07:25:36 +00:00
/ * *
* A map of Stack names and corresponding settings objects .
* /
2020-10-08 01:31:55 +00:00
stackSettings ? : { [ key : string ] : StackSettings } ;
2022-10-19 23:35:46 +00:00
/ * *
* Indicates that the workspace is a remote workspace .
*
* @internal
* /
remote? : boolean ;
/ * *
* The remote Git source info .
*
* @internal
* /
remoteGitProgramArgs? : RemoteGitProgramArgs ;
/ * *
* An optional list of arbitrary commands to run before a remote Pulumi operation is invoked .
*
* @internal
* /
remotePreRunCommands? : string [ ] ;
/ * *
* The environment variables to pass along when running remote Pulumi operations .
*
* @internal
* /
remoteEnvVars ? : { [ key : string ] : string | { secret : string } } ;
2022-12-18 03:31:44 +00:00
/ * *
* Whether to skip the default dependency installation step .
*
* @internal
* /
remoteSkipInstallDependencies? : boolean ;
2020-10-08 01:31:55 +00:00
}
2020-09-14 14:55:06 +00:00
2020-10-07 07:25:36 +00:00
/ * *
* Returns true if the provided ` args ` object satisfies the ` LocalProgramArgs ` interface .
*
* @param args The args object to evaluate
* /
2020-10-02 21:29:47 +00:00
function isLocalProgramArgs ( args : LocalProgramArgs | InlineProgramArgs ) : args is LocalProgramArgs {
return ( args as LocalProgramArgs ) . workDir !== undefined ;
}
2020-10-07 07:25:36 +00:00
/ * *
* Returns true if the provided ` args ` object satisfies the ` InlineProgramArgs ` interface .
*
* @param args The args object to evaluate
* /
2020-10-02 21:29:47 +00:00
function isInlineProgramArgs ( args : LocalProgramArgs | InlineProgramArgs ) : args is InlineProgramArgs {
2023-04-28 22:27:10 +00:00
return ( args as InlineProgramArgs ) . projectName !== undefined && ( args as InlineProgramArgs ) . program !== undefined ;
2020-10-02 21:29:47 +00:00
}
2020-10-06 15:42:15 +00:00
const settingsExtensions = [ ".yaml" , ".yml" , ".json" ] ;
2020-09-16 15:39:44 +00:00
2020-10-02 21:29:47 +00:00
function getStackSettingsName ( name : string ) : string {
2020-09-16 15:39:44 +00:00
const parts = name . split ( "/" ) ;
if ( parts . length < 1 ) {
return name ;
}
return parts [ parts . length - 1 ] ;
2020-10-02 21:29:47 +00:00
}
2020-09-22 06:10:43 +00:00
2020-10-03 01:16:22 +00:00
type StackInitializer = ( name : string , workspace : Workspace ) = > Promise < Stack > ;
2020-09-22 06:10:43 +00:00
2020-10-02 21:29:47 +00:00
function defaultProject ( projectName : string ) {
2021-04-10 03:30:11 +00:00
const settings : ProjectSettings = { name : projectName , runtime : "nodejs" , main : process.cwd ( ) } ;
2020-09-22 06:10:43 +00:00
return settings ;
2020-10-02 21:29:47 +00:00
}
2021-03-23 06:04:36 +00:00
2021-03-31 14:51:11 +00:00
function loadProjectSettings ( workDir : string ) {
for ( const ext of settingsExtensions ) {
const isJSON = ext === ".json" ;
const path = upath . joinSafe ( workDir , ` Pulumi ${ ext } ` ) ;
2023-04-28 22:27:10 +00:00
if ( ! fs . existsSync ( path ) ) {
continue ;
}
2021-03-31 14:51:11 +00:00
const contents = fs . readFileSync ( path ) . toString ( ) ;
if ( isJSON ) {
return JSON . parse ( contents ) ;
}
return yaml . safeLoad ( contents ) as ProjectSettings ;
}
throw new Error ( ` failed to find project settings file in workdir: ${ workDir } ` ) ;
}
2021-10-26 23:20:45 +00:00
/ * *
* @internal
* Throws an error if the Pulumi CLI version is not valid .
*
* @param minVersion The minimum acceptable version of the Pulumi CLI .
* @param currentVersion The currently known version . ` null ` indicates that the current version is unknown .
* @paramoptOut If the user has opted out of the version check .
* /
2023-04-28 22:27:10 +00:00
export function parseAndValidatePulumiVersion (
minVersion : semver.SemVer ,
currentVersion : string ,
optOut : boolean ,
) : semver . SemVer | null {
2021-10-28 03:54:23 +00:00
const version = semver . parse ( currentVersion ) ;
2021-04-28 03:54:27 +00:00
if ( optOut ) {
2021-10-28 03:54:23 +00:00
return version ;
2021-04-28 03:54:27 +00:00
}
2021-10-28 03:54:23 +00:00
if ( version == null ) {
2023-04-28 22:27:10 +00:00
throw new Error (
` Failed to parse Pulumi CLI version. This is probably an internal error. You can override this by setting " ${ SKIP_VERSION_CHECK_VAR } " to "true". ` ,
) ;
2021-10-26 23:20:45 +00:00
}
2021-10-28 03:54:23 +00:00
if ( minVersion . major < version . major ) {
2023-04-28 22:27:10 +00:00
throw new Error (
` Major version mismatch. You are using Pulumi CLI version ${ currentVersion . toString ( ) } with Automation SDK v ${
minVersion . major
} . Please update the SDK . ` ,
) ;
2021-03-23 06:04:36 +00:00
}
2021-10-28 03:54:23 +00:00
if ( minVersion . compare ( version ) === 1 ) {
2023-04-28 22:27:10 +00:00
throw new Error (
` Minimum version requirement failed. The minimum CLI version requirement is ${ minVersion . toString ( ) } , your current CLI version is ${ currentVersion . toString ( ) } . Please update the Pulumi CLI. ` ,
) ;
2021-03-23 06:04:36 +00:00
}
2021-10-28 03:54:23 +00:00
return version ;
2021-03-23 06:04:36 +00:00
}