update error strategy to be more idiomatic
This commit is contained in:
parent
97e1d25802
commit
7b766924ec
|
@ -14,7 +14,7 @@
|
|||
|
||||
import * as childProcess from "child_process";
|
||||
|
||||
import { CommandError } from "./errors";
|
||||
import { createCommandError } from "./errors";
|
||||
|
||||
/** @internal */
|
||||
export class CommandResult {
|
||||
|
@ -73,13 +73,13 @@ export function runPulumiCmd(
|
|||
const resCode = code !== null ? code : unknownErrCode;
|
||||
const result = new CommandResult(stdout, stderr, resCode);
|
||||
if (code !== 0) {
|
||||
return reject(new CommandError(result));
|
||||
return reject(createCommandError(result));
|
||||
}
|
||||
return resolve(result);
|
||||
});
|
||||
proc.on("error", (err) => {
|
||||
const result = new CommandResult(stdout, stderr, unknownErrCode, err);
|
||||
return reject(new CommandError(result));
|
||||
return reject(createCommandError(result));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@ import { CommandResult } from "./cmd";
|
|||
|
||||
/**
|
||||
* CommandError is an error resulting from invocation of a Pulumi Command.
|
||||
* This is an opaque error that provides utility functions to detect specific error cases
|
||||
* such as concurrent stack updates (`isConcurrentUpdateError`). If you'd like to detect an additional
|
||||
* error case that isn't currently covered, please file an issue: https://github.com/pulumi/pulumi/issues/new
|
||||
* @alpha
|
||||
*/
|
||||
export class CommandError extends Error {
|
||||
|
@ -27,30 +24,52 @@ export class CommandError extends Error {
|
|||
super(commandResult.toString());
|
||||
this.name = "CommandError";
|
||||
}
|
||||
/**
|
||||
* Returns true if the error was a result of a conflicting update locking the stack.
|
||||
*
|
||||
* @returns a boolean indicating if this failure was due to a conflicting concurrent update on the stack.
|
||||
*/
|
||||
isConcurrentUpdateError() {
|
||||
return this.commandResult.stderr.indexOf("[409] Conflict: Another update is currently in progress.") >= 0;
|
||||
}
|
||||
/**
|
||||
* Returns true if the error was the result of selecting a stack that does not exist.
|
||||
*
|
||||
* @returns a boolean indicating if this failure was the result of selecting a stack that does not exist.
|
||||
*/
|
||||
isSelectStack404Error() {
|
||||
const exp = new RegExp("no stack named.*found");
|
||||
return exp.test(this.commandResult.stderr);
|
||||
}
|
||||
/**
|
||||
* Returns true if the error was a result of creating a stack that already exists.
|
||||
*
|
||||
* @returns a boolean indicating if the error was a result of creating a stack that already exists.
|
||||
*/
|
||||
isCreateStack409Error() {
|
||||
const exp = new RegExp("stack.*already exists");
|
||||
return exp.test(this.commandResult.stderr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ConcurrentUpdateError is thrown when attempting to update a stack that already has an update in progress.
|
||||
*/
|
||||
export class ConcurrentUpdateError extends CommandError {
|
||||
/** @internal */
|
||||
constructor(commandResult: CommandResult) {
|
||||
super(commandResult);
|
||||
this.name = "ConcurrentUpdateError";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StackNotFoundError is thrown when attempting to select a stack that does not exist.
|
||||
*/
|
||||
export class StackNotFoundError extends CommandError {
|
||||
/** @internal */
|
||||
constructor(commandResult: CommandResult) {
|
||||
super(commandResult);
|
||||
this.name = "StackNotFoundError";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StackAlreadyExistsError is thrown when attempting to create a stack that already exists.
|
||||
*/
|
||||
export class StackAlreadyExistsError extends CommandError {
|
||||
/** @internal */
|
||||
constructor(commandResult: CommandResult) {
|
||||
super(commandResult);
|
||||
this.name = "StackAlreadyExistsError";
|
||||
}
|
||||
}
|
||||
|
||||
const notFoundRegex = new RegExp("no stack named.*found");
|
||||
const alreadyExistsRegex = new RegExp("stack.*already exists");
|
||||
const conflictText = "[409] Conflict: Another update is currently in progress.";
|
||||
|
||||
/** @internal */
|
||||
export function createCommandError(result: CommandResult): CommandError {
|
||||
const stderr = result.stderr;
|
||||
return (
|
||||
notFoundRegex.test(stderr) ? new StackNotFoundError(result) :
|
||||
alreadyExistsRegex.test(stderr) ? new StackAlreadyExistsError(result) :
|
||||
stderr.indexOf(conflictText) >= 0 ? new ConcurrentUpdateError(result) :
|
||||
new CommandError(result)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import * as grpc from "@grpc/grpc-js";
|
|||
|
||||
import { CommandResult, runPulumiCmd } from "./cmd";
|
||||
import { ConfigMap, ConfigValue } from "./config";
|
||||
import { CommandError } from "./errors";
|
||||
import { StackAlreadyExistsError } from "./errors";
|
||||
import { LanguageServer, maxRPCMessageSize } from "./server";
|
||||
import { PulumiFn, Workspace } from "./workspace";
|
||||
|
||||
|
@ -92,7 +92,7 @@ export class Stack {
|
|||
return this;
|
||||
case "createOrSelect":
|
||||
this.ready = workspace.createStack(name).catch((err) => {
|
||||
if (err instanceof CommandError && err.isCreateStack409Error()) {
|
||||
if (err instanceof StackAlreadyExistsError) {
|
||||
return workspace.selectStack(name);
|
||||
}
|
||||
throw err;
|
||||
|
|
Loading…
Reference in a new issue