only expose static create methods (and overloads) for Stack and LocalWorkspace
This commit is contained in:
parent
6f622bc9e1
commit
e77fc0a961
|
@ -25,7 +25,7 @@ import { asyncTest } from "../util";
|
|||
describe("LocalWorkspace", () => {
|
||||
it(`projectSettings from yaml/yml/json`, asyncTest(async () => {
|
||||
for (const ext of ["yaml", "yml", "json"]) {
|
||||
const ws = new LocalWorkspace({ workDir: upath.joinSafe(__dirname, "data", ext) });
|
||||
const ws = await LocalWorkspace.create({ workDir: upath.joinSafe(__dirname, "data", ext) });
|
||||
const settings = await ws.projectSettings();
|
||||
assert(settings.name, "testproj");
|
||||
assert(settings.runtime.name, "go");
|
||||
|
@ -36,7 +36,7 @@ describe("LocalWorkspace", () => {
|
|||
|
||||
it(`stackSettings from yaml/yml/json`, asyncTest(async () => {
|
||||
for (const ext of ["yaml", "yml", "json"]) {
|
||||
const ws = new LocalWorkspace({ workDir: upath.joinSafe(__dirname, "data", ext) });
|
||||
const ws = await LocalWorkspace.create({ workDir: upath.joinSafe(__dirname, "data", ext) });
|
||||
const settings = await ws.stackSettings("dev");
|
||||
assert.equal(settings.secretsProvider, "abc");
|
||||
assert.equal(settings.config!["plain"].value, "plain");
|
||||
|
@ -48,24 +48,22 @@ describe("LocalWorkspace", () => {
|
|||
const projectSettings = new ProjectSettings();
|
||||
projectSettings.name = "node_test";
|
||||
projectSettings.runtime.name = "nodejs";
|
||||
const ws = new LocalWorkspace({ projectSettings });
|
||||
await ws.ready;
|
||||
const ws = await LocalWorkspace.create({ projectSettings });
|
||||
const stackName = `int_test${getTestSuffix()}`;
|
||||
await ws.createStack(stackName);
|
||||
await ws.selectStack(stackName);
|
||||
await ws.removeStack(stackName);
|
||||
}));
|
||||
|
||||
it(`Create/Select/Upsert Stack`, asyncTest(async () => {
|
||||
it(`create/select/createOrSelect Stack`, asyncTest(async () => {
|
||||
const projectSettings = new ProjectSettings();
|
||||
projectSettings.name = "node_test";
|
||||
projectSettings.runtime.name = "nodejs";
|
||||
const ws = new LocalWorkspace({ projectSettings });
|
||||
await ws.ready;
|
||||
const ws = await LocalWorkspace.create({ projectSettings });
|
||||
const stackName = `int_test${getTestSuffix()}`;
|
||||
await Stack.Create(stackName, ws);
|
||||
await Stack.Select(stackName, ws);
|
||||
await Stack.Upsert(stackName, ws);
|
||||
await Stack.create(stackName, ws);
|
||||
await Stack.select(stackName, ws);
|
||||
await Stack.createOrSelect(stackName, ws);
|
||||
await ws.removeStack(stackName);
|
||||
}));
|
||||
it(`Config`, asyncTest(async () => {
|
||||
|
@ -73,10 +71,9 @@ describe("LocalWorkspace", () => {
|
|||
const projectSettings = new ProjectSettings();
|
||||
projectSettings.name = projectName;
|
||||
projectSettings.runtime.name = "nodejs";
|
||||
const ws = new LocalWorkspace({ projectSettings });
|
||||
await ws.ready;
|
||||
const ws = await LocalWorkspace.create({ projectSettings });
|
||||
const stackName = `int_test${getTestSuffix()}`;
|
||||
const stack = await Stack.Create(stackName, ws);
|
||||
const stack = await Stack.create(stackName, ws);
|
||||
|
||||
const config = {
|
||||
plain: { value: "abc" },
|
||||
|
@ -116,14 +113,13 @@ describe("LocalWorkspace", () => {
|
|||
const projectSettings = new ProjectSettings();
|
||||
projectSettings.name = `node_list_test${getTestSuffix()}`;
|
||||
projectSettings.runtime.name = "nodejs";
|
||||
const ws = new LocalWorkspace({ projectSettings });
|
||||
await ws.ready;
|
||||
const ws = await LocalWorkspace.create({ projectSettings });
|
||||
const stackNamer = () => `int_test${getTestSuffix()}`;
|
||||
const stackNames: string[] = [];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const stackName = stackNamer();
|
||||
stackNames[i] = stackName;
|
||||
await Stack.Create(stackName, ws);
|
||||
await Stack.create(stackName, ws);
|
||||
const stackSummary = await ws.stack();
|
||||
assert.equal(stackSummary?.current, true);
|
||||
const stacks = await ws.listStacks();
|
||||
|
@ -138,10 +134,9 @@ describe("LocalWorkspace", () => {
|
|||
const projectSettings = new ProjectSettings();
|
||||
projectSettings.name = "node_test";
|
||||
projectSettings.runtime.name = "nodejs";
|
||||
const ws = new LocalWorkspace({ projectSettings });
|
||||
await ws.ready;
|
||||
const ws = await LocalWorkspace.create({ projectSettings });
|
||||
const stackName = `int_test${getTestSuffix()}`;
|
||||
const stack = await Stack.Create(stackName, ws);
|
||||
const stack = await Stack.create(stackName, ws);
|
||||
const histroy = await stack.history();
|
||||
assert.equal(histroy.length, 0);
|
||||
const info = await stack.info();
|
||||
|
@ -151,7 +146,7 @@ describe("LocalWorkspace", () => {
|
|||
it(`runs through the stack lifecycle with a local program`, asyncTest(async () => {
|
||||
const stackName = `int_test${getTestSuffix()}`;
|
||||
const workDir = upath.joinSafe(__dirname, "data", "testproj");
|
||||
const stack = await LocalWorkspace.NewStackLocalSource(stackName, workDir);
|
||||
const stack = await LocalWorkspace.createStack({ stackName, workDir });
|
||||
|
||||
const config: ConfigMap = {
|
||||
"bar": { value: "abc" },
|
||||
|
@ -188,16 +183,17 @@ describe("LocalWorkspace", () => {
|
|||
await stack.getWorkspace().removeStack(stackName);
|
||||
}));
|
||||
it(`runs through the stack lifecycle with an inline program`, asyncTest(async () => {
|
||||
const program = () => {
|
||||
const program = async () => {
|
||||
const config = new Config();
|
||||
return Promise.resolve({
|
||||
return {
|
||||
exp_static: "foo",
|
||||
exp_cfg: config.get("bar"),
|
||||
exp_secret: config.getSecret("buzz"),
|
||||
});
|
||||
};
|
||||
};
|
||||
const stackName = `int_test${getTestSuffix()}`;
|
||||
const stack = await LocalWorkspace.NewStackInlineSource(stackName, "inline_node", program);
|
||||
const projectName = "inline_node";
|
||||
const stack = await LocalWorkspace.createStack({ stackName, projectName, program });
|
||||
|
||||
const stackConfig: ConfigMap = {
|
||||
"bar": { value: "abc" },
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
import * as assert from "assert";
|
||||
import { Output } from "../output";
|
||||
import { CustomResource } from "../index";
|
||||
import { Output } from "../output";
|
||||
import * as runtime from "../runtime";
|
||||
import { asyncTest } from "./util";
|
||||
|
||||
|
|
|
@ -24,77 +24,78 @@ import { StackSettings } from "./stackSettings";
|
|||
import { PulumiFn, StackSummary, Workspace } from "./workspace";
|
||||
|
||||
export class LocalWorkspace implements Workspace {
|
||||
ready: Promise<any[]>;
|
||||
private workDir: string;
|
||||
private pulumiHome?: string;
|
||||
private program?: PulumiFn;
|
||||
private envVars: { [key: string]: string };
|
||||
private secretsProvider?: string;
|
||||
public static async NewStackLocalSource(
|
||||
stackName: string, workDir: string, opts?: LocalWorkspaceOpts,
|
||||
): Promise<Stack> {
|
||||
return this.localSourceStackHelper(stackName, workDir, Stack.Create, opts);
|
||||
readonly workDir: string;
|
||||
readonly pulumiHome?: string;
|
||||
readonly secretsProvider?: string;
|
||||
public program?: PulumiFn;
|
||||
public envVars: { [key: string]: string };
|
||||
private ready: Promise<any[]>;
|
||||
public static async create(opts: LocalWorkspaceOptions): Promise<LocalWorkspace> {
|
||||
const ws = new LocalWorkspace(opts);
|
||||
await ws.ready;
|
||||
return ws;
|
||||
}
|
||||
public static async UpsertStackLocalSource(
|
||||
stackName: string, workDir: string, opts?: LocalWorkspaceOpts,
|
||||
): Promise<Stack> {
|
||||
return this.localSourceStackHelper(stackName, workDir, Stack.Upsert, opts);
|
||||
public static async createStack(args: LocalProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack>;
|
||||
public static async createStack(args: InlineProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack>;
|
||||
public static async createStack(args: InlineProgramArgs | LocalProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack> {
|
||||
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}`);
|
||||
}
|
||||
public static async SelectStackLocalSource(
|
||||
stackName: string, workDir: string, opts?: LocalWorkspaceOpts,
|
||||
): Promise<Stack> {
|
||||
return this.localSourceStackHelper(stackName, workDir, Stack.Select, opts);
|
||||
public static async selectStack(args: LocalProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack>;
|
||||
public static async selectStack(args: InlineProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack>;
|
||||
public static async selectStack(args: InlineProgramArgs | LocalProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack> {
|
||||
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}`);
|
||||
}
|
||||
public static async createOrSelectStack(args: LocalProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack>;
|
||||
public static async createOrSelectStack(args: InlineProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack>;
|
||||
public static async createOrSelectStack(args: InlineProgramArgs | LocalProgramArgs, opts?: LocalWorkspaceOptions): Promise<Stack> {
|
||||
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}`);
|
||||
}
|
||||
private static async localSourceStackHelper(
|
||||
stackName: string, workDir: string, initFn: stackInitFunc, opts?: LocalWorkspaceOpts,
|
||||
args: LocalProgramArgs, initFn: stackInitializer, opts?: LocalWorkspaceOptions,
|
||||
): Promise<Stack> {
|
||||
let wsOpts = { workDir };
|
||||
let wsOpts = { workDir: args.workDir };
|
||||
if (opts) {
|
||||
wsOpts = { ...opts, workDir };
|
||||
wsOpts = { ...opts, workDir: args.workDir };
|
||||
}
|
||||
|
||||
const ws = new LocalWorkspace(wsOpts);
|
||||
await ws.ready;
|
||||
|
||||
const stack = await initFn(stackName, ws);
|
||||
|
||||
return Promise.resolve(stack);
|
||||
}
|
||||
public static async NewStackInlineSource(
|
||||
stackName: string, projectName: string, program: PulumiFn, opts?: LocalWorkspaceOpts,
|
||||
): Promise<Stack> {
|
||||
return this.inlineSourceStackHelper(stackName, projectName, program, Stack.Create, opts);
|
||||
}
|
||||
public static async UpsertStackInlineSource(
|
||||
stackName: string, projectName: string, program: PulumiFn, opts?: LocalWorkspaceOpts,
|
||||
): Promise<Stack> {
|
||||
return this.inlineSourceStackHelper(stackName, projectName, program, Stack.Upsert, opts);
|
||||
}
|
||||
public static async SelectStackInlineSource(
|
||||
stackName: string, projectName: string, program: PulumiFn, opts?: LocalWorkspaceOpts,
|
||||
): Promise<Stack> {
|
||||
return this.inlineSourceStackHelper(stackName, projectName, program, Stack.Select, opts);
|
||||
return await initFn(args.stackName, ws);
|
||||
}
|
||||
private static async inlineSourceStackHelper(
|
||||
stackName: string, projectName: string, program: PulumiFn, initFn: stackInitFunc, opts?: LocalWorkspaceOpts,
|
||||
args: InlineProgramArgs, initFn: stackInitializer, opts?: LocalWorkspaceOptions,
|
||||
): Promise<Stack> {
|
||||
let wsOpts: LocalWorkspaceOpts = { program };
|
||||
let wsOpts: LocalWorkspaceOptions = { program: args.program };
|
||||
if (opts) {
|
||||
wsOpts = { ...opts, program };
|
||||
wsOpts = { ...opts, program: args.program };
|
||||
}
|
||||
|
||||
if (!wsOpts.projectSettings) {
|
||||
wsOpts.projectSettings = defaultProject(projectName);
|
||||
wsOpts.projectSettings = defaultProject(args.projectName);
|
||||
}
|
||||
|
||||
const ws = new LocalWorkspace(wsOpts);
|
||||
await ws.ready;
|
||||
|
||||
const stack = await initFn(stackName, ws);
|
||||
|
||||
return Promise.resolve(stack);
|
||||
return await initFn(args.stackName, ws);
|
||||
}
|
||||
constructor(opts?: LocalWorkspaceOpts) {
|
||||
private constructor(opts?: LocalWorkspaceOptions) {
|
||||
let dir = "";
|
||||
let envs = {};
|
||||
|
||||
|
@ -135,11 +136,11 @@ export class LocalWorkspace implements Workspace {
|
|||
if (!fs.existsSync(path)) { continue; }
|
||||
const contents = fs.readFileSync(path).toString();
|
||||
if (isJSON) {
|
||||
return Promise.resolve(ProjectSettings.fromJSON(JSON.parse(contents)));
|
||||
return ProjectSettings.fromJSON(JSON.parse(contents));
|
||||
}
|
||||
return Promise.resolve(ProjectSettings.fromYAML(contents));
|
||||
return ProjectSettings.fromYAML(contents);
|
||||
}
|
||||
return Promise.reject(new Error(`failed to find project settings file in workdir: ${this.workDir}`));
|
||||
throw new Error(`failed to find project settings file in workdir: ${this.workDir}`);
|
||||
}
|
||||
async saveProjectSettings(settings: ProjectSettings): Promise<void> {
|
||||
let foundExt = ".yaml";
|
||||
|
@ -158,7 +159,7 @@ export class LocalWorkspace implements Workspace {
|
|||
else {
|
||||
contents = settings.toYAML();
|
||||
}
|
||||
return Promise.resolve(fs.writeFileSync(path, contents));
|
||||
return fs.writeFileSync(path, contents);
|
||||
}
|
||||
async stackSettings(stackName: string): Promise<StackSettings> {
|
||||
const stackSettingsName = getStackSettingsName(stackName);
|
||||
|
@ -168,11 +169,11 @@ export class LocalWorkspace implements Workspace {
|
|||
if (!fs.existsSync(path)) { continue; }
|
||||
const contents = fs.readFileSync(path).toString();
|
||||
if (isJSON) {
|
||||
return Promise.resolve(StackSettings.fromJSON(JSON.parse(contents)));
|
||||
return StackSettings.fromJSON(JSON.parse(contents));
|
||||
}
|
||||
return Promise.resolve(StackSettings.fromYAML(contents));
|
||||
return StackSettings.fromYAML(contents);
|
||||
}
|
||||
return Promise.reject(new Error(`failed to find stack settings file in workdir: ${this.workDir}`));
|
||||
throw new Error(`failed to find stack settings file in workdir: ${this.workDir}`);
|
||||
}
|
||||
async saveStackSettings(settings: StackSettings, stackName: string): Promise<void> {
|
||||
const stackSettingsName = getStackSettingsName(stackName);
|
||||
|
@ -192,53 +193,37 @@ export class LocalWorkspace implements Workspace {
|
|||
else {
|
||||
contents = settings.toYAML();
|
||||
}
|
||||
return Promise.resolve(fs.writeFileSync(path, contents));
|
||||
return fs.writeFileSync(path, contents);
|
||||
}
|
||||
async createStack(stackName: string): Promise<void> {
|
||||
const args = ["stack", "init", stackName];
|
||||
if (this.secretsProvider) {
|
||||
args.push("--secrets-provider", this.secretsProvider);
|
||||
}
|
||||
try {
|
||||
const result = await this.runPulumiCmd(args);
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await this.runPulumiCmd(args);
|
||||
}
|
||||
async selectStack(stackName: string): Promise<void> {
|
||||
try {
|
||||
const result = await this.runPulumiCmd(["stack", "select", stackName]);
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await this.runPulumiCmd(["stack", "select", stackName]);
|
||||
}
|
||||
async removeStack(stackName: string): Promise<void> {
|
||||
try {
|
||||
const result = await this.runPulumiCmd(["stack", "rm", "--yes", stackName]);
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await this.runPulumiCmd(["stack", "rm", "--yes", stackName]);
|
||||
}
|
||||
async getConfig(stackName: string, key: string): Promise<ConfigValue> {
|
||||
await this.selectStack(stackName);
|
||||
const result = await this.runPulumiCmd(["config", "get", key, "--json"]);
|
||||
const val = JSON.parse(result.stdout);
|
||||
return Promise.resolve(val);
|
||||
return val;
|
||||
}
|
||||
async getAllConfig(stackName: string): Promise<ConfigMap> {
|
||||
await this.selectStack(stackName);
|
||||
const result = await this.runPulumiCmd(["config", "--show-secrets", "--json"]);
|
||||
const val = JSON.parse(result.stdout);
|
||||
return Promise.resolve(val);
|
||||
return val;
|
||||
}
|
||||
async setConfig(stackName: string, key: string, value: ConfigValue): Promise<void> {
|
||||
await this.selectStack(stackName);
|
||||
const secretArg = value.secret ? "--secret" : "--plaintext";
|
||||
await this.runPulumiCmd(["config", "set", key, value.value, secretArg]);
|
||||
return Promise.resolve();
|
||||
}
|
||||
async setAllConfig(stackName: string, config: ConfigMap): Promise<void> {
|
||||
const promises: Promise<void>[] = [];
|
||||
|
@ -246,74 +231,48 @@ export class LocalWorkspace implements Workspace {
|
|||
promises.push(this.setConfig(stackName, key, value));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return Promise.resolve();
|
||||
}
|
||||
async removeConfig(stackName: string, key: string): Promise<void> {
|
||||
await this.selectStack(stackName);
|
||||
await this.runPulumiCmd(["config", "rm", key]);
|
||||
return Promise.resolve();
|
||||
}
|
||||
async removeAllConfig(stackName: string, keys: string[]): Promise<void> {
|
||||
const promises: Promise<void>[] = [];
|
||||
for (const key of keys) {
|
||||
promises.push(this.removeConfig(stackName, key));
|
||||
}
|
||||
return Promise.resolve(<any>{});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
async refreshConfig(stackName: string): Promise<ConfigMap> {
|
||||
await this.selectStack(stackName);
|
||||
await this.runPulumiCmd(["config", "refresh", "--force"]);
|
||||
return this.getAllConfig(stackName);
|
||||
}
|
||||
getEnvVars(): { [key: string]: string } {
|
||||
return this.envVars;
|
||||
}
|
||||
setEnvVars(envs: { [key: string]: string }): void {
|
||||
this.envVars = { ...this.envVars, ...envs };
|
||||
}
|
||||
setEnvVar(key: string, value: string): void {
|
||||
this.envVars[key] = value;
|
||||
}
|
||||
unsetEnvVar(key: string): void {
|
||||
delete this.envVars[key];
|
||||
}
|
||||
getWorkDir(): string {
|
||||
return this.workDir;
|
||||
}
|
||||
getPulumiHome(): string | undefined {
|
||||
return this.pulumiHome;
|
||||
}
|
||||
async whoAmI(): Promise<string> {
|
||||
const result = await this.runPulumiCmd(["whoami"]);
|
||||
return Promise.resolve(result.stdout.trim());
|
||||
return result.stdout.trim();
|
||||
}
|
||||
async stack(): Promise<StackSummary | undefined> {
|
||||
const stacks = await this.listStacks();
|
||||
for (const stack of stacks) {
|
||||
if (stack.current) {
|
||||
return Promise.resolve(stack);
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
return undefined;
|
||||
}
|
||||
async listStacks(): Promise<StackSummary[]> {
|
||||
const result = await this.runPulumiCmd(["stack", "ls", "--json"]);
|
||||
const stacks: StackSummary[] = JSON.parse(result.stdout);
|
||||
return Promise.resolve(stacks);
|
||||
return stacks;
|
||||
}
|
||||
getProgram(): PulumiFn | undefined {
|
||||
return this.program;
|
||||
}
|
||||
setProgram(program: PulumiFn): void {
|
||||
this.program = program;
|
||||
}
|
||||
serializeArgsForOp(_: string): Promise<string[]> {
|
||||
async serializeArgsForOp(_: string): Promise<string[]> {
|
||||
// LocalWorkspace does not take advantage of this extensibility point.
|
||||
return Promise.resolve([]);
|
||||
return [];
|
||||
}
|
||||
postCommandCallback(_: string): Promise<void> {
|
||||
async postCommandCallback(_: string): Promise<void> {
|
||||
// LocalWorkspace does not take advantage of this extensibility point.
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
private async runPulumiCmd(
|
||||
args: string[],
|
||||
|
@ -322,12 +281,23 @@ export class LocalWorkspace implements Workspace {
|
|||
if (this.pulumiHome) {
|
||||
envs["PULUMI_HOME"] = this.pulumiHome;
|
||||
}
|
||||
envs = { ...envs, ...this.getEnvVars() };
|
||||
envs = { ...envs, ...this.envVars };
|
||||
return runPulumiCmd(args, this.workDir, envs);
|
||||
}
|
||||
}
|
||||
|
||||
export type LocalWorkspaceOpts = {
|
||||
export interface InlineProgramArgs {
|
||||
stackName: string;
|
||||
projectName: string;
|
||||
program: PulumiFn;
|
||||
}
|
||||
|
||||
export interface LocalProgramArgs {
|
||||
stackName: string;
|
||||
workDir: string;
|
||||
}
|
||||
|
||||
export type LocalWorkspaceOptions = {
|
||||
workDir?: string,
|
||||
pulumiHome?: string,
|
||||
program?: PulumiFn,
|
||||
|
@ -337,21 +307,30 @@ export type LocalWorkspaceOpts = {
|
|||
stackSettings?: { [key: string]: StackSettings },
|
||||
};
|
||||
|
||||
function isLocalProgramArgs(args: LocalProgramArgs | InlineProgramArgs): args is LocalProgramArgs {
|
||||
return (args as LocalProgramArgs).workDir !== undefined;
|
||||
}
|
||||
|
||||
function isInlineProgramArgs(args: LocalProgramArgs | InlineProgramArgs): args is InlineProgramArgs {
|
||||
return (args as InlineProgramArgs).projectName !== undefined &&
|
||||
(args as InlineProgramArgs).program !== undefined;
|
||||
}
|
||||
|
||||
export const settingsExtensions = [".yaml", ".yml", ".json"];
|
||||
|
||||
const getStackSettingsName = (name: string): string => {
|
||||
function getStackSettingsName(name: string): string {
|
||||
const parts = name.split("/");
|
||||
if (parts.length < 1) {
|
||||
return name;
|
||||
}
|
||||
return parts[parts.length - 1];
|
||||
};
|
||||
}
|
||||
|
||||
type stackInitFunc = (name: string, workspace: Workspace) => Promise<Stack>;
|
||||
type stackInitializer = (name: string, workspace: Workspace) => Promise<Stack>;
|
||||
|
||||
const defaultProject = (projectName: string) => {
|
||||
function defaultProject(projectName: string) {
|
||||
const settings = new ProjectSettings();
|
||||
settings.name = projectName;
|
||||
settings.runtime.name = "nodejs";
|
||||
return settings;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,28 +21,26 @@ import { PulumiFn, Workspace } from "./workspace";
|
|||
|
||||
const langrpc = require("../../proto/language_grpc_pb.js");
|
||||
|
||||
export type StackInitMode = "create" | "select" | "upsert";
|
||||
|
||||
export class Stack {
|
||||
ready: Promise<any>;
|
||||
private name: string;
|
||||
private workspace: Workspace;
|
||||
public static async Create(name: string, workspace: Workspace): Promise<Stack> {
|
||||
readonly name: string;
|
||||
readonly workspace: Workspace;
|
||||
private ready: Promise<any>;
|
||||
public static async create(name: string, workspace: Workspace): Promise<Stack> {
|
||||
const stack = new Stack(name, workspace, "create");
|
||||
await stack.ready;
|
||||
return Promise.resolve(stack);
|
||||
return stack;
|
||||
}
|
||||
public static async Select(name: string, workspace: Workspace): Promise<Stack> {
|
||||
public static async select(name: string, workspace: Workspace): Promise<Stack> {
|
||||
const stack = new Stack(name, workspace, "select");
|
||||
await stack.ready;
|
||||
return Promise.resolve(stack);
|
||||
return stack;
|
||||
}
|
||||
public static async Upsert(name: string, workspace: Workspace): Promise<Stack> {
|
||||
const stack = new Stack(name, workspace, "upsert");
|
||||
public static async createOrSelect(name: string, workspace: Workspace): Promise<Stack> {
|
||||
const stack = new Stack(name, workspace, "createOrSelect");
|
||||
await stack.ready;
|
||||
return Promise.resolve(stack);
|
||||
return stack;
|
||||
}
|
||||
constructor(name: string, workspace: Workspace, mode: StackInitMode) {
|
||||
private constructor(name: string, workspace: Workspace, mode: StackInitMode) {
|
||||
this.name = name;
|
||||
this.workspace = workspace;
|
||||
|
||||
|
@ -53,7 +51,7 @@ export class Stack {
|
|||
case "select":
|
||||
this.ready = workspace.selectStack(name);
|
||||
return this;
|
||||
case "upsert":
|
||||
case "createOrSelect":
|
||||
// TODO update this based on structured errors (check for 409)
|
||||
this.ready = workspace.createStack(name).catch(() => {
|
||||
return workspace.selectStack(name);
|
||||
|
@ -66,7 +64,7 @@ export class Stack {
|
|||
async up(opts?: UpOptions): Promise<UpResult> {
|
||||
const args = ["up", "--yes", "--skip-preview"];
|
||||
let kind = execKind.local;
|
||||
let program: PulumiFn | undefined = this.workspace.getProgram();
|
||||
let program = this.workspace.program;
|
||||
await this.workspace.selectStack(this.name);
|
||||
|
||||
if (opts) {
|
||||
|
@ -133,13 +131,13 @@ export class Stack {
|
|||
summary: status[0]!,
|
||||
outputs: status[1]!,
|
||||
};
|
||||
return Promise.resolve(result);
|
||||
return result;
|
||||
}
|
||||
async preview(opts?: PreviewOptions): Promise<PreviewResult> {
|
||||
// TODO JSON
|
||||
const args = ["preview"];
|
||||
let kind = execKind.local;
|
||||
let program: PulumiFn | undefined = this.workspace.getProgram();
|
||||
let program = this.workspace.program;
|
||||
await this.workspace.selectStack(this.name);
|
||||
|
||||
if (opts) {
|
||||
|
@ -205,7 +203,7 @@ export class Stack {
|
|||
stderr: preResult.stderr,
|
||||
summary: summary!,
|
||||
};
|
||||
return Promise.resolve(result);
|
||||
return result;
|
||||
}
|
||||
async refresh(opts?: RefreshOptions): Promise<RefreshResult> {
|
||||
const args = ["refresh", "--yes", "--skip-preview"];
|
||||
|
@ -235,7 +233,7 @@ export class Stack {
|
|||
stderr: refResult.stderr,
|
||||
summary: summary!,
|
||||
};
|
||||
return Promise.resolve(result);
|
||||
return result;
|
||||
}
|
||||
async destroy(opts?: DestroyOptions): Promise<DestroyResult> {
|
||||
const args = ["destroy", "--yes", "--skip-preview"];
|
||||
|
@ -265,7 +263,7 @@ export class Stack {
|
|||
stderr: preResult.stderr,
|
||||
summary: summary!,
|
||||
};
|
||||
return Promise.resolve(result);
|
||||
return result;
|
||||
}
|
||||
getName(): string { return this.name; }
|
||||
getWorkspace(): Workspace { return this.workspace; }
|
||||
|
@ -304,34 +302,33 @@ export class Stack {
|
|||
outputs[key] = { value, secret };
|
||||
}
|
||||
|
||||
return Promise.resolve(outputs);
|
||||
return outputs;
|
||||
}
|
||||
async history(): Promise<UpdateSummary[]> {
|
||||
const result = await this.runPulumiCmd(["history", "--json", "--show-secrets"]);
|
||||
const summaries: UpdateSummary[] = JSON.parse(result.stdout);
|
||||
return Promise.resolve(summaries);
|
||||
return summaries;
|
||||
}
|
||||
async info(): Promise<UpdateSummary | undefined> {
|
||||
const history = await this.history();
|
||||
if (!history || history.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
return undefined;
|
||||
}
|
||||
return Promise.resolve(history[0]);
|
||||
return history[0];
|
||||
}
|
||||
private async runPulumiCmd(args: string[], onOutput?: (out: string) => void): Promise<CommandResult> {
|
||||
const ws = this.getWorkspace();
|
||||
let envs: { [key: string]: string } = {};
|
||||
const pulumiHome = ws.getPulumiHome();
|
||||
const pulumiHome = ws.pulumiHome;
|
||||
if (pulumiHome) {
|
||||
envs["PULUMI_HOME"] = pulumiHome;
|
||||
}
|
||||
const additionalEnvs = await ws.getEnvVars();
|
||||
envs = { ...envs, ...additionalEnvs };
|
||||
envs = { ...envs, ...ws.envVars };
|
||||
const additionalArgs = await ws.serializeArgsForOp(this.name);
|
||||
args = [...args, ...additionalArgs];
|
||||
const result = await runPulumiCmd(args, ws.getWorkDir(), envs, onOutput);
|
||||
const result = await runPulumiCmd(args, ws.workDir, envs, onOutput);
|
||||
await ws.postCommandCallback(this.name);
|
||||
return Promise.resolve(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -440,3 +437,5 @@ const execKind = {
|
|||
local: "auto.local",
|
||||
inline: "auto.inline",
|
||||
};
|
||||
|
||||
type StackInitMode = "create" | "select" | "createOrSelect";
|
||||
|
|
|
@ -17,6 +17,11 @@ import { ProjectSettings } from "./projectSettings";
|
|||
import { StackSettings } from "./stackSettings";
|
||||
|
||||
export interface Workspace {
|
||||
readonly workDir: string;
|
||||
readonly pulumiHome?: string;
|
||||
readonly secretsProvider?: string;
|
||||
program?: PulumiFn;
|
||||
envVars: { [key: string]: string };
|
||||
projectSettings(): Promise<ProjectSettings>;
|
||||
saveProjectSettings(settings: ProjectSettings): Promise<void>;
|
||||
stackSettings(stackName: string): Promise<StackSettings>;
|
||||
|
@ -30,20 +35,12 @@ export interface Workspace {
|
|||
removeConfig(stackName: string, key: string): Promise<void>;
|
||||
removeAllConfig(stackName: string, keys: string[]): Promise<void>;
|
||||
refreshConfig(stackName: string): Promise<ConfigMap>;
|
||||
getEnvVars(): { [key: string]: string };
|
||||
setEnvVars(envs: { [key: string]: string }): void;
|
||||
setEnvVar(key: string, value: string): void;
|
||||
unsetEnvVar(key: string): void;
|
||||
getWorkDir(): string;
|
||||
getPulumiHome(): string | undefined;
|
||||
whoAmI(): Promise<string>;
|
||||
stack(): Promise<StackSummary | undefined>;
|
||||
createStack(stackName: string): Promise<void>;
|
||||
selectStack(stackName: string): Promise<void>;
|
||||
removeStack(stackName: string): Promise<void>;
|
||||
listStacks(): Promise<StackSummary[]>;
|
||||
getProgram(): PulumiFn | undefined;
|
||||
setProgram(program: PulumiFn): void;
|
||||
// TODO import/export
|
||||
}
|
||||
|
||||
|
@ -56,4 +53,4 @@ export type StackSummary = {
|
|||
url?: string,
|
||||
};
|
||||
|
||||
export type PulumiFn = () => Promise<any>;
|
||||
export type PulumiFn = () => Promise<Record<string, any> | void>;
|
||||
|
|
Loading…
Reference in a new issue