* now starts the codepipeline after stack update through pwcli * cleanup
189 lines
6.0 KiB
TypeScript
189 lines
6.0 KiB
TypeScript
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
|
|
const chalk = require('chalk');
|
|
const { AutoComplete, Input, Confirm } = require('enquirer');
|
|
import { Octokit } from "@octokit/core";
|
|
import { exit } from 'process';
|
|
import { defaultMenuSettings, getCurrentBranch, getSettings, sleep } from '../../../../globals';
|
|
|
|
type Stack = {
|
|
name: string
|
|
status: string
|
|
drift_status: string
|
|
branch: string
|
|
updated: string
|
|
}
|
|
|
|
const getBranchName = async (toolbox: GluegunMenuToolbox, token: string, repoPath: string) => {
|
|
const {print} = toolbox;
|
|
const currentBranch = await getCurrentBranch(repoPath, toolbox);
|
|
const input = new Input({
|
|
type: 'input',
|
|
name: 'branch',
|
|
message: 'What github branch should be deployed?',
|
|
initial: currentBranch,
|
|
});
|
|
const responseBranch = await input.run();
|
|
|
|
// First ask what branch should be deployed
|
|
const octokit = new Octokit({ auth: token });
|
|
|
|
try {
|
|
const response = await octokit.request("GET /repos/{owner}/{repo}/branches/{branch}", {
|
|
owner: "photowall",
|
|
repo: "photowall",
|
|
branch: responseBranch
|
|
});
|
|
if (response.status === 200) {
|
|
return responseBranch;
|
|
}
|
|
} catch (e) {
|
|
print.error('Not a valid branch on photowall repo');
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const getConfirmation = async (branchName: string, stackName: string) => {
|
|
const confirm = new Confirm({
|
|
name: 'confirm',
|
|
message: `The branch ${chalk.green(branchName)} will deploy to ${chalk.yellow(stackName)}`
|
|
});
|
|
|
|
try {
|
|
return confirm.run();
|
|
} catch (e) {
|
|
console.error(e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
name: 'update',
|
|
alias: ['u'],
|
|
description: 'Update stack with different branch (u)',
|
|
hidden: false,
|
|
run: async (toolbox: GluegunMenuToolbox) => {
|
|
const { system, strings, print } = toolbox;
|
|
|
|
// Load settings
|
|
const config = await getSettings(toolbox);
|
|
if (!config || (!config.photowall_repo || config.photowall_repo === "")) {
|
|
print.error(`
|
|
|
|
The create command requires that you set an absolute path to your local photowall repository.
|
|
|
|
`);
|
|
await toolbox.menu.showMenu('setup', defaultMenuSettings);
|
|
return;
|
|
}
|
|
|
|
let branchName = null;
|
|
while (!branchName) {
|
|
branchName = await getBranchName(toolbox, config.gh_token, config.photowall_repo);
|
|
}
|
|
|
|
const stacks = JSON.parse(
|
|
strings.trim(await system.run(`aws cloudformation list-stacks`))
|
|
)
|
|
const teststacks: Stack[] = await Promise.all(
|
|
stacks.StackSummaries.map(async item => {
|
|
if (
|
|
item.StackName.indexOf('photowall-test-') > -1 &&
|
|
[
|
|
'CREATE_COMPLETE',
|
|
'UPDATE_COMPLETE',
|
|
'UPDATE_IN_PROGRESS',
|
|
'UPDATE_FAILED',
|
|
'CREATE_FAILED',
|
|
'CREATE_IN_PROGRESS'
|
|
].includes(item.StackStatus)
|
|
) {
|
|
const pipeline = JSON.parse(
|
|
strings.trim(
|
|
await system.run(
|
|
`aws codepipeline get-pipeline --name ${item.StackName}Pipeline`
|
|
)
|
|
)
|
|
)
|
|
const branch = pipeline.pipeline.stages.filter(stage => {
|
|
return stage.name === 'Source'
|
|
})[0].actions[0].configuration.Branch
|
|
const lastUpdated = pipeline.metadata.updated
|
|
return {
|
|
name: item.StackName,
|
|
status: item.StackStatus,
|
|
drift_status: item.DriftInformation.StackDriftStatus,
|
|
branch: branch,
|
|
updated: lastUpdated
|
|
}
|
|
}
|
|
return Promise.resolve(null)
|
|
})
|
|
)
|
|
|
|
const curratedStacks: Stack[] = teststacks.filter(Boolean)
|
|
const options = curratedStacks.map(item => {
|
|
return item.name;
|
|
});
|
|
|
|
const prompt = new AutoComplete({
|
|
name: 'testserver',
|
|
message: 'Choose a server',
|
|
limit: options.length - 1,
|
|
initial: options.length - 1,
|
|
choices: options
|
|
});
|
|
|
|
try {
|
|
const stackName = await prompt.run();
|
|
const stacksuffix = stackName.replace('photowall-', '');
|
|
|
|
const shouldRun = await getConfirmation(branchName, stackName);
|
|
|
|
if (shouldRun) {
|
|
const cmd = `make update-stack STACK_ENVIRONMENT_NAME=${stacksuffix} GITHUB_BRANCH=${branchName}`;
|
|
print.fancy(`Running [${chalk.yellow(cmd)}] in folder [${`${config.photowall_repo}/cloudformation/`}]`);
|
|
const output = await system.run(cmd, {cwd: `${config.photowall_repo}/cloudformation/`, trim: true});
|
|
print.fancy(output);
|
|
|
|
// Check the status
|
|
const spinner = print.spin(`Waiting for stack to update`);
|
|
let currentStackStatus = "";
|
|
while (currentStackStatus !== "UPDATE_COMPLETE") {
|
|
const stackCmd = `aws cloudformation describe-stacks --stack-name photowall-${stacksuffix}`;
|
|
const response = await system.run(stackCmd, {trim: true});
|
|
const stackData = JSON.parse(response);
|
|
currentStackStatus = stackData.Stacks[0].StackStatus;
|
|
switch (currentStackStatus) {
|
|
case "UPDATE_IN_PROGRESS":
|
|
spinner.text = `[${chalk.red(currentStackStatus)}]: Updating the stack`;
|
|
case "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS":
|
|
spinner.text = `[${chalk.yellow(currentStackStatus)}]: Almost done, cleanup in progress`;
|
|
case "UPDATE_COMPLETE":
|
|
spinner.text = `[${chalk.green(currentStackStatus)}]: Update complete`;
|
|
break;
|
|
}
|
|
if (currentStackStatus !== 'UPDATE_COMPLETE') {
|
|
await sleep(1000);
|
|
}
|
|
}
|
|
|
|
spinner.text = `Will start the pipeline now [${chalk.yellow(`photowall-${stacksuffix}Pipeline`)}]`;
|
|
const runPipelineCmd = `aws codepipeline start-pipeline-execution --name photowall-${stacksuffix}Pipeline`;
|
|
await system.run(runPipelineCmd);
|
|
await sleep(2000);
|
|
spinner.stop();
|
|
print.fancy('Pipeline started, bye! 🚀');
|
|
}
|
|
|
|
} catch (e) {
|
|
console.log(`e`, e)
|
|
}
|
|
|
|
if (toolbox.fromMenu()) {
|
|
await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings)
|
|
} else {
|
|
exit();
|
|
}
|
|
}
|
|
}
|