first commit

This commit is contained in:
Arwid Thornström
2022-01-19 07:28:09 +01:00
commit f55052d5b3
40 changed files with 6193 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
.DS_Store
node_modules
+16
View File
@@ -0,0 +1,16 @@
const { system, filesystem } = require('gluegun')
const src = filesystem.path(__dirname, '..')
const cli = async cmd =>
system.run('node ' + filesystem.path(src, 'bin', 'pwcli') + ` ${cmd}`)
test('outputs version', async () => {
const output = await cli('--version')
expect(output).toContain('0.0.1')
})
test('outputs help', async () => {
const output = await cli('--help')
expect(output).toContain('0.0.1')
})
Executable
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env node
/* tslint:disable */
// check if we're running in dev mode
var devMode = require('fs').existsSync(`${__dirname}/../src`)
// or want to "force" running the compiled version with --compiled-build
var wantsCompiled = process.argv.indexOf('--compiled-build') >= 0
if (wantsCompiled || !devMode) {
// this runs from the compiled javascript source
require(`${__dirname}/../build/cli`).run(process.argv)
} else {
// this runs from the typescript source (for dev only)
// hook into ts-node so we can run typescript on the fly
require('ts-node').register({ project: `${__dirname}/../tsconfig.json` })
// run the CLI with the current process arguments
require(`${__dirname}/../src/cli`).run(process.argv)
}
+172
View File
@@ -0,0 +1,172 @@
var __awaiter =
(this && this.__awaiter) ||
function(thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P
? value
: new P(function(resolve) {
resolve(value)
})
}
return new (P || (P = Promise))(function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value))
} catch (e) {
reject(e)
}
}
function rejected(value) {
try {
step(generator['throw'](value))
} catch (e) {
reject(e)
}
}
function step(result) {
result.done
? resolve(result.value)
: adopt(result.value).then(fulfilled, rejected)
}
step((generator = generator.apply(thisArg, _arguments || [])).next())
})
}
var __generator =
(this && this.__generator) ||
function(thisArg, body) {
var _ = {
label: 0,
sent: function() {
if (t[0] & 1) throw t[1]
return t[1]
},
trys: [],
ops: []
},
f,
y,
t,
g
return (
(g = { next: verb(0), throw: verb(1), return: verb(2) }),
typeof Symbol === 'function' &&
(g[Symbol.iterator] = function() {
return this
}),
g
)
function verb(n) {
return function(v) {
return step([n, v])
}
}
function step(op) {
if (f) throw new TypeError('Generator is already executing.')
while (_)
try {
if (
((f = 1),
y &&
(t =
op[0] & 2
? y['return']
: op[0]
? y['throw'] || ((t = y['return']) && t.call(y), 0)
: y.next) &&
!(t = t.call(y, op[1])).done)
)
return t
if (((y = 0), t)) op = [op[0] & 2, t.value]
switch (op[0]) {
case 0:
case 1:
t = op
break
case 4:
_.label++
return { value: op[1], done: false }
case 5:
_.label++
y = op[1]
op = [0]
continue
case 7:
op = _.ops.pop()
_.trys.pop()
continue
default:
if (
!((t = _.trys), (t = t.length > 0 && t[t.length - 1])) &&
(op[0] === 6 || op[0] === 2)
) {
_ = 0
continue
}
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
_.label = op[1]
break
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1]
t = op
break
}
if (t && _.label < t[2]) {
_.label = t[2]
_.ops.push(op)
break
}
if (t[2]) _.ops.pop()
_.trys.pop()
continue
}
op = body.call(thisArg, _)
} catch (e) {
op = [6, e]
y = 0
} finally {
f = t = 0
}
if (op[0] & 5) throw op[1]
return { value: op[0] ? op[1] : void 0, done: true }
}
}
var build = require('gluegun').build
/**
* Create the cli and kick it off
*/
function run(argv) {
return __awaiter(this, void 0, void 0, function() {
var cli, toolbox
return __generator(this, function(_a) {
switch (_a.label) {
case 0:
cli = build()
.brand('pwcli')
.src(__dirname)
.plugins('./node_modules', { matching: 'pwcli-*', hidden: true })
.plugin(
__dirname + '/../node_modules/@lenne.tech/gluegun-menu/dist',
{
commandFilePattern: '*.js',
extensionFilePattern: '*.js'
}
)
.help() // provides default for help, h, --help, -h
.version() // provides default for version, v, --version, -v
.create()
return [
4 /*yield*/,
cli.run(argv)
// send it back (for testing, mostly)
]
case 1:
toolbox = _a.sent()
// send it back (for testing, mostly)
return [2 /*return*/, toolbox]
}
})
})
}
module.exports = { run: run }
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBUSxJQUFBLEtBQUssR0FBSyxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQXZCLENBQXVCO0FBRXBDOztHQUVHO0FBQ0gsU0FBZSxHQUFHLENBQUMsSUFBSTs7Ozs7O29CQUVmLEdBQUcsR0FBRyxLQUFLLEVBQUU7eUJBQ2hCLEtBQUssQ0FBQyxPQUFPLENBQUM7eUJBQ2QsR0FBRyxDQUFDLFNBQVMsQ0FBQzt5QkFDZCxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQzt5QkFDaEUsTUFBTSxDQUFDLFNBQVMsR0FBRyxnREFBZ0QsRUFBRTt3QkFDcEUsa0JBQWtCLEVBQUUsTUFBTTt3QkFDMUIsb0JBQW9CLEVBQUUsTUFBTTtxQkFDN0IsQ0FBQzt5QkFDRCxJQUFJLEVBQUUsQ0FBQywyQ0FBMkM7eUJBQ2xELE9BQU8sRUFBRSxDQUFDLGlEQUFpRDt5QkFDM0QsTUFBTSxFQUFFLENBQUE7b0JBS0sscUJBQU0sR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7d0JBRW5DLHFDQUFxQztzQkFGRjs7b0JBQTdCLE9BQU8sR0FBRyxTQUFtQjtvQkFFbkMscUNBQXFDO29CQUNyQyxzQkFBTyxPQUFPLEVBQUE7Ozs7Q0FDZjtBQUVELE1BQU0sQ0FBQyxPQUFPLEdBQUcsRUFBRSxHQUFHLEtBQUEsRUFBRSxDQUFBIn0=
+55
View File
@@ -0,0 +1,55 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
module.exports = {
name: 'deployment',
alias: ['d'],
description: 'Description for deployment',
hidden: true,
run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, toolbox.menu.showMenu('deployment')];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); }
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21tYW5kcy9kZXBsb3ltZW50L2RlcGxveW1lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFQSxNQUFNLENBQUMsT0FBTyxHQUFHO0lBQ2YsSUFBSSxFQUFFLFlBQVk7SUFDbEIsS0FBSyxFQUFFLENBQUMsR0FBRyxDQUFDO0lBQ1osV0FBVyxFQUFFLDRCQUE0QjtJQUN6QyxNQUFNLEVBQUUsSUFBSTtJQUNaLEdBQUcsRUFBRSxVQUFPLE9BQTJCOzs7d0JBQ3JDLHFCQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxFQUFBOztvQkFBekMsU0FBeUMsQ0FBQzs7OztTQUMzQztDQUNGLENBQUMifQ==
@@ -0,0 +1,155 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var cliSelect = require('cli-select');
var chalk = require('chalk');
var AutoComplete = require('enquirer').AutoComplete;
var STACK_DEFAULTS = {
STACK_ENVIRONMENT_NAME_TAG: 'test',
CPU_SIZE: 512,
MEMORY_SIZE: '1GB',
HOSTED_ZONE_WITHOUT_TLD: 'photowall-test',
PRIMARY_CERTIFICATE_ARN: 'arn:aws:acm:eu-west-1:954747537408:certificate/12e33b74-da14-430d-a7ed-f62fa7113112',
STATIC_CDN_CERTIFICATE_ARN: 'arn:aws:acm:us-east-1:954747537408:certificate/223550cf-e404-4ff1-85bb-703b936c9347',
DB_SECURITY_GROUP_ID: 'sg-001b3667edf19e1ce',
STATIC_CDN_HOSTNAME: 'staging.assets.photowall-test.com',
MAX_CONTAINERS: 1,
MIN_CONTAINERS: 1,
AWS_KEY_ENVIRONMENT: 'staging'
};
var createCloudFormationCommand = function (environmentName, branch) {
return "aws cloudformation update-stack --stack-name " + environmentName + " --template-body file://ecs-service.yaml \n\t\t--capabilities CAPABILITY_NAMED_IAM\n --tags Key=EnvironmentName,Value=test \n\t\t--parameters \n ParameterKey=\"EnvironmentName\",UsePreviousValue=true \n ParameterKey=\"Image\",UsePreviousValue=true \n ParameterKey=\"HostedZoneNameWithOutTLD\",UsePreviousValue=true \n ParameterKey=\"DomainNameWithoutTld\",UsePreviousValue=true \n ParameterKey=\"PrimaryCertificateArn\",UsePreviousValue=true \n ParameterKey=\"GitHubRepo\",UsePreviousValue=true \n ParameterKey=\"GitHubUser\",UsePreviousValue=true \n ParameterKey=\"GitHubBranch\",ParameterValue=\"" + branch + "\" \n ParameterKey=\"GitHubToken\",UsePreviousValue=true \n ParameterKey=\"ComposerAuth\",UsePreviousValue=true \n ParameterKey=\"CpuSize\",ParameterValue=\"" + STACK_DEFAULTS.CPU_SIZE + "\" \n ParameterKey=\"MemorySize\",ParameterValue=\"" + STACK_DEFAULTS.MEMORY_SIZE + "\" \n ParameterKey=\"MinContainers\",ParameterValue=\"" + STACK_DEFAULTS.MIN_CONTAINERS + "\" \n ParameterKey=\"MaxContainers\",ParameterValue=\"" + STACK_DEFAULTS.MAX_CONTAINERS + "\" \n ParameterKey=\"StaticCdnHostName\",ParameterValue=\"" + STACK_DEFAULTS.STATIC_CDN_HOSTNAME + "\" \n ParameterKey=\"StaticCdnCertificateArn\",ParameterValue=\"" + STACK_DEFAULTS.STATIC_CDN_CERTIFICATE_ARN + "\" \n ParameterKey=\"AwsAccessKeyParamNameEnvironment\",ParameterValue=\"" + STACK_DEFAULTS.AWS_KEY_ENVIRONMENT + "\" \n ParameterKey=\"DatabaseSecurityGroup\",ParameterValue=\"" + STACK_DEFAULTS.DB_SECURITY_GROUP_ID + "\"";
};
/**
* Subsection1 menu
*/
module.exports = {
name: 'deploy',
alias: ['d'],
description: 'Deploy current branch to a testserver',
hidden: true,
run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
var system, strings, stacks, _a, _b, _c, _d, teststacks, curratedStacks, options, prompt, choice, branch, _e, _f, cmd, e_1;
return __generator(this, function (_g) {
switch (_g.label) {
case 0:
system = toolbox.system, strings = toolbox.strings;
_b = (_a = JSON).parse;
_d = (_c = strings).trim;
return [4 /*yield*/, system.run("aws cloudformation list-stacks")];
case 1:
stacks = _b.apply(_a, [_d.apply(_c, [_g.sent()])]);
return [4 /*yield*/, Promise.all(stacks.StackSummaries.map(function (item) { return __awaiter(void 0, void 0, void 0, function () {
var pipeline, _a, _b, _c, _d, branch, lastUpdated;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (!(item.StackName.indexOf('photowall-test-') > -1 &&
[
'CREATE_COMPLETE',
'UPDATE_COMPLETE',
'UPDATE_IN_PROGRESS',
'UPDATE_FAILED',
'CREATE_FAILED',
'CREATE_IN_PROGRESS'
].includes(item.StackStatus))) return [3 /*break*/, 2];
_b = (_a = JSON).parse;
_d = (_c = strings).trim;
return [4 /*yield*/, system.run("aws codepipeline get-pipeline --name " + item.StackName + "Pipeline")];
case 1:
pipeline = _b.apply(_a, [_d.apply(_c, [_e.sent()])]);
branch = pipeline.pipeline.stages.filter(function (stage) {
return stage.name === 'Source';
})[0].actions[0].configuration.Branch;
lastUpdated = pipeline.metadata.updated;
return [2 /*return*/, {
name: item.StackName,
status: item.StackStatus,
drift_status: item.DriftInformation.StackDriftStatus,
branch: branch,
updated: lastUpdated
}];
case 2: return [2 /*return*/, Promise.resolve(null)];
}
});
}); }))];
case 2:
teststacks = _g.sent();
curratedStacks = teststacks.filter(Boolean);
options = curratedStacks.map(function (item) {
return item.name;
});
console.log("options", options);
prompt = new AutoComplete({
name: 'testserver',
message: 'Choose a server',
limit: options.length - 1,
initial: options.length - 1,
choices: options
});
_g.label = 3;
case 3:
_g.trys.push([3, 6, , 7]);
return [4 /*yield*/, prompt.run()];
case 4:
choice = _g.sent();
console.log("choice", choice);
_f = (_e = strings).trim;
return [4 /*yield*/, system.run("git branch --show-current")];
case 5:
branch = _f.apply(_e, [_g.sent()]);
console.log("branch", branch);
cmd = createCloudFormationCommand(choice, branch);
console.log("cmd", cmd);
return [3 /*break*/, 7];
case 6:
e_1 = _g.sent();
console.log("e", e_1);
return [3 /*break*/, 7];
case 7:
if (!toolbox.fromMenu()) return [3 /*break*/, 9];
return [4 /*yield*/, toolbox.menu.showMenu('deployment testservers')];
case 8:
_g.sent();
_g.label = 9;
case 9: return [2 /*return*/];
}
});
}); }
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2RlcGxveW1lbnQvdGVzdHNlcnZlcnMvZGVwbG95L2RlcGxveS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLElBQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQUN2QyxJQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDdEIsSUFBQSxZQUFZLEdBQUssT0FBTyxDQUFDLFVBQVUsQ0FBQyxhQUF4QixDQUF3QjtBQUU1QyxJQUFNLGNBQWMsR0FBRztJQUNyQiwwQkFBMEIsRUFBRSxNQUFNO0lBQ2xDLFFBQVEsRUFBRSxHQUFHO0lBQ2IsV0FBVyxFQUFFLEtBQUs7SUFDbEIsdUJBQXVCLEVBQUUsZ0JBQWdCO0lBQ3pDLHVCQUF1QixFQUNyQixxRkFBcUY7SUFDdkYsMEJBQTBCLEVBQ3hCLHFGQUFxRjtJQUN2RixvQkFBb0IsRUFBRSxzQkFBc0I7SUFDNUMsbUJBQW1CLEVBQUUsbUNBQW1DO0lBQ3hELGNBQWMsRUFBRSxDQUFDO0lBQ2pCLGNBQWMsRUFBRSxDQUFDO0lBQ2pCLG1CQUFtQixFQUFFLFNBQVM7Q0FDL0IsQ0FBQTtBQVVELElBQU0sMkJBQTJCLEdBQUcsVUFBQyxlQUFlLEVBQUUsTUFBTTtJQUMxRCxPQUFPLGtEQUFnRCxlQUFlLHluQkFXdEIsTUFBTSw4S0FHWCxjQUFjLENBQUMsUUFBUSw4REFDcEIsY0FBYyxDQUFDLFdBQVcsaUVBQ3ZCLGNBQWMsQ0FBQyxjQUFjLGlFQUM3QixjQUFjLENBQUMsY0FBYyxxRUFDekIsY0FBYyxDQUFDLG1CQUFtQiwyRUFDNUIsY0FBYyxDQUFDLDBCQUEwQixvRkFDaEMsY0FBYyxDQUFDLG1CQUFtQix5RUFDN0MsY0FBYyxDQUFDLG9CQUFvQixPQUFHLENBQUE7QUFDakcs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
@@ -0,0 +1,120 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var chalk = require('chalk');
var tto = require('terminal-table-output').create();
/**
* Subsection1 menu
*/
module.exports = {
name: 'status',
alias: ['s'],
description: 'Show status for available testservers',
hidden: true,
run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
var system, strings, stacks, _a, _b, _c, _d, teststacks, curratedStacks, status, _i, curratedStacks_1, stack;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
system = toolbox.system, strings = toolbox.strings;
_b = (_a = JSON).parse;
_d = (_c = strings).trim;
return [4 /*yield*/, system.run("aws cloudformation list-stacks")];
case 1:
stacks = _b.apply(_a, [_d.apply(_c, [_e.sent()])]);
return [4 /*yield*/, Promise.all(stacks.StackSummaries.map(function (item) { return __awaiter(void 0, void 0, void 0, function () {
var pipeline, _a, _b, _c, _d, branch, lastUpdated;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (!(item.StackName.indexOf('photowall-test-') > -1 && ['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'UPDATE_IN_PROGRESS', 'UPDATE_FAILED', 'CREATE_FAILED', 'CREATE_IN_PROGRESS'].includes(item.StackStatus))) return [3 /*break*/, 2];
_b = (_a = JSON).parse;
_d = (_c = strings).trim;
return [4 /*yield*/, system.run("aws codepipeline get-pipeline --name " + item.StackName + "Pipeline")];
case 1:
pipeline = _b.apply(_a, [_d.apply(_c, [_e.sent()])]);
branch = pipeline.pipeline.stages.filter(function (stage) {
return stage.name === 'Source';
})[0].actions[0].configuration.Branch;
lastUpdated = pipeline.metadata.updated;
return [2 /*return*/, {
name: item.StackName,
status: item.StackStatus,
drift_status: item.DriftInformation.StackDriftStatus,
branch: branch,
updated: lastUpdated,
}];
case 2: return [2 /*return*/, Promise.resolve(null)];
}
});
}); }))];
case 2:
teststacks = _e.sent();
curratedStacks = teststacks.filter(Boolean);
status = function (status) {
switch (status) {
case 'UPDATE_FAILED':
case 'CREATE_FAILED':
return " (\uD83D\uDC94) ";
case 'UPDATE_IN_PROGRESS':
case 'CREATE_IN_PROGRESS':
return " (\uD83D\uDFE1) ";
case 'UPDATE_COMPLETE':
case 'CREATE_COMPLETE':
return " (\uD83D\uDFE2) ";
}
};
tto.line('-');
tto.pushrow(['| status', 'stack', 'branch', 'updated'])
.line('-');
for (_i = 0, curratedStacks_1 = curratedStacks; _i < curratedStacks_1.length; _i++) {
stack = curratedStacks_1[_i];
tto.pushrow([status(stack.status), stack.name, stack.branch, stack.updated]);
}
tto.print(true);
if (!toolbox.fromMenu()) return [3 /*break*/, 4];
return [4 /*yield*/, toolbox.menu.showMenu('deployment testservers')];
case 3:
_e.sent();
_e.label = 4;
case 4: return [2 /*return*/];
}
});
}); }
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdHVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2RlcGxveW1lbnQvdGVzdHNlcnZlcnMvc3RhdHVzL3N0YXR1cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLElBQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUMvQixJQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQVV0RDs7R0FFRztBQUNILE1BQU0sQ0FBQyxPQUFPLEdBQUc7SUFDZixJQUFJLEVBQUUsUUFBUTtJQUNkLEtBQUssRUFBRSxDQUFDLEdBQUcsQ0FBQztJQUNaLFdBQVcsRUFBRSx1Q0FBdUM7SUFDcEQsTUFBTSxFQUFFLElBQUk7SUFDWixHQUFHLEVBQUUsVUFBTyxPQUEyQjs7Ozs7b0JBRTdCLE1BQU0sR0FBYyxPQUFPLE9BQXJCLEVBQUUsT0FBTyxHQUFLLE9BQU8sUUFBWixDQUFZO29CQUVwQixLQUFBLENBQUEsS0FBQSxJQUFJLENBQUEsQ0FBQyxLQUFLLENBQUE7b0JBQUMsS0FBQSxDQUFBLEtBQUEsT0FBTyxDQUFBLENBQUMsSUFBSSxDQUFBO29CQUFDLHFCQUFNLE1BQU0sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLENBQUMsRUFBQTs7b0JBQW5GLE1BQU0sR0FBRyxjQUFXLGNBQWEsU0FBa0QsRUFBQyxFQUFDO29CQUMvRCxxQkFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLFVBQU8sSUFBSTs7Ozs7NkNBQzdFLENBQUEsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLG9CQUFvQixFQUFFLGVBQWUs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
@@ -0,0 +1,58 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Section1 menu
*/
module.exports = {
name: 'testservers',
alias: ['ts'],
description: 'Deploy to testservers',
hidden: true,
run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, toolbox.menu.showMenu('deployment testservers')];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); }
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdHNlcnZlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tbWFuZHMvZGVwbG95bWVudC90ZXN0c2VydmVycy90ZXN0c2VydmVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE9BQU8sR0FBRztJQUNmLElBQUksRUFBRSxhQUFhO0lBQ25CLEtBQUssRUFBRSxDQUFDLElBQUksQ0FBQztJQUNiLFdBQVcsRUFBRSx1QkFBdUI7SUFDcEMsTUFBTSxFQUFFLElBQUk7SUFDWixHQUFHLEVBQUUsVUFBTyxPQUEyQjs7O3dCQUNyQyxxQkFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyx3QkFBd0IsQ0FBQyxFQUFBOztvQkFBckQsU0FBcUQsQ0FBQzs7OztTQUN2RDtDQUNGLENBQUMifQ==
+58
View File
@@ -0,0 +1,58 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* interactive menu
*/
module.exports = {
name: 'interactive',
alias: ['i'],
description: 'Interactive tree view',
hidden: true,
run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, toolbox.menu.showMenu('deployment')];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); }
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJhY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZHMvaW50ZXJhY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxPQUFPLEdBQUc7SUFDZixJQUFJLEVBQUUsYUFBYTtJQUNuQixLQUFLLEVBQUUsQ0FBQyxHQUFHLENBQUM7SUFDWixXQUFXLEVBQUUsdUJBQXVCO0lBQ3BDLE1BQU0sRUFBRSxJQUFJO0lBQ1osR0FBRyxFQUFFLFVBQU8sT0FBMkI7Ozt3QkFDckMscUJBQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLEVBQUE7O29CQUF6QyxTQUF5QyxDQUFDOzs7O1NBQzNDO0NBQ0YsQ0FBQyJ9
+51
View File
@@ -0,0 +1,51 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var command = {
name: 'pwcli',
run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
var print;
return __generator(this, function (_a) {
print = toolbox.print;
print.info('Welcome to your CLI');
return [2 /*return*/];
});
}); },
};
module.exports = command;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHdjbGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZHMvcHdjbGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFJQSxJQUFNLE9BQU8sR0FBbUI7SUFDOUIsSUFBSSxFQUFFLE9BQU87SUFDYixHQUFHLEVBQUUsVUFBTSxPQUFPOzs7WUFDUixLQUFLLEdBQUssT0FBTyxNQUFaLENBQVk7WUFFekIsS0FBSyxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBOzs7U0FDbEM7Q0FDRixDQUFBO0FBRUQsTUFBTSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUEifQ==
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// add your CLI-specific functionality here, which will then be accessible
// to your commands
module.exports = function (toolbox) {
toolbox.foo = function () {
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),
// pwcli.config.json, etc.
// toolbox.config = {
// ...toolbox.config,
// ...toolbox.config.loadConfig("pwcli", process.cwd())
// }
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWV4dGVuc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9leHRlbnNpb25zL2NsaS1leHRlbnNpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFJQSwwRUFBMEU7QUFDMUUsbUJBQW1CO0FBQ25CLE1BQU0sQ0FBQyxPQUFPLEdBQUcsVUFBQyxPQUF1QjtJQUN2QyxPQUFPLENBQUMsR0FBRyxHQUFHO1FBQ1osT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQTtJQUM1QyxDQUFDLENBQUE7SUFFRCx3REFBd0Q7SUFDeEQsNkRBQTZEO0lBQzdELDBCQUEwQjtJQUMxQixxQkFBcUI7SUFDckIsdUJBQXVCO0lBQ3ZCLHlEQUF5RDtJQUN6RCxJQUFJO0FBQ04sQ0FBQyxDQUFBIn0=
+2
View File
@@ -0,0 +1,2 @@
// export types
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsZUFBZSJ9
+5
View File
@@ -0,0 +1,5 @@
declare const build: any;
/**
* Create the cli and kick it off
*/
declare function run(argv: any): Promise<any>;
+1
View File
@@ -0,0 +1 @@
export {};
@@ -0,0 +1 @@
export {};
@@ -0,0 +1 @@
export {};
@@ -0,0 +1 @@
export {};
+1
View File
@@ -0,0 +1 @@
export {};
+1
View File
@@ -0,0 +1 @@
export {};
+1
View File
@@ -0,0 +1 @@
export {};
View File
+3
View File
@@ -0,0 +1,3 @@
# Command Reference for pwcli
TODO: Add your command reference here
+47
View File
@@ -0,0 +1,47 @@
# Plugin guide for pwcli
Plugins allow you to add features to pwcli, such as commands and
extensions to the `toolbox` object that provides the majority of the functionality
used by pwcli.
Creating a pwcli plugin is easy. Just create a repo with two folders:
```
commands/
extensions/
```
A command is a file that looks something like this:
```js
// commands/foo.js
module.exports = {
run: (toolbox) => {
const { print, filesystem } = toolbox
const desktopDirectories = filesystem.subdirectories(`~/Desktop`)
print.info(desktopDirectories)
}
}
```
An extension lets you add additional features to the `toolbox`.
```js
// extensions/bar-extension.js
module.exports = (toolbox) => {
const { print } = toolbox
toolbox.bar = () => { print.info('Bar!') }
}
```
This is then accessible in your plugin's commands as `toolbox.bar`.
# Loading a plugin
To load a particular plugin (which has to start with `pwcli-*`),
install it to your project using `npm install --save-dev pwcli-PLUGINNAME`,
and pwcli will pick it up automatically.
+62
View File
@@ -0,0 +1,62 @@
{
"name": "pwcli",
"version": "0.0.1",
"description": "pwcli CLI",
"private": true,
"types": "build/types/types.d.ts",
"bin": {
"pwcli": "bin/pwcli"
},
"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",
"prepublishOnly": "yarn build",
"test": "jest",
"watch": "jest --watch",
"snapupdate": "jest --updateSnapshot",
"coverage": "jest --coverage"
},
"files": [
"tsconfig.json",
"tslint.json",
"build",
"LICENSE",
"readme.md",
"docs",
"bin"
],
"license": "MIT",
"dependencies": {
"@lenne.tech/gluegun-menu": "^0.0.5",
"@octokit/core": "^3.5.1",
"chalk": "^4.1.2",
"cli-select": "^1.1.2",
"enquirer": "^2.3.6",
"gluegun": "latest",
"terminal-table-output": "^1.3.2"
},
"devDependencies": {
"@types/jest": "^24.0.18",
"@types/node": "^12.7.11",
"jest": "^24.1.0",
"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": "^3.6.3"
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node"
},
"prettier": {
"semi": false,
"singleQuote": true
}
}
+25
View File
@@ -0,0 +1,25 @@
# pwcli CLI
A CLI for pwcli.
## Customizing your CLI
Check out the documentation at https://github.com/infinitered/gluegun/tree/master/docs.
## Publishing to NPM
To package your CLI up for NPM, do this:
```shell
$ npm login
$ npm whoami
$ npm lint
$ npm test
(if typescript, run `npm run build` here)
$ npm publish
```
# License
MIT - see LICENSE
+35
View File
@@ -0,0 +1,35 @@
const { build } = require('gluegun');
/**
* Create the cli and kick it off
*/
async function run(argv) {
// create a CLI runtime
const cli = build()
.brand('pwcli')
.src(__dirname)
.plugins('./node_modules', { matching: 'pwcli-*', hidden: true })
.plugin(__dirname + '/../node_modules/@lenne.tech/gluegun-menu/dist', {
commandFilePattern: '*.js',
extensionFilePattern: '*.js'
})
.help({
name: 'help',
alias: 'helpmeplease',
hidden: true,
dashed: true,
run: toolbox => toolbox.print.info('No help for you!')
}) // provides default for help, h, --help, -h
.version() // provides default for version, v, --version, -v
.create();
// enable the following method if you'd like to skip loading one of these core extensions
// this can improve performance if they're not necessary for your project:
// .exclude(['meta', 'strings', 'print', 'filesystem', 'semver', 'system', 'prompt', 'http', 'template', 'patching', 'package-manager'])
// and run it
const toolbox = await cli.run(argv);
// send it back (for testing, mostly)
return toolbox;
}
module.exports = { run }
+11
View File
@@ -0,0 +1,11 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
module.exports = {
name: 'deployment',
alias: ['d'],
description: 'Description for deployment (d)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
await toolbox.menu.showMenu('deployment');
}
};
@@ -0,0 +1,251 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
import { Octokit } from "@octokit/core";
import { GluegunPrint } from 'gluegun';
const os = require("os");
const STACK_DEFAULTS = {
STACK_ENVIRONMENT_NAME_TAG: 'test',
CPU_SIZE: 512,
MEMORY_SIZE: '1GB',
HOSTED_ZONE_WITHOUT_TLD: 'photowall-test',
DOMAIN_NAME_WITHOUT_TLD: '.photowall-test',
PRIMARY_CERTIFICATE_ARN:
'arn:aws:acm:eu-west-1:954747537408:certificate/12e33b74-da14-430d-a7ed-f62fa7113112',
STATIC_CDN_CERTIFICATE_ARN:
'arn:aws:acm:us-east-1:954747537408:certificate/223550cf-e404-4ff1-85bb-703b936c9347',
DB_SECURITY_GROUP_ID: 'sg-001b3667edf19e1ce',
GITHUB_REPO: 'photowall',
GITHUB_USER: 'Photowall',
STATIC_CDN_HOSTNAME: `''`,
MAX_CONTAINERS: 1,
MIN_CONTAINERS: 1,
AWS_KEY_ENVIRONMENT: 'staging'
}
type Stack = {
name: string
status: string
drift_status: string
branch: string
updated: string
}
const getDownloadFileFromRepoCommand = (token: string, org: string, repo: string, path: string) => {
const file = path.split('/').pop();
return `curl -o /tmp/${file} -H 'Authorization: token ${token} ' -H 'Accept: application/vnd.github.v3.raw' -O -L https://api.github.com/repos/${org}/${repo}/contents/${path}`;
}
const getCreateStackCommand = (stackName: string, branch: string, templateFile: string, dockerImage: string, githubToken: string, composerAuth: string) => {
const stack = 'photowall';
const stackDomain = stackName.replace('photowall-', '');
const cmd = [
`aws cloudformation create-stack --stack-name ${stackName}`,
`--template-body ${templateFile}`,
`--capabilities CAPABILITY_NAMED_IAM`,
`--tags Key=EnvironmentName,Value=test`,
`--parameters`,
`ParameterKey=EnvironmentName,ParameterValue=${stackDomain}`,
`ParameterKey=Image,ParameterValue=${dockerImage}`,
`ParameterKey=HostedZoneNameWithOutTLD,ParameterValue=${STACK_DEFAULTS.HOSTED_ZONE_WITHOUT_TLD}`,
`ParameterKey=DomainNameWithoutTld,ParameterValue=${stackDomain}${STACK_DEFAULTS.DOMAIN_NAME_WITHOUT_TLD}`,
`ParameterKey=PrimaryCertificateArn,ParameterValue='${STACK_DEFAULTS.PRIMARY_CERTIFICATE_ARN}'`,
`ParameterKey=GitHubRepo,ParameterValue=${STACK_DEFAULTS.GITHUB_REPO}`,
`ParameterKey=GitHubUser,ParameterValue=${STACK_DEFAULTS.GITHUB_USER}`,
`ParameterKey=GitHubBranch,ParameterValue=${branch}`,
`ParameterKey=GitHubToken,ParameterValue=${githubToken}`,
`ParameterKey=ComposerAuth,ParameterValue="${composerAuth}"`,
`ParameterKey=CpuSize,ParameterValue=${STACK_DEFAULTS.CPU_SIZE}`,
`ParameterKey=MemorySize,ParameterValue=${STACK_DEFAULTS.MEMORY_SIZE}`,
`ParameterKey=MinContainers,ParameterValue=${STACK_DEFAULTS.MIN_CONTAINERS}`,
`ParameterKey=MaxContainers,ParameterValue=${STACK_DEFAULTS.MAX_CONTAINERS}`,
`ParameterKey=StaticCdnHostName,ParameterValue=${STACK_DEFAULTS.STATIC_CDN_HOSTNAME}`,
`ParameterKey=StaticCdnCertificateArn,ParameterValue=${STACK_DEFAULTS.STATIC_CDN_CERTIFICATE_ARN}`,
`ParameterKey=AwsAccessKeyParamNameEnvironment,ParameterValue=${STACK_DEFAULTS.AWS_KEY_ENVIRONMENT}`,
`ParameterKey=DatabaseSecurityGroup,ParameterValue=${STACK_DEFAULTS.DB_SECURITY_GROUP_ID}`,
];
return cmd.join(' ');
};
const getBranchName = async (print: GluegunPrint, token: string) => {
const input = new Input({
type: 'input',
name: 'branch',
message: 'What github branch should be deployed?'
});
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 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?`
});
try {
return confirm.run();
} catch (e) {
console.error(e);
return false;
}
}
/**
* Subsection1 menu
*/
module.exports = {
name: 'create',
alias: ['c'],
description: 'Create new testserver on aws (c)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings, print, filesystem } = toolbox;
// Load settings
const config = await filesystem.readAsync(`${os.homedir()}/.pwcli_settings`, "json");
if (!config) {
print.error(`
No config found, please run [ ${chalk.cyan('pwcli s')} ] or setup from the menu.
`);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu()
} else {
return;
}
}
let branchName = null;
while (!branchName) {
branchName = await getBranchName(print, config.gh_token);
}
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 input = new Input({
type: 'input',
name: 'stack',
message: `Insert name of the new stack (${chalk.yellow('photowall-test-xx-x')})`
});
const stackName = await input.run();
if (options.includes(stackName)) {
print.error(`
The stack ${chalk.yellow(stackName)} is already taken, try the update command instead.
`);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers');
}
} else if (stackName.indexOf('photowall-test-') !== 0) {
print.error(`
The stack must begin with ${chalk.yellow('photowall-test-')}.
`);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers');
}
}
try {
const shouldRun = await getConfirmation(branchName, stackName);
if (shouldRun) {
// Download files to /tmp
await system.run(getDownloadFileFromRepoCommand(config.gh_token, 'Photowall', 'photowall', 'cloudformation/ecr-lifecycle-policy.json'));
await system.run(getDownloadFileFromRepoCommand(config.gh_token, 'Photowall', 'photowall', 'cloudformation/ecs-service.yaml'));
const aws_account_id = strings.trim(await system.run(`aws sts get-caller-identity --query Account --output text`));
const aws_region = strings.trim(await system.run(`aws configure get region`));
const github_token = strings.trim(await system.run(`aws ssm get-parameter --with-decryption --name /github/CODE_PIPELINE_TOKEN --output text --query Parameter.Value`));
print.fancy(await system.run(`aws ecr create-repository --repository ${stackName}`));
print.fancy(await system.run(`aws ecr get-login-password --region ${aws_region} | docker login --username AWS --password-stdin ${aws_account_id}.dkr.ecr.${aws_region}.amazonaws.com`));
print.fancy(await system.run(`docker pull nginx`));
print.fancy(await system.run(`docker tag nginx ${aws_account_id}.dkr.ecr.${aws_region}.amazonaws.com/${stackName}:latest`));
print.fancy(await system.run(`docker push ${aws_account_id}.dkr.ecr.${aws_region}.amazonaws.com/${stackName}:latest`));
const dockerImage = `${aws_account_id}.dkr.ecr.${aws_region}.amazonaws.com/${stackName}`;
let composerAuthToken = await system.run(`aws ssm get-parameter --with-decryption --name /github/COMPOSER_TOKEN --output text --query Parameter.Value`);
composerAuthToken = composerAuthToken.replace('\n', '');
const composer_auth = `'{\"github-oauth\":{\"github.com\":\"${composerAuthToken}\"}}'`;
const createCommand = getCreateStackCommand(stackName, branchName, 'file://ecs-service.yaml', dockerImage, github_token, composer_auth);
print.fancy(await system.run(createCommand, {cwd: '/tmp/', trim: true}));
}
} catch (e) {
console.log(`e`, e)
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers')
}
}
}
@@ -0,0 +1,136 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
import { GluegunSystem, print } from 'gluegun';
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
type Stack = {
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')}`
});
try {
return confirm.run();
} catch (e) {
return false;
}
}
const confirmCommand = async (cmd: string) => {
const confirm = new Confirm({
name: 'confirm',
message: `RUN COMMAND > [${chalk.yellow(cmd)}] ?`,
});
try {
const resp = await confirm.run();
if (resp) {
return cmd;
}
return null;
} catch (e) {
return null;
}
}
const runCommand = async (system: GluegunSystem, cmd : string | null) => {
if (cmd) {
return system.run(cmd);
}
return null;
};
/**
* Subsection1 menu
*/
module.exports = {
name: 'delete',
alias: ['d'],
description: 'Choose a testserver to delete (d)',
hidden: true,
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 (
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
});
const stackName = await prompt.run();
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');
for (const artifact of artifacts) {
await runCommand(system, await confirmCommand(`aws s3 rb --force s3://${artifact}`));
}
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers');
}
}
}
@@ -0,0 +1,71 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
const tto = require('terminal-table-output').create();
type Stack = {
name: string,
status: string,
drift_status: string,
branch: string,
updated: string,
};
/**
* Subsection1 menu
*/
module.exports = {
name: 'status',
alias: ['s'],
description: 'Show status for available testservers (s)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
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 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 status = (status: string) => {
switch(status) {
case 'UPDATE_FAILED':
case 'CREATE_FAILED':
return ` (💔) `;
case 'UPDATE_IN_PROGRESS':
case 'CREATE_IN_PROGRESS':
return ` (🟡) `;
case 'UPDATE_COMPLETE':
case 'CREATE_COMPLETE':
return ` (🟢) `;
}
}
tto.line('-');
tto.pushrow(['| status', 'stack', 'branch', 'updated'])
.line('-');
for (const stack of curratedStacks) {
tto.pushrow([status(stack.status), stack.name, stack.branch, stack.updated]);
}
tto.print(true);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers');
}
}
}
@@ -0,0 +1,14 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
/**
* Section1 menu
*/
module.exports = {
name: 'testservers',
alias: ['ts'],
description: 'Deploy to testservers (ts)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
await toolbox.menu.showMenu('deployment testservers');
}
};
@@ -0,0 +1,221 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
import { Octokit } from "@octokit/core";
import { GluegunPrint } from 'gluegun';
const os = require("os");
const STACK_DEFAULTS = {
STACK_ENVIRONMENT_NAME_TAG: 'test',
CPU_SIZE: 512,
MEMORY_SIZE: '1GB',
HOSTED_ZONE_WITHOUT_TLD: 'photowall-test',
PRIMARY_CERTIFICATE_ARN:
'arn:aws:acm:eu-west-1:954747537408:certificate/12e33b74-da14-430d-a7ed-f62fa7113112',
STATIC_CDN_CERTIFICATE_ARN:
'arn:aws:acm:us-east-1:954747537408:certificate/223550cf-e404-4ff1-85bb-703b936c9347',
DB_SECURITY_GROUP_ID: 'sg-001b3667edf19e1ce',
STATIC_CDN_HOSTNAME: `''`,
MAX_CONTAINERS: 1,
MIN_CONTAINERS: 1,
AWS_KEY_ENVIRONMENT: 'staging'
}
type Stack = {
name: string
status: string
drift_status: string
branch: string
updated: string
}
const getDownloadFileFromRepoCommand = (token: string, org: string, repo: string, path: string) => {
const file = path.split('/').pop();
return `curl -o /tmp/${file} -H 'Authorization: token ${token} ' -H 'Accept: application/vnd.github.v3.raw' -O -L https://api.github.com/repos/${org}/${repo}/contents/${path}`;
}
const getLifeCyclePolicyCommand = (stackName: string, policyFile: string) => {
return `aws ecr put-lifecycle-policy --repository-name ${stackName} --lifecycle-policy-text "${policyFile}"`;
}
const getUpdateStackCommand = (stackName: string, branch: string, templateFile: string) => {
const cmd = [
`aws cloudformation update-stack --stack-name ${stackName}`,
`--template-body ${templateFile}`,
`--capabilities CAPABILITY_NAMED_IAM`,
`--tags Key=EnvironmentName,Value=test`,
`--parameters`,
`ParameterKey=EnvironmentName,UsePreviousValue=true`,
`ParameterKey=Image,UsePreviousValue=true`,
`ParameterKey=HostedZoneNameWithOutTLD,UsePreviousValue=true`,
`ParameterKey=DomainNameWithoutTld,UsePreviousValue=true`,
`ParameterKey=PrimaryCertificateArn,UsePreviousValue=true`,
`ParameterKey=GitHubRepo,UsePreviousValue=true`,
`ParameterKey=GitHubUser,UsePreviousValue=true`,
`ParameterKey=GitHubBranch,ParameterValue=${branch}`,
`ParameterKey=GitHubToken,UsePreviousValue=true`,
`ParameterKey=ComposerAuth,UsePreviousValue=true`,
`ParameterKey=CpuSize,ParameterValue=${STACK_DEFAULTS.CPU_SIZE}`,
`ParameterKey=MemorySize,ParameterValue=${STACK_DEFAULTS.MEMORY_SIZE}`,
`ParameterKey=MinContainers,ParameterValue=${STACK_DEFAULTS.MIN_CONTAINERS}`,
`ParameterKey=MaxContainers,ParameterValue=${STACK_DEFAULTS.MAX_CONTAINERS}`,
`ParameterKey=StaticCdnHostName,ParameterValue=${STACK_DEFAULTS.STATIC_CDN_HOSTNAME}`,
`ParameterKey=StaticCdnCertificateArn,ParameterValue=${STACK_DEFAULTS.STATIC_CDN_CERTIFICATE_ARN}`,
`ParameterKey=AwsAccessKeyParamNameEnvironment,ParameterValue=${STACK_DEFAULTS.AWS_KEY_ENVIRONMENT}`,
`ParameterKey=DatabaseSecurityGroup,ParameterValue=${STACK_DEFAULTS.DB_SECURITY_GROUP_ID}`
];
return cmd.join(' ');
}
const getBranchName = async (print: GluegunPrint, token: string) => {
const input = new Input({
type: 'input',
name: 'branch',
message: 'What github branch should be deployed?'
});
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;
}
}
/**
* Subsection1 menu
*/
module.exports = {
name: 'update',
alias: ['u'],
description: 'Update stack with different branch (u)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings, print, filesystem } = toolbox;
// Load settings
const config = await filesystem.readAsync(`${os.homedir()}/.pwcli_settings`, "json");
if (!config) {
print.error(`
No config found, please run [ ${chalk.cyan('pwcli s')} ] or setup from the menu.
`);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu()
} else {
return;
}
}
let branchName = null;
while (!branchName) {
branchName = await getBranchName(print, config.gh_token);
}
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 {
// Download files to /tmp
await system.run(getDownloadFileFromRepoCommand(config.gh_token, 'Photowall', 'photowall', 'cloudformation/ecr-lifecycle-policy.json'));
await system.run(getDownloadFileFromRepoCommand(config.gh_token, 'Photowall', 'photowall', 'cloudformation/ecs-service.yaml'));
const stackName = await prompt.run();
const lifeCycleCommand = getLifeCyclePolicyCommand(stackName, `file://ecr-lifecycle-policy.json`);
const updateStackCommand = getUpdateStackCommand(stackName, branchName, `file://ecs-service.yaml`);
const shouldRun = await getConfirmation(branchName, stackName);
if (shouldRun) {
let output = await system.run(lifeCycleCommand, {cwd: '/tmp/', trim: true});
print.fancy(output);
output = await system.run(updateStackCommand, {cwd: '/tmp/', trim: true});
print.fancy(output);
}
} catch (e) {
console.log(`e`, e)
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers')
}
}
}
+15
View File
@@ -0,0 +1,15 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import { GluegunCommand } from 'gluegun'
const command: GluegunCommand = {
name: 'pwcli',
run: async (toolbox: GluegunMenuToolbox) => {
const { print } = toolbox;
print.info('Welcome to photowall CLI for everything, almost 😬');
await toolbox.menu.showMenu();
}
};
module.exports = command;
+131
View File
@@ -0,0 +1,131 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import chalk = require('chalk');
import { system } from 'gluegun';
const { Confirm, Input } = require('enquirer');
const checkCLIProgram = async (toolbox: GluegunMenuToolbox, cmd: string) => {
const {print, system, strings} = toolbox;
try {
const result = strings.trim(await system.run(`command -v ${cmd}`));
return true;
} catch(e) {
return false;
}
}
module.exports = {
name: 'settings',
alias: ['se'],
description: 'Setup settings for pwcli (se)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
const {print, system, strings} = toolbox;
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')}
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.
`));
// Check if brew is installed
// if (await checkCLIProgram(toolbox, 'brew')) {
// print.info(`\nDetected ${chalk.green('brew')}`);
// } else {
// print.info(`\nRequired program ${chalk.green('brew')} is not installed.`);
// if (await (new Confirm({
// name: 'confirm',
// message: `Do you want pwcli to install it?`
// })).run()) {
// print.info(`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`);
// // system.run('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"');
// } else {
// if (await (new Confirm({
// name: 'confirm',
// message: `Do you want to install it your self?`
// })).run()) {
// system.run('open https://brew.sh');
// } else {
// print.info('😔 ok, your choice..');
// }
// }
// if (await (new Confirm({
// name: 'confirm',
// message: `Is ${chalk.green('brew')} installed?`
// })).run()) {
// print.info('Great, lets continue!');
// } else {
// print.info('😔 ok, your choice..');
// }
// }
// if (await checkCLIProgram(toolbox, 'asdf')) {
// print.info(`\nDetected ${chalk.green('aws cli')}`);
// } else {
// print.info(`\nRequired program ${chalk.green('aws cli')} is not installed.`);
// if (await (new Confirm({
// name: 'confirm',
// message: `Do you want pwcli to install it?`
// })).run()) {
// print.info(`brew install awscli`);
// // system.run('brew install awscli');
// } else {
// if (await (new Confirm({
// name: 'confirm',
// message: `Do you want to install it your self?`
// })).run()) {
// system.run('open https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html');
// } else {
// print.info('😔 ok, your choice..');
// }
// }
// if (await (new Confirm({
// name: 'confirm',
// message: `Is ${chalk.green('aws cli')} installed and configured?`
// })).run()) {
// } else {
// print.info('😔 ok, install it and run ..');
// await toolbox.menu.showMenu();
// }
// }
system.run('touch ~/.pwcli_settings');
print.info(`Created configuration file ${chalk.yellow(`~/.pwcli_settings`)}`);
const config = {
gh_token: '',
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 >`
})).run();
config.photowall_repo = await (new Input({
message: `If you want to be able to push active branch in your photowall repository, please insert the absolute path to the project >`
})).run();
print.info(`
${JSON.stringify(config)}
`);
if (await (new Confirm({
message: `Ok to save the these settings to ${chalk.yellow(`~/.pwcli_settings`)}?`
})).run()) {
system.run(`echo '${JSON.stringify(config)}' > ~/.pwcli_settings`);
} else {
print.info('Ok then.');
if (toolbox.fromMenu()) await toolbox.menu.showMenu();
}
if (toolbox.fromMenu()) await toolbox.menu.showMenu();
}
};
+14
View File
@@ -0,0 +1,14 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
/**
* Section1 menu
*/
module.exports = {
name: 'setup',
alias: ['s'],
description: 'Setup pwcli (s)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
await toolbox.menu.showMenu('setup');
}
};
+19
View File
@@ -0,0 +1,19 @@
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')
}
// enable this if you want to read configuration in from
// the current folder's package.json (in a "pwcli" property),
// pwcli.config.json, etc.
// toolbox.config = {
// ...toolbox.config,
// ...toolbox.config.loadConfig("pwcli", process.cwd())
// }
}
+1
View File
@@ -0,0 +1 @@
// export types
+28
View File
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": false,
"experimentalDecorators": true,
"lib": [
"es2015",
"scripthost",
"es2015.promise",
"es2015.generator",
"es2015.iterable",
"dom"
],
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": false,
"noImplicitThis": true,
"noUnusedLocals": false,
"sourceMap": false,
"inlineSourceMap": true,
"outDir": "build",
"strict": false,
"target": "es5",
"declaration": true,
"declarationDir": "build/types"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": ["tslint-config-standard", "tslint-config-prettier"],
"rules": {
"strict-type-predicates": false
},
"env": {
"jest": true
}
}
+4361
View File
File diff suppressed because it is too large Load Diff