added directly mode on some commands (#31)

This commit is contained in:
Arwid Thornström
2025-11-06 13:30:10 +01:00
committed by GitHub
parent 1ed0f300dc
commit 7e50d5eb54
4 changed files with 415 additions and 52 deletions
@@ -18,6 +18,9 @@ module.exports = {
return;
}
// Check for --json flag
const jsonOutput = toolbox.parameters.options.json;
const testStacks = await getTestStacksInfo(toolbox);
const status = (status: string) => {
switch (status) {
@@ -189,6 +192,33 @@ module.exports = {
return aNumber - bNumber;
});
// If JSON output is requested, output and return early
if (jsonOutput) {
const jsonData = testStacks.map((stack) => {
const regex = /^(\d+)/;
const match = stack.branch.match(regex);
const branchIssueNumber = match ? match[1] : null;
const issueStatus = issueStatuses.find(
(issueStatus) => issueStatus.issue === branchIssueNumber,
);
return {
name: stack.name,
status: stack.status,
branch: stack.branch,
issueNumber: branchIssueNumber,
issueStatus: issueStatus ? issueStatus.status : getStatusIcon('null'),
issueUpdated: issueStatus ? issueStatus.issueUpdated : null,
created: stack.created,
updated: stack.updated,
url: stackUrl(stack.name),
};
});
console.log(JSON.stringify(jsonData, null, 2));
return;
}
for (const stack of testStacks) {
const regex = /^(\d+)/;
const match = stack.branch.match(regex);
@@ -80,9 +80,30 @@ module.exports = {
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings, print } = toolbox;
// Check for parameters
const jsonOutput = toolbox.parameters.options.json;
const branchParam = toolbox.parameters.options.branch;
const stackParam =
toolbox.parameters.options.stack || toolbox.parameters.options.server;
const skipConfirm = toolbox.parameters.options['skip-confirm'];
// Load settings
const config = await getSettings(toolbox);
if (!config || !config.photowall_repo || config.photowall_repo === '') {
if (jsonOutput) {
console.log(
JSON.stringify(
{
success: false,
message:
'The update command requires that you set an absolute path to your local photowall repository.',
},
null,
2,
),
);
return;
}
print.error(`
The create command requires that you set an absolute path to your local photowall repository.
@@ -93,40 +114,122 @@ module.exports = {
}
let branchName = null;
while (!branchName) {
branchName = await getBranchName(
toolbox,
config.gh_token,
config.photowall_repo,
);
// If branch is provided as parameter, validate it
if (branchParam) {
const octokit = new Octokit({ auth: config.gh_token });
try {
const response = await octokit.request(
'GET /repos/{owner}/{repo}/branches/{branch}',
{
owner: 'photowall',
repo: 'photowall',
branch: branchParam,
},
);
if (response.status === 200) {
branchName = branchParam;
}
} catch (e) {
if (jsonOutput) {
console.log(
JSON.stringify(
{
success: false,
message: `Not a valid branch on photowall repo: ${branchParam}`,
},
null,
2,
),
);
return;
}
print.error(`Not a valid branch on photowall repo: ${branchParam}`);
return;
}
} else {
// Interactive mode - ask for branch
while (!branchName) {
branchName = await getBranchName(
toolbox,
config.gh_token,
config.photowall_repo,
);
}
}
const testStacks = await getTestStacksInfo(toolbox);
const options = testStacks.map((item) => {
return item.name;
});
let stackName = null;
const prompt = new AutoComplete({
name: 'testserver',
message: 'Choose a server',
limit: options.length - 1,
initial: options.length - 1,
choices: options,
});
// If stack is provided as parameter, validate it
if (stackParam) {
const foundStack = testStacks.find((stack) => {
return (
stack.name === stackParam ||
stack.name === `photowall-${stackParam}` ||
stack.name.replace('photowall-', '') === stackParam
);
});
if (foundStack) {
stackName = foundStack.name;
} else {
if (jsonOutput) {
console.log(
JSON.stringify(
{
success: false,
message: `Stack not found: ${stackParam}`,
availableStacks: testStacks.map((s) => s.name),
},
null,
2,
),
);
return;
}
print.error(`Stack not found: ${stackParam}`);
print.info('Available stacks:');
testStacks.forEach((s) => print.info(` - ${s.name}`));
return;
}
} else {
// Interactive mode - ask for stack
const options = testStacks.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,
});
stackName = await prompt.run();
}
try {
const stackName = await prompt.run();
const stacksuffix = stackName.replace('photowall-', '');
const shouldRun = await getConfirmation(branchName, stackName);
// Skip confirmation if parameters are provided or skip-confirm flag is set
const shouldRun =
branchParam && stackParam
? skipConfirm
? true
: await getConfirmation(branchName, stackName)
: await getConfirmation(branchName, stackName);
if (shouldRun) {
const cmd = `make update-stack STACK_ENVIRONMENT_NAME=${stacksuffix} GITHUB_BRANCH=${branchName}`;
print.fancy(
`Running [${chalk.yellow(
cmd,
)}] in folder [${`${config.photowall_repo}/cloudformation/`}]`,
);
if (!jsonOutput) {
print.fancy(
`Running [${chalk.yellow(
cmd,
)}] in folder [${`${config.photowall_repo}/cloudformation/`}]`,
);
}
const child = spawn(
'make',
[
@@ -140,10 +243,14 @@ module.exports = {
);
child.stdout.setEncoding('utf8');
child.stdout.on('data', (data) => {
process.stdout.write(data);
if (!jsonOutput) {
process.stdout.write(data);
}
});
child.stderr.on('data', (data) => {
process.stderr.write(data);
if (!jsonOutput) {
process.stderr.write(data);
}
});
await new Promise((resolve, reject) => {
child.on('close', (code) => {
@@ -156,48 +263,109 @@ module.exports = {
});
// Check the status
const spinner = print.spin(`Waiting for stack to update`);
const spinner = jsonOutput
? null
: print.spin(`Waiting for stack to update`);
let currentStackStatus = '';
while (currentStackStatus !== 'UPDATE_COMPLETE') {
const stackCmd = `aws cloudformation describe-stacks --stack-name photowall-${stacksuffix}`;
const response = await system.run(stackCmd, { trim: true });
const stackData = JSON.parse(response);
currentStackStatus = stackData.Stacks[0].StackStatus;
let statusOutput = '';
switch (currentStackStatus) {
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;
if (!jsonOutput) {
let statusOutput = '';
switch (currentStackStatus) {
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;
}
spinner.text = statusOutput;
if (currentStackStatus !== 'UPDATE_COMPLETE') {
await sleep(1000);
}
}
spinner.text = `Will start the pipeline now [${chalk.yellow(
`photowall-${stacksuffix}Pipeline`,
)}]`;
if (!jsonOutput) {
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! 🚀');
if (jsonOutput) {
console.log(
JSON.stringify(
{
success: true,
message: `Successfully updated ${stackName} with branch ${branchName} and started pipeline`,
stack: stackName,
branch: branchName,
pipeline: `photowall-${stacksuffix}Pipeline`,
},
null,
2,
),
);
} else {
spinner.stop();
print.fancy('Pipeline started, bye! 🚀');
}
} else {
// User cancelled
if (jsonOutput) {
console.log(
JSON.stringify(
{
success: false,
message: 'Update cancelled by user',
},
null,
2,
),
);
} else {
print.info('Update cancelled');
}
}
} catch (e) {
console.log(`e`, e);
if (jsonOutput) {
console.log(
JSON.stringify(
{
success: false,
message: `Error during update: ${e.message || e}`,
error: e.message || String(e),
},
null,
2,
),
);
} else {
console.log(`e`, e);
}
}
// Skip menu if using parameters or JSON output
if (jsonOutput || (branchParam && stackParam)) {
return;
}
if (toolbox.fromMenu()) {