Swapped tslint to eslint and fixed files

This commit is contained in:
Arwid Thornström
2023-02-03 12:48:29 +01:00
committed by GitHub
parent 258e0b2dde
commit a7da247cf4
15 changed files with 1136 additions and 386 deletions
+16
View File
@@ -0,0 +1,16 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2017
},
"env": {
"es6": true
},
"extends": ["prettier"],
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"prettier/prettier": ["error"],
"no-return-await": "error"
}
}
+6 -5
View File
@@ -9,11 +9,10 @@
},
"scripts": {
"format": "prettier --write **/*.{js,ts,tsx,json}",
"lint": "tslint -p .",
"clean-build": "rm -rf ./build",
"compile": "tsc -p .",
"copy-templates": "if [ -e ./src/templates ]; then cp -a ./src/templates ./build/; fi",
"build": "yarn format && yarn lint && yarn clean-build && yarn compile && yarn copy-templates",
"build": "yarn format && yarn clean-build && yarn compile && yarn copy-templates",
"prepublishOnly": "yarn build",
"test": "jest",
"watch": "jest --watch",
@@ -48,9 +47,11 @@
"prettier": "^1.12.1",
"ts-jest": "^24.1.0",
"ts-node": "^8.4.1",
"tslint": "^5.12.0",
"tslint-config-prettier": "^1.17.0",
"tslint-config-standard": "^8.0.1",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"typescript": "^3.6.3"
},
"jest": {
+16 -8
View File
@@ -1,4 +1,4 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import chalk = require('chalk');
import { confirmMessage, defaultMenuSettings } from '../../../globals';
const { AutoComplete } = require('enquirer');
@@ -10,10 +10,11 @@ module.exports = {
description: 'Tail a log in cloudwatch (l) (WIP)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings } = toolbox;
const { system, strings } = toolbox
const groups = JSON.parse(strings.trim(await system.run(`aws logs describe-log-groups`)));
const groups = JSON.parse(
strings.trim(await system.run(`aws logs describe-log-groups`))
);
const options = groups.logGroups.map(item => {
return item.logGroupName;
@@ -29,16 +30,23 @@ module.exports = {
const logGroup = await prompt.run();
if (await confirmMessage(`Tail logs from ${chalk.yellow(logGroup)}?`)) {
const child = spawn('aws', ['logs', 'tail', `${logGroup}`, '--follow', '--format', 'short']);
const child = spawn('aws', [
'logs',
'tail',
`${logGroup}`,
'--follow',
'--format',
'short'
]);
child.stdout.setEncoding('utf8');
child.stdout.on('data', function(data) {
// Here is where the output goes
console.log(data);
});
child.stderr.on('data', (data) => {
child.stderr.on('data', data => {
console.error(`stderr: ${data}`);
});
child.on('close', (code) => {
child.on('close', code => {
console.log(`child process exited with code ${code}`);
});
}
@@ -47,4 +55,4 @@ module.exports = {
await toolbox.menu.showMenu('aws', defaultMenuSettings);
}
}
}
};
@@ -1,4 +1,4 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import chalk = require('chalk');
import { defaultMenuSettings, sleep } from '../../../globals';
const { AutoComplete } = require('enquirer');
@@ -9,7 +9,6 @@ module.exports = {
description: 'Parameter store functions (ps)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings, print, filesystem } = toolbox;
// Check for cache in /tmp folder
@@ -19,21 +18,38 @@ module.exports = {
let nextToken = '';
if (valueNames.length === 0) {
const spinner = print.spin(`Downloading parameter names (${chalk.red('0')})`);
const spinner = print.spin(
`Downloading parameter names (${chalk.red('0')})`
);
while (nextToken !== null) {
const values = JSON.parse(
strings.trim(
await system.run(`aws ssm describe-parameters --output json --max-items 50 ${(nextToken !== '') ? `--starting-token ${nextToken}` : ''}`)));
await system.run(
`aws ssm describe-parameters --output json --max-items 50 ${
nextToken !== '' ? `--starting-token ${nextToken}` : ''
}`
)
)
);
await sleep(500);
valueNames.push(...values.Parameters.map(({Name}) => { return Name; }));
valueNames.push(
...values.Parameters.map(({ Name }) => {
return Name;
})
);
nextToken = values.NextToken || null;
spinner.text = `Downloading parameter names (${chalk.red(valueNames.length)})`
spinner.text = `Downloading parameter names (${chalk.red(
valueNames.length
)})`;
}
spinner.text = 'Saving parameter names to /tmp/.pwcli_parametercache';
filesystem.file('/tmp/.pwcli_parametercache', {mode: '600', content: JSON.stringify(valueNames)});
filesystem.file('/tmp/.pwcli_parametercache', {
mode: '600',
content: JSON.stringify(valueNames)
});
await sleep(2000);
spinner.stop();
@@ -51,8 +67,18 @@ module.exports = {
try {
const parameterName = await prompt.run();
const parameterValue = JSON.parse(strings.trim(await system.run(`aws ssm get-parameter --name ${parameterName} --with-decryption`)));
print.success(`${chalk.green(parameterName)} value is [${chalk.yellow(parameterValue.Parameter.Value)}]`);
const parameterValue = JSON.parse(
strings.trim(
await system.run(
`aws ssm get-parameter --name ${parameterName} --with-decryption`
)
)
);
print.success(
`${chalk.green(parameterName)} value is [${chalk.yellow(
parameterValue.Parameter.Value
)}]`
);
} catch (e) {
parameterName = 'exit';
}
@@ -62,4 +88,4 @@ module.exports = {
await toolbox.menu.showMenu('aws', defaultMenuSettings);
}
}
}
};
@@ -1,4 +1,4 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import { exit } from 'process';
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
@@ -6,18 +6,20 @@ import { defaultMenuSettings, getSettings } from '../../../../globals';
import { getRepoBranches } from '../../../../services/github_rest';
type Stack = {
name: string
status: string
drift_status: string
branch: string
updated: string
}
name: string;
status: string;
drift_status: string;
branch: string;
updated: string;
};
const getConfirmation = async (branchName: string, stackName: string) => {
const url = stackName.replace('photowall-', '');
const confirm = new Confirm({
name: 'confirm',
message: `Will create ${chalk.yellow(url + '.photowall-test.xx')} and publish ${chalk.green(branchName)} to it, continue?`
message: `Will create ${chalk.yellow(
url + '.photowall-test.xx'
)} and publish ${chalk.green(branchName)} to it, continue?`
});
try {
@@ -26,7 +28,7 @@ const getConfirmation = async (branchName: string, stackName: string) => {
console.error(e);
return false;
}
}
};
module.exports = {
name: 'create',
@@ -38,7 +40,7 @@ module.exports = {
// Load settings
const config = await getSettings(toolbox);
if (!config || (!config.photowall_repo || config.photowall_repo === "")) {
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.
@@ -48,7 +50,12 @@ module.exports = {
return;
}
const branches = await getRepoBranches(toolbox, config.gh_token, 'Photowall', 'photowall');
const branches = await getRepoBranches(
toolbox,
config.gh_token,
'Photowall',
'photowall'
);
const branchOptions = branches.map(item => item.name);
const promptBranch = new AutoComplete({
@@ -62,7 +69,7 @@ module.exports = {
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 (
@@ -82,24 +89,24 @@ module.exports = {
`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 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)
return Promise.resolve(null);
})
)
);
const curratedStacks: Stack[] = teststacks.filter(Boolean)
const curratedStacks: Stack[] = teststacks.filter(Boolean);
const options = curratedStacks.map(item => {
return item.name;
});
@@ -110,12 +117,14 @@ module.exports = {
message: `Subdomain of new server (${chalk.yellow('test-xxx')})`
});
const stacksuffix = await input.run();
const stackName = `photowall-${stacksuffix}`
const stackName = `photowall-${stacksuffix}`;
if (options.includes(stackName)) {
print.error(`
The stack ${chalk.yellow(stackName)} is already taken, try the update command instead.
The stack ${chalk.yellow(
stackName
)} is already taken, try the update command instead.
`);
if (toolbox.fromMenu()) {
@@ -126,11 +135,16 @@ module.exports = {
} else if (stackName.indexOf('photowall-test-') !== 0) {
print.error(`
The stack must begin with ${chalk.yellow('test-')} and then something after like ${chalk.yellow('test-yourname-1')}.
The stack must begin with ${chalk.yellow(
'test-'
)} and then something after like ${chalk.yellow('test-yourname-1')}.
`);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings);
await toolbox.menu.showMenu(
'deployment testservers',
defaultMenuSettings
);
} else {
exit();
}
@@ -141,8 +155,15 @@ module.exports = {
if (shouldRun) {
const cmd = `make create-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(
`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);
}
} catch (e) {
@@ -150,7 +171,10 @@ module.exports = {
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings);
}
await toolbox.menu.showMenu(
'deployment testservers',
defaultMenuSettings
);
}
}
};
@@ -1,21 +1,23 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import { GluegunSystem } from 'gluegun';
import { defaultMenuSettings } from '../../../../globals';
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
type Stack = {
name: string,
status: string,
drift_status: string,
branch: string,
updated: string,
name: string;
status: string;
drift_status: string;
branch: string;
updated: string;
};
const getConfirmation = async (stackName: string) => {
const confirm = new Confirm({
name: 'confirm',
message: `The stack ${chalk.yellow(stackName)} will be ${chalk.red.bold('deleted')}`
message: `The stack ${chalk.yellow(stackName)} will be ${chalk.red.bold(
'deleted'
)}`
});
try {
@@ -23,12 +25,12 @@ const getConfirmation = async (stackName: string) => {
} catch (e) {
return false;
}
}
};
const confirmCommand = async (cmd: string) => {
const confirm = new Confirm({
name: 'confirm',
message: `RUN COMMAND > [${chalk.yellow(cmd)}] ?`,
message: `RUN COMMAND > [${chalk.yellow(cmd)}] ?`
});
try {
@@ -40,7 +42,7 @@ const confirmCommand = async (cmd: string) => {
} catch (e) {
return null;
}
}
};
const runCommand = async (system: GluegunSystem, cmd: string | null) => {
if (cmd) {
@@ -55,12 +57,11 @@ module.exports = {
description: 'Choose a testserver to delete (d)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings, print } = toolbox;
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 (
@@ -80,27 +81,27 @@ module.exports = {
`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 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)
return Promise.resolve(null);
})
)
);
const curratedStacks: Stack[] = teststacks.filter(Boolean)
const curratedStacks: Stack[] = teststacks.filter(Boolean);
const options = curratedStacks.map(item => {
return item.name
})
return item.name;
});
const prompt = new AutoComplete({
name: 'testserver',
@@ -115,20 +116,50 @@ module.exports = {
const shouldRun = await getConfirmation(stackName);
if (shouldRun) {
await runCommand(system, await confirmCommand(`aws cloudformation delete-stack --stack-name ${stackName}`));
await runCommand(system, await confirmCommand(`aws ecr delete-repository --force --repository-name ${stackName}`));
await runCommand(system, await confirmCommand(`aws logs delete-log-group --log-group-name /aws/codebuild/${stackName}`));
await runCommand(system, await confirmCommand(`aws logs delete-log-group --log-group-name ${stackName}`));
const artifacts = strings.trim(
await system.run(`aws s3 ls | grep ${stackName}-artifactbucket | awk '{print $3}'`)
).split('\n');
await runCommand(
system,
await confirmCommand(
`aws cloudformation delete-stack --stack-name ${stackName}`
)
);
await runCommand(
system,
await confirmCommand(
`aws ecr delete-repository --force --repository-name ${stackName}`
)
);
await runCommand(
system,
await confirmCommand(
`aws logs delete-log-group --log-group-name /aws/codebuild/${stackName}`
)
);
await runCommand(
system,
await confirmCommand(
`aws logs delete-log-group --log-group-name ${stackName}`
)
);
const artifacts = strings
.trim(
await system.run(
`aws s3 ls | grep ${stackName}-artifactbucket | awk '{print $3}'`
)
)
.split('\n');
for (const artifact of artifacts) {
await runCommand(system, await confirmCommand(`aws s3 rb --force s3://${artifact}`));
await runCommand(
system,
await confirmCommand(`aws s3 rb --force s3://${artifact}`)
);
}
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings);
}
await toolbox.menu.showMenu(
'deployment testservers',
defaultMenuSettings
);
}
}
};
@@ -1,14 +1,14 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import chalk = require('chalk');
import { defaultMenuSettings } from '../../../../globals';
const tto = require('terminal-table-output').create();
type Stack = {
name: string,
status: string,
drift_status: string,
branch: string,
updated: string,
name: string;
status: string;
drift_status: string;
branch: string;
updated: string;
};
module.exports = {
@@ -17,39 +17,59 @@ module.exports = {
description: 'Show status for available testservers (s)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings } = toolbox;
const { system, strings } = toolbox
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 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)
) {
try {
const pipeline = JSON.parse(strings.trim(await system.run(`aws codepipeline get-pipeline --name ${item.StackName}Pipeline`)));
const pipeline = JSON.parse(
strings.trim(
await system.run(
`aws codepipeline get-pipeline --name ${item.StackName}Pipeline`
)
)
);
const sourceStage = pipeline.pipeline.stages.filter(stage => {
return stage.name === 'Source';
});
const branch = sourceStage[0].actions[0].configuration.Branch ?? sourceStage[0].actions[0].configuration.BranchName;
const branch =
sourceStage[0].actions[0].configuration.Branch ??
sourceStage[0].actions[0].configuration.BranchName;
const lastUpdated = pipeline.metadata.updated;
return {
name: item.StackName,
status: item.StackStatus,
drift_status: item.DriftInformation.StackDriftStatus,
branch: branch,
updated: lastUpdated,
}
updated: lastUpdated
};
} catch (e) {
return {
name: item.StackName,
status: 'NO_STATUS',
drift_status: '',
branch: '',
updated: '',
updated: ''
};
}
}
}
return Promise.resolve(null);
}));
})
);
const curratedStacks: Stack[] = teststacks.filter(Boolean);
@@ -67,10 +87,12 @@ module.exports = {
case 'CREATE_COMPLETE':
return `(${chalk.greenBright('OK')})`;
}
}
};
const stackUrl = (stackname: string) => {
return `https://test-${stackname.split('photowall-test-')[1]}.photowall-test.com/us`;
return `https://test-${
stackname.split('photowall-test-')[1]
}.photowall-test.com/us`;
};
const ellipsis = (a: string, max: number) => {
@@ -88,30 +110,31 @@ module.exports = {
let interval = seconds / 31536000;
if (interval > 1) {
return Math.floor(interval) + " years";
return Math.floor(interval) + ' years';
}
interval = seconds / 2592000;
if (interval > 1) {
return `${chalk.red(Math.floor(interval) + " months")}`;
return `${chalk.red(Math.floor(interval) + ' months')}`;
}
interval = seconds / 86400;
if (interval > 1) {
const days = Math.floor(interval);
return `${chalk[days >= 14 ? 'yellow' : 'green'](days + " days")}`;
return `${chalk[days >= 14 ? 'yellow' : 'green'](days + ' days')}`;
}
interval = seconds / 3600;
if (interval > 1) {
return `${chalk.green(Math.floor(interval) + " hours")}`;
return `${chalk.green(Math.floor(interval) + ' hours')}`;
}
interval = seconds / 60;
if (interval > 1) {
return `${chalk.green(Math.floor(interval) + " minutes")}`;
}
return Math.floor(seconds) + " seconds";
return `${chalk.green(Math.floor(interval) + ' minutes')}`;
}
return Math.floor(seconds) + ' seconds';
};
tto.line('-');
tto.pushrow(['| status', 'stack', 'branch', 'time since update', 'url'])
tto
.pushrow(['| status', 'stack', 'branch', 'time since update', 'url'])
.line('-');
// Sort on stackname
curratedStacks.sort((a, b) => {
@@ -121,12 +144,21 @@ module.exports = {
});
for (const stack of curratedStacks) {
const t = new Date(stack.updated);
tto.pushrow([status(stack.status), stack.name, ellipsis(stack.branch, 24), timeSince(t.getTime()), stackUrl(stack.name)]);
tto.pushrow([
status(stack.status),
stack.name,
ellipsis(stack.branch, 24),
timeSince(t.getTime()),
stackUrl(stack.name)
]);
}
tto.print(true);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings);
}
await toolbox.menu.showMenu(
'deployment testservers',
defaultMenuSettings
);
}
}
};
@@ -1,26 +1,35 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
import { Octokit } from "@octokit/core";
import { Octokit } from '@octokit/core';
import { exit } from 'process';
import { defaultMenuSettings, getCurrentBranch, getSettings, sleep } from '../../../../globals';
import {
defaultMenuSettings,
getCurrentBranch,
getSettings,
sleep
} from '../../../../globals';
type Stack = {
name: string
status: string
drift_status: string
branch: string
updated: string
}
name: string;
status: string;
drift_status: string;
branch: string;
updated: string;
};
const getBranchName = async (toolbox: GluegunMenuToolbox, token: string, repoPath: 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,
initial: currentBranch
});
const responseBranch = await input.run();
@@ -28,11 +37,14 @@ const getBranchName = async (toolbox: GluegunMenuToolbox, token: string, repoPat
const octokit = new Octokit({ auth: token });
try {
const response = await octokit.request("GET /repos/{owner}/{repo}/branches/{branch}", {
owner: "photowall",
repo: "photowall",
const response = await octokit.request(
'GET /repos/{owner}/{repo}/branches/{branch}',
{
owner: 'photowall',
repo: 'photowall',
branch: responseBranch
});
}
);
if (response.status === 200) {
return responseBranch;
}
@@ -45,7 +57,9 @@ const getBranchName = async (toolbox: GluegunMenuToolbox, token: string, repoPat
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)}`
message: `The branch ${chalk.green(
branchName
)} will deploy to ${chalk.yellow(stackName)}`
});
try {
@@ -54,7 +68,7 @@ const getConfirmation = async (branchName: string, stackName: string) => {
console.error(e);
return false;
}
}
};
module.exports = {
name: 'update',
@@ -66,7 +80,7 @@ module.exports = {
// Load settings
const config = await getSettings(toolbox);
if (!config || (!config.photowall_repo || config.photowall_repo === "")) {
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.
@@ -78,12 +92,16 @@ module.exports = {
let branchName = null;
while (!branchName) {
branchName = await getBranchName(toolbox, config.gh_token, config.photowall_repo);
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 (
@@ -103,24 +121,24 @@ module.exports = {
`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 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)
return Promise.resolve(null);
})
)
);
const curratedStacks: Stack[] = teststacks.filter(Boolean)
const curratedStacks: Stack[] = teststacks.filter(Boolean);
const options = curratedStacks.map(item => {
return item.name;
});
@@ -141,48 +159,69 @@ module.exports = {
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(
`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") {
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;
let statusOutput = '';
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`;
case 'UPDATE_COMPLETE_CLEANUP_IN_PROGRESS':
statusOutput = `[${chalk.yellow(
currentStackStatus
)}]: Almost done, cleanup in progress`;
break;
case 'UPDATE_COMPLETE':
statusOutput = `[${chalk.green(
currentStackStatus
)}]: Update complete`;
break;
default:
statusOutput = `[${chalk.red(
currentStackStatus
)}]: Updating the stack`;
break;
}
spinner.text = statusOutput;
if (currentStackStatus !== 'UPDATE_COMPLETE') {
await sleep(1000);
}
}
spinner.text = `Will start the pipeline now [${chalk.yellow(`photowall-${stacksuffix}Pipeline`)}]`;
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)
console.log(`e`, e);
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings)
await toolbox.menu.showMenu(
'deployment testservers',
defaultMenuSettings
);
} else {
exit();
}
}
}
};
+29 -18
View File
@@ -12,7 +12,7 @@ const checkCLIProgram = async (toolbox: GluegunMenuToolbox, cmd: string) => {
} catch (e) {
return false;
}
}
};
module.exports = {
name: 'settings',
@@ -20,10 +20,10 @@ module.exports = {
description: 'Setup settings for pwcli (se)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
const { print, system, strings } = toolbox;
print.info(chalk.yellow(`
print.info(
chalk.yellow(`
This will help you setup everything needed to run pwcli on a mac (maby linux).
All settings will be saved to ${chalk.cyan('~/.pwcli_settings')}
@@ -31,7 +31,8 @@ module.exports = {
First step is to install aws cli [https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html]
and configuring it. Install it either with brew or do as specified in the link.
`));
`)
);
let config = await getSettings(toolbox);
@@ -101,38 +102,48 @@ module.exports = {
// }
await system.run('touch ~/.pwcli_settings');
print.info(`Created configuration file ${chalk.yellow(`~/.pwcli_settings`)}`);
print.info(
`Created configuration file ${chalk.yellow(`~/.pwcli_settings`)}`
);
if (!config) {
config = {
gh_token: '',
photowall_repo: '',
photowall_repo: ''
};
}
config.gh_token = await (new Input({
message: `A github accesstoken is required with ${chalk.yellow('Full control of private repositories')}, please insert the key >`,
initial: config.gh_token,
})).run();
config.gh_token = await new Input({
message: `A github accesstoken is required with ${chalk.yellow(
'Full control of private repositories'
)}, please insert the key >`,
initial: config.gh_token
}).run();
config.photowall_repo = await (new Input({
config.photowall_repo = await new Input({
message: `If you want to be able to use current branch in your photowall repository\nor the create and update commands for testservers, please insert\nthe absolute path to the project or leave blank >`,
initial: config.photowall_repo,
})).run();
initial: config.photowall_repo
}).run();
print.info(`
${JSON.stringify(config)}
`);
if (await (new Confirm({
message: `Ok to save the these settings to ${chalk.yellow(`~/.pwcli_settings`)}?`
})).run()) {
if (
await new Confirm({
message: `Ok to save the these settings to ${chalk.yellow(
`~/.pwcli_settings`
)}?`
}).run()
) {
await system.run(`echo '${JSON.stringify(config)}' > ~/.pwcli_settings`);
} else {
print.info('Ok then.');
if (toolbox.fromMenu()) await toolbox.menu.showMenu(null, defaultMenuSettings);
if (toolbox.fromMenu())
await toolbox.menu.showMenu(null, defaultMenuSettings);
}
if (toolbox.fromMenu()) await toolbox.menu.showMenu(null, defaultMenuSettings);
if (toolbox.fromMenu())
await toolbox.menu.showMenu(null, defaultMenuSettings);
}
};
+33 -11
View File
@@ -2,9 +2,14 @@ import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import { Octokit } from '@octokit/core';
import chalk = require('chalk');
import { system } from 'gluegun';
import { confirmMessage, defaultMenuSettings, getSettings, issueToBranchName } from '../../../globals';
import { createPullRequest, getIssueFromRepo, getOpenIssuesFromRepo, getOrgIssues, getOrgRepos } from '../../../services/github_rest';
const { AutoComplete, Confirm, Input } = require('enquirer');
import {
confirmMessage,
defaultMenuSettings,
getSettings,
issueToBranchName
} from '../../../globals';
import { getIssueFromRepo, getOrgIssues } from '../../../services/github_rest';
const { AutoComplete } = require('enquirer');
module.exports = {
name: 'SetupIssue',
@@ -12,7 +17,6 @@ module.exports = {
description: 'Setup everything for a issue (si)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
const { print, system, strings } = toolbox;
// Load settings
@@ -24,8 +28,10 @@ module.exports = {
const repos = await getOrgIssues(toolbox, config.gh_token);
const issueOptions = repos.flatMap(repo => {
return repo.issues.map(issue => `${issue.number}-${repo.repo}-${issue.title}`);
})
return repo.issues.map(
issue => `${issue.number}-${repo.repo}-${issue.title}`
);
});
const promptIssues = new AutoComplete({
name: 'issues',
@@ -38,14 +44,30 @@ module.exports = {
const issueNumber = issueResponse.split('-')[0];
const repo = issueResponse.split('-')[1];
const issueData = await getIssueFromRepo(toolbox, config.gh_token, repo, issueNumber);
const issueData = await getIssueFromRepo(
toolbox,
config.gh_token,
repo,
issueNumber
);
const branchName = issueToBranchName(issueData);
if (await confirmMessage(`Create new branch ${chalk.yellow(branchName)} from origin/master?`)) {
await system.run(`git checkout -b ${branchName} origin/master`, {cwd: config.photowall_repo, trim: true});
await system.run(`git push -u origin ${branchName}`, {cwd: config.photowall_repo, trim: true});
if (
await confirmMessage(
`Create new branch ${chalk.yellow(branchName)} from origin/master?`
)
) {
await system.run(`git checkout -b ${branchName} origin/master`, {
cwd: config.photowall_repo,
trim: true
});
await system.run(`git push -u origin ${branchName}`, {
cwd: config.photowall_repo,
trim: true
});
}
if (toolbox.fromMenu()) await toolbox.menu.showMenu('workflow', defaultMenuSettings);
if (toolbox.fromMenu())
await toolbox.menu.showMenu('workflow', defaultMenuSettings);
}
};
+4 -6
View File
@@ -1,13 +1,11 @@
import { GluegunToolbox } from 'gluegun'
import { GluegunToolbox } from 'gluegun';
// add your CLI-specific functionality here, which will then be accessible
// to your commands
module.exports = (toolbox: GluegunToolbox) => {
toolbox.foo = () => {
toolbox.print.info('called foo extension')
}
toolbox.print.info('called foo extension');
};
// enable this if you want to read configuration in from
// the current folder's package.json (in a "pwcli" property),
@@ -16,4 +14,4 @@ module.exports = (toolbox: GluegunToolbox) => {
// ...toolbox.config,
// ...toolbox.config.loadConfig("pwcli", process.cwd())
// }
}
};
+3 -3
View File
@@ -66,6 +66,6 @@ export const confirmMessage = async (message: string) => {
}
};
export const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
export const sleep = milliseconds => {
return new Promise(resolve => setTimeout(resolve, milliseconds));
};
+37 -26
View File
@@ -1,12 +1,12 @@
import { Octokit } from "@octokit/core";
import { Octokit } from '@octokit/core';
export const getOrgRepos = async (toolbox, token, org) => {
const { print } = toolbox;
const octokit = new Octokit({ auth: token });
try {
const response = await octokit.request("GET /orgs/{org}/repos", {
const response = await octokit.request('GET /orgs/{org}/repos', {
org: org,
per_page: 100,
per_page: 100
});
if (response.status === 200) {
return response.data;
@@ -21,9 +21,9 @@ export const getRepo = async (toolbox, token, owner, repo) => {
const { print } = toolbox;
const octokit = new Octokit({ auth: token });
try {
const response = await octokit.request("GET /repos/{owner}/{repo}", {
const response = await octokit.request('GET /repos/{owner}/{repo}', {
owner: owner,
repo: repo,
repo: repo
});
if (response.status === 200) {
return response.data;
@@ -32,19 +32,22 @@ export const getRepo = async (toolbox, token, owner, repo) => {
print.error('Not a valid organisation for your token access');
return null;
}
}
};
export const getRepoBranches = async (toolbox, token, owner, repo) => {
const { print } = toolbox;
const octokit = new Octokit({ auth: token });
const getBranches = async (toolbox, token, owner, repo, page) => {
const response = await octokit.request("GET /repos/{owner}/{repo}/branches", {
const response = await octokit.request(
'GET /repos/{owner}/{repo}/branches',
{
owner: owner,
repo: repo,
page: page,
per_page: 100,
});
per_page: 100
}
);
return response;
};
@@ -62,29 +65,31 @@ export const getRepoBranches = async (toolbox, token, owner, repo) => {
}
return allBranches;
}
};
export const getOrgIssues = async (toolbox, token) => {
// const { print } = toolbox;
const repos = await getOrgRepos(toolbox, token, 'Photowall');
const repoNames = repos.map(item => item.name);
const allIssues = await Promise.all(repoNames.map(async (repoName) => {
const allIssues = await Promise.all(
repoNames.map(async repoName => {
const issues = await getOpenIssuesFromRepo(toolbox, token, repoName);
// console.log(`${repoName} - issues`, issues.length);
// return issues.map(item => `${item.number}-${item.title.substring(0, 10)}`);
return { repo: repoName, issues: issues };
}));
})
);
return allIssues.flat();
}
};
export const getOpenIssuesFromRepo = async (toolbox, token, repo) => {
const { print } = toolbox;
const octokit = new Octokit({ auth: token });
try {
const response = await octokit.request("GET /repos/{owner}/{repo}/issues", {
owner: "Photowall",
const response = await octokit.request('GET /repos/{owner}/{repo}/issues', {
owner: 'Photowall',
repo: repo,
per_page: 100,
per_page: 100
});
if (response.status === 200) {
return response.data;
@@ -93,17 +98,20 @@ export const getOpenIssuesFromRepo = async (toolbox, token, repo) => {
print.error('Not a valid issuenumber for this repository');
return null;
}
}
};
export const getIssueFromRepo = async (toolbox, token, repo, issueNumber) => {
const { print } = toolbox;
const octokit = new Octokit({ auth: token });
try {
const response = await octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}", {
owner: "Photowall",
const response = await octokit.request(
'GET /repos/{owner}/{repo}/issues/{issue_number}',
{
owner: 'Photowall',
repo: repo,
issue_number: issueNumber,
});
issue_number: issueNumber
}
);
if (response.status === 200) {
return response.data;
}
@@ -111,9 +119,14 @@ export const getIssueFromRepo = async (toolbox, token, repo, issueNumber) => {
print.error('Not a valid issuenumber for this repository');
return null;
}
}
};
export const createPullRequest = async (toolbox, token: string, repo: string, branch: string) => {
export const createPullRequest = async (
toolbox,
token: string,
repo: string,
branch: string
) => {
const { print } = toolbox;
const octokit = new Octokit({ auth: token });
try {
@@ -131,6 +144,4 @@ export const createPullRequest = async (toolbox, token: string, repo: string, br
print.error('Not a valid branch');
return null;
}
}
};
+4 -1
View File
@@ -1,5 +1,8 @@
{
"compilerOptions": {
"esModuleInterop": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false,
"allowSyntheticDefaultImports": false,
"experimentalDecorators": true,
"lib": [
@@ -19,7 +22,7 @@
"inlineSourceMap": true,
"outDir": "build",
"strict": false,
"target": "es5",
"target": "es2020",
"declaration": true,
"declarationDir": "build/types"
},
+638 -110
View File
File diff suppressed because it is too large Load Diff