Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c5679b7

Browse files
committed
Lint
1 parent 6f9e5a5 commit c5679b7

File tree

7 files changed

+57
-22
lines changed

7 files changed

+57
-22
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# github-run-script
2+
23
Run a script on multiple repositories, cloning them if needed.

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const cli = sade("github-run-script <script>", true)
1515
"-s, --search-path",
1616
"A path to search for already-cloned repositories."
1717
)
18+
.option("-t, --terminate", "Terminate any spawned processes on error.")
19+
.option("-s, --signal", "The signal to terminate a process with.")
1820
.action(handler);
1921

2022
export default cli;

src/handler.ts

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
import { mkdtemp, readdir, stat, rm } from "fs/promises";
2-
import { spawn } from "child_process";
3-
import { CliFlags, RepoOwner } from "./types";
4-
import { getRepoAndOwner, waitOnChildProcessToExit } from "./utils";
2+
import { ChildProcess, spawn as actualSpawn } from "child_process";
53
import ArrayStringMap from "array-string-map";
64
import filterAsync from "node-filter-async";
75
import { tmpdir } from "os";
6+
import { getRepoAndOwner, waitOnChildProcessToExit } from "./utils";
7+
import { CliFlags, RepoOwner } from "./types";
8+
9+
// We need to make a spawn cache. If an exception is thrown,
10+
// we need to be able to comply with the --terminate flag..
11+
const spawnedProcesses: Map<ChildProcess, null> = new Map();
12+
13+
async function spawn(command: string, args?: string[], options?: object) {
14+
const childProcess = await actualSpawn(command, args, options);
15+
spawnedProcesses.set(childProcess, null);
16+
childProcess.on("exit", () => spawnedProcesses.delete(childProcess));
17+
return childProcess;
18+
}
19+
20+
// eslint-disable-next-line no-undef -- NodeJS is a fake namespace by TypeScript.
21+
function terminateSpawnCache(signal: NodeJS.Signals = "SIGTERM") {
22+
for (const childProcess of spawnedProcesses.keys()) {
23+
childProcess.kill(signal);
24+
}
25+
}
826

927
export default async function handler(script: string, flags: CliFlags) {
10-
console.log(script, flags);
1128
const { owner: defaultOwner, _: repoNames } = flags;
29+
let { search } = flags;
1230
const repos: RepoOwner[] = [];
1331
for (const repoName of repoNames) {
1432
try {
@@ -20,35 +38,39 @@ export default async function handler(script: string, flags: CliFlags) {
2038
process.exit(1);
2139
}
2240
}
41+
2342
const tempDir = await mkdtemp(`${tmpdir()}/github-run-script-`);
2443
try {
2544
const directoryMapping: ArrayStringMap<RepoOwner, string> =
2645
new ArrayStringMap();
2746
const scanDirectories: Map<string, string[]> = new Map();
28-
if (flags.search) {
47+
if (search) {
2948
// If it's one path, it won't be in an array. This converts it into an array.
30-
if (typeof flags.search === "string") {
31-
flags.search = [flags.search];
49+
if (typeof search === "string") {
50+
search = [search];
3251
}
52+
3353
// What this code block does is simple. It stores in `scanDirectories`
3454
// a mapping of source path name to an array of directories in that directory.
3555
await Promise.all(
36-
flags.search.map(async (path) => {
56+
search.map(async (path) => {
3757
scanDirectories.set(
3858
path,
39-
await filterAsync(await readdir(path), async (item) => {
40-
return (await stat(`${path}/${item}`)).isDirectory();
41-
})
59+
await filterAsync(await readdir(path), async (item) =>
60+
(await stat(`${path}/${item}`)).isDirectory()
61+
)
4262
);
4363
})
4464
);
4565
}
66+
4667
await Promise.all(
4768
repos.map(async ([owner, repo]) => {
4869
// First, we need to check if the repository exists in `scanDirectories`.
49-
// TODO: Handle cases where the same repo is present multiple times in
50-
// TODO: different directories, or if two repos with the same name but
51-
// TODO: different owners is provided. (Maybe we can check `.git`.)
70+
// TODO:
71+
// Handle cases where the same repo is present multiple times in
72+
// different directories, or if two repos with the same name but
73+
// different owners is provided. (Maybe we can check `.git`.)
5274
for (const [path, directories] of scanDirectories) {
5375
for (const directory of directories) {
5476
if (repo === directory) {
@@ -57,12 +79,14 @@ export default async function handler(script: string, flags: CliFlags) {
5779
break;
5880
}
5981
}
82+
6083
// If we already found a match earlier, no need to re-iterate over the other
6184
// directories.
6285
if (directoryMapping.has([owner, repo])) {
6386
break;
6487
}
6588
}
89+
6690
// Deal wit the special case where we did not find a match. Time to clone.
6791
if (!directoryMapping.has([owner, repo])) {
6892
const destPath = `${tempDir}/${repo}`;
@@ -75,6 +99,7 @@ export default async function handler(script: string, flags: CliFlags) {
7599
await waitOnChildProcessToExit(childProc);
76100
directoryMapping.set([owner, repo], destPath);
77101
}
102+
78103
// Time to execute the script!
79104
const path = directoryMapping.get([owner, repo]);
80105
const childProc = await spawn(script, [], {
@@ -92,6 +117,11 @@ export default async function handler(script: string, flags: CliFlags) {
92117
})
93118
);
94119
} finally {
120+
if (flags.terminate ?? true) {
121+
// eslint-disable-next-line no-undef -- NodeJS is a fake namespace by TypeScript.
122+
terminateSpawnCache(flags.signal as NodeJS.Signals);
123+
}
124+
95125
// We need to clean up the temporary directory.
96126
await rm(tempDir, { recursive: true, force: true });
97127
}

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export interface CliFlags {
22
owner?: string;
33
search?: string | string[];
4+
terminate?: string | boolean;
5+
signal?: string;
46
_: string[];
57
}
68

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { RepoOwner } from "./types";
21
import { ChildProcess } from "child_process";
2+
import { RepoOwner } from "./types";
33

44
export function getRepoAndOwner(
55
input: string,

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"module": "commonjs",
55
"outDir": "dist",
66
"strict": true,
7-
"target": "es2019",
7+
"target": "es2019"
88
},
99
"include": ["src/**/*"]
1010
}

0 commit comments

Comments
 (0)