Skip to content

Commit 7ee1fb1

Browse files
committed
Add new templates
1 parent 31d49ad commit 7ee1fb1

File tree

8 files changed

+144
-6
lines changed

8 files changed

+144
-6
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "github-run-script",
3-
"version": "1.0.4",
3+
"version": "1.1.0",
44
"description": "Run a script on multiple repositories, cloning them if needed.",
55
"main": "dist/index.js",
66
"type": "commonjs",

src/cli.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import * as sade from "sade";
22
import handler from "./handler";
3+
import addTemplates from "./template";
34

45
// eslint-disable-next-line @typescript-eslint/no-var-requires -- Needed in order to not copy over package.json and make new src directory inside of dist
56
const { version, description } = require("../package.json");
67

7-
const cli = sade("github-run-script <script>", true)
8+
let cli = sade("github-run-script")
89
.version(version)
910
.describe(description)
11+
.command("execute <script>", "Execute a script on the given repositories", {
12+
default: true,
13+
})
1014
.option(
1115
"-o, --owner",
1216
"The owner for repositories without an explicit owner."
@@ -16,4 +20,6 @@ const cli = sade("github-run-script <script>", true)
1620
.option("--signal", "The signal to terminate a process with.")
1721
.action(handler);
1822

23+
cli = addTemplates(cli);
24+
1925
export default cli;

src/template.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Template } from "./types";
2+
import { Sade } from "sade";
3+
import templates from "./templates";
4+
5+
function generateCLIFromTemplate(sade: Sade, template: Template): Sade {
6+
const argString: string = template.arguments
7+
? " " +
8+
template.arguments
9+
.map((arg) => (typeof arg === "string" ? { name: arg } : arg))
10+
.map((arg) => `<${arg.name}>`)
11+
.join(" ")
12+
: "";
13+
sade = sade.command(
14+
`template ${template.name}${argString}`,
15+
template.description,
16+
{
17+
alias: template.aliases?.map((alias) => `template ${alias}`),
18+
}
19+
);
20+
template.flags
21+
?.map((flag) => (typeof flag === "string" ? { name: flag } : flag))
22+
.forEach((flag) => {
23+
sade = sade.option(flag.name, flag.description, flag.value);
24+
});
25+
sade = sade
26+
.option("--output-dir", "The directory to output the template to.")
27+
.option(
28+
"--output-file",
29+
"The filename to output the template to.",
30+
template.defaultFileName
31+
)
32+
.action(template.handler);
33+
return sade;
34+
}
35+
36+
export default function main(sade: Sade): Sade {
37+
for (const template of templates) {
38+
sade = generateCLIFromTemplate(sade, template);
39+
}
40+
return sade;
41+
}

src/templates/cp.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { GenerateTemplateCliFlags, Template } from "../types";
2+
import { getOutputPath } from "../utils";
3+
import { writeFile } from "fs/promises";
4+
5+
export default class CpTemplate implements Template {
6+
readonly name = "copy";
7+
readonly description =
8+
"A template to copy a signle source file to multiple repositories and commit the changes.";
9+
readonly aliases = ["cp"];
10+
11+
readonly defaultFileName = "cp.sh";
12+
13+
readonly arguments = [
14+
{
15+
name: "source_path",
16+
description: "The path that will be copied to the destination.",
17+
},
18+
{
19+
name: "dest_path",
20+
description:
21+
"Relative path to copy to. May omit the filename in order to use the filename of the source file.",
22+
},
23+
{
24+
name: "commit_message",
25+
description: "The commit message to use when committing the changes.",
26+
},
27+
];
28+
29+
async handler(
30+
source_file: string,
31+
dest_path: string,
32+
commit_message: string,
33+
flags: GenerateTemplateCliFlags
34+
) {
35+
const templateString = `
36+
#!/bin/bash
37+
$FILE="${source_file}"
38+
$RELATIVE_DEST="${dest_path}"
39+
git pull
40+
cp -r $FILE $RELATIVE_DEST
41+
git add $RELATIVE_DEST
42+
git commit -m "${commit_message}"
43+
git push
44+
`;
45+
const outputPath = await getOutputPath(this, flags);
46+
await writeFile(outputPath, templateString);
47+
console.log(`Output log written to: ${outputPath}`);
48+
}
49+
}

src/templates/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Template } from "../types";
2+
import CpTemplate from "./cp";
3+
4+
const Templates: Template[] = [new CpTemplate()];
5+
6+
export default Templates;

src/types.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,34 @@
1-
export interface CliFlags {
1+
export interface BaseCliFlags {
2+
_: string[];
3+
}
4+
5+
export interface CliFlags extends BaseCliFlags {
26
owner?: string;
37
search?: string | string[];
48
terminate?: string | boolean;
59
signal?: string;
6-
_: string[];
710
}
811

912
/**
1013
* A two-element tuple that contains [owner, repository].
1114
*/
1215
export type RepoOwner = [string, string];
16+
17+
export interface GenerateTemplateCliFlags extends BaseCliFlags {
18+
outputDir?: string;
19+
outputFile?: string;
20+
}
21+
22+
export interface Template {
23+
name: string;
24+
description?: string;
25+
aliases?: string[];
26+
27+
defaultFileName: string;
28+
29+
arguments?: (string | { name: string; description?: string })[];
30+
flags?: (string | { name: string; description?: string; value?: any })[];
31+
handler: (...args: any[]) => any;
32+
}
33+
34+
export type TemplateJSON = { [name: string]: Template };

src/utils.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { ChildProcess } from "child_process";
2-
import { RepoOwner } from "./types";
2+
import { GenerateTemplateCliFlags, RepoOwner, Template } from "./types";
3+
import { mkdtemp } from "fs/promises";
4+
import { tmpdir } from "os";
35

46
export function getRepoAndOwner(
57
input: string,
@@ -28,3 +30,14 @@ export async function waitOnChildProcessToExit(process: ChildProcess) {
2830
process.on("error", reject);
2931
});
3032
}
33+
34+
export async function getOutputPath(
35+
template: Template,
36+
flags: GenerateTemplateCliFlags
37+
) {
38+
let { outputDir, outputFile } = flags;
39+
outputDir =
40+
outputDir ?? (await mkdtemp(`${tmpdir()}/github-run-script-template-`));
41+
outputFile = outputFile ?? template.defaultFileName;
42+
return `${outputDir}/${outputFile}`;
43+
}

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"module": "commonjs",
55
"outDir": "dist",
66
"strict": true,
7-
"target": "es2019"
7+
"target": "es2019",
8+
"resolveJsonModule": true
89
},
910
"include": ["src/**/*"]
1011
}

0 commit comments

Comments
 (0)