terrafaker 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/generate/file.d.ts +13 -0
- package/dist/commands/generate/file.js +32 -0
- package/dist/commands/generate/index.d.ts +7 -0
- package/dist/commands/generate/index.js +9 -0
- package/dist/commands/generate/repo.d.ts +18 -0
- package/dist/commands/generate/repo.js +60 -0
- package/dist/commands/gh/clone-repos.d.ts +10 -0
- package/dist/commands/gh/clone-repos.js +46 -0
- package/dist/commands/gh/delete-repos.d.ts +9 -0
- package/dist/commands/gh/delete-repos.js +41 -0
- package/dist/commands/gh/index.d.ts +7 -0
- package/dist/commands/gh/index.js +10 -0
- package/dist/commands/util/format-psv.d.ts +10 -0
- package/dist/commands/util/format-psv.js +46 -0
- package/dist/commands/util/format-tsv.d.ts +13 -0
- package/dist/commands/util/format-tsv.js +33 -0
- package/dist/commands/util/index.d.ts +7 -0
- package/dist/commands/util/index.js +9 -0
- package/dist/constants/aws.d.ts +192 -0
- package/dist/constants/aws.js +201 -0
- package/dist/constants/gcp.d.ts +88 -0
- package/dist/constants/gcp.js +109 -0
- package/dist/constants/tags.d.ts +5 -0
- package/dist/constants/tags.js +17 -0
- package/dist/enums/help-messages.d.ts +4 -0
- package/dist/enums/help-messages.js +4 -0
- package/dist/enums/providers.d.ts +8 -0
- package/dist/enums/providers.js +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/object-values.d.ts +2 -0
- package/dist/types/object-values.js +1 -0
- package/dist/utilities/base-command.d.ts +5 -0
- package/dist/utilities/base-command.js +9 -0
- package/dist/utilities/flags.d.ts +5 -0
- package/dist/utilities/flags.js +21 -0
- package/dist/utilities/generators/aws-generators.d.ts +4 -0
- package/dist/utilities/generators/aws-generators.js +80 -0
- package/dist/utilities/generators/gcp-generators.d.ts +4 -0
- package/dist/utilities/generators/gcp-generators.js +69 -0
- package/dist/utilities/generators/generator-utils.d.ts +80 -0
- package/dist/utilities/generators/generator-utils.js +72 -0
- package/dist/utilities/github.d.ts +8 -0
- package/dist/utilities/github.js +4 -0
- package/dist/utilities/string-utils.d.ts +5 -0
- package/dist/utilities/string-utils.js +7 -0
- package/oclif.manifest.json +358 -0
- package/package.json +82 -0
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# terrafaker
|
|
2
|
+
|
|
3
|
+
CLI for easily generating fake terraform files and repos
|
|
4
|
+
|
|
5
|
+
[](https://oclif.io)
|
|
6
|
+
[](https://npmjs.org/package/terrafaker)
|
|
7
|
+
[](https://npmjs.org/package/terrafaker)
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
This tool mostly exists to quickly seed data for testing out platforms that rely on infrastructure-as-code, like [Infracost](https://www.infracost.io/). If you find it useful, or there's a feature you'd like to see, feel free to open up an [issue](https://github.com/brandongregoryscott/terrafaker/issues).
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Generate individual files
|
|
16
|
+
- Generate git repos with multiple files (and optionally push them to GitHub)
|
|
17
|
+
- Bulk clone and delete generated repos by prefix
|
|
18
|
+
|
|
19
|
+
### Supported providers and resources
|
|
20
|
+
|
|
21
|
+
- AWS
|
|
22
|
+
- EC2 instances
|
|
23
|
+
- Lambda functions
|
|
24
|
+
- GCP
|
|
25
|
+
- Compute instances
|
|
26
|
+
- Functions
|
|
27
|
+
- TODO: Azure
|
|
28
|
+
|
|
29
|
+
<!-- prettier-ignore-start -->
|
|
30
|
+
<!-- toc -->
|
|
31
|
+
* [terrafaker](#terrafaker)
|
|
32
|
+
* [Usage](#usage)
|
|
33
|
+
* [Commands](#commands)
|
|
34
|
+
<!-- tocstop -->
|
|
35
|
+
|
|
36
|
+
# Usage
|
|
37
|
+
|
|
38
|
+
<!-- usage -->
|
|
39
|
+
```sh-session
|
|
40
|
+
$ npm install -g terrafaker
|
|
41
|
+
$ terrafaker COMMAND
|
|
42
|
+
running command...
|
|
43
|
+
$ terrafaker (--version)
|
|
44
|
+
terrafaker/0.0.0 darwin-arm64 node-v24.8.0
|
|
45
|
+
$ terrafaker --help [COMMAND]
|
|
46
|
+
USAGE
|
|
47
|
+
$ terrafaker COMMAND
|
|
48
|
+
...
|
|
49
|
+
```
|
|
50
|
+
<!-- usagestop -->
|
|
51
|
+
|
|
52
|
+
# Commands
|
|
53
|
+
|
|
54
|
+
<!-- commands -->
|
|
55
|
+
* [`terrafaker generate file`](#terrafaker-generate-file)
|
|
56
|
+
* [`terrafaker generate repo`](#terrafaker-generate-repo)
|
|
57
|
+
* [`terrafaker gh clone-repos`](#terrafaker-gh-clone-repos)
|
|
58
|
+
* [`terrafaker gh delete-repos`](#terrafaker-gh-delete-repos)
|
|
59
|
+
* [`terrafaker help [COMMAND]`](#terrafaker-help-command)
|
|
60
|
+
|
|
61
|
+
## `terrafaker generate file`
|
|
62
|
+
|
|
63
|
+
Generates a terraform file.
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
USAGE
|
|
67
|
+
$ terrafaker generate file [--name <value>] [--provider aws|gcp] [--resource-count <value>] [-f] [-q]
|
|
68
|
+
|
|
69
|
+
FLAGS
|
|
70
|
+
-f, --[no-]format Format the output terraform files. Requires `terraform` to be in your $PATH.
|
|
71
|
+
-q, --quiet Suppress the logging output.
|
|
72
|
+
--name=<value> Name for the generated file, which must end in .tf
|
|
73
|
+
--provider=<option> Cloud provider to generate resources for
|
|
74
|
+
<options: aws|gcp>
|
|
75
|
+
--resource-count=<value> [default: 3] Number of resources per file to generate
|
|
76
|
+
|
|
77
|
+
DESCRIPTION
|
|
78
|
+
Generates a terraform file.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
_See code: [src/commands/generate/file.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/generate/file.ts)_
|
|
82
|
+
|
|
83
|
+
## `terrafaker generate repo`
|
|
84
|
+
|
|
85
|
+
Generates repo(s) with multiple terraform files.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
USAGE
|
|
89
|
+
$ terrafaker generate repo [--directory <value>] [--count <value>] [--file-count <value>] [--resource-count
|
|
90
|
+
<value>] [--prefix <value>] [--provider aws|gcp] [-f] [--create-remote] [--public] [-q]
|
|
91
|
+
|
|
92
|
+
FLAGS
|
|
93
|
+
-f, --[no-]format Format the output terraform files. Requires `terraform` to be in your $PATH.
|
|
94
|
+
-q, --quiet Suppress the logging output.
|
|
95
|
+
--count=<value> [default: 1] Number of repos to generate
|
|
96
|
+
--create-remote Create and push a remote GitHub repo. Requires the `gh` CLI to be installed. To install,
|
|
97
|
+
run `brew install gh`.
|
|
98
|
+
--directory=<value> [default: .] Directory to generate the repo(s) in
|
|
99
|
+
--file-count=<value> [default: 3] Number of files per repo to generate
|
|
100
|
+
--prefix=<value> [default: tf_] Prefix for repo names, useful for quickly identifying generated content
|
|
101
|
+
--provider=<option> Cloud provider to generate resources for
|
|
102
|
+
<options: aws|gcp>
|
|
103
|
+
--public Whether the remote repo(s) created are public.
|
|
104
|
+
--resource-count=<value> [default: 3] Number of resources per file to generate
|
|
105
|
+
|
|
106
|
+
DESCRIPTION
|
|
107
|
+
Generates repo(s) with multiple terraform files.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
_See code: [src/commands/generate/repo.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/generate/repo.ts)_
|
|
111
|
+
|
|
112
|
+
## `terrafaker gh clone-repos`
|
|
113
|
+
|
|
114
|
+
Clones repos from your Github account, useful for pulling down generated repos for manual modifications. Requires the `gh` CLI to be installed. To install, run `brew install gh`.
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
USAGE
|
|
118
|
+
$ terrafaker gh clone-repos --prefix <value> [--directory <value>]
|
|
119
|
+
|
|
120
|
+
FLAGS
|
|
121
|
+
--directory=<value> [default: .] Directory to clone the repo(s) in
|
|
122
|
+
--prefix=<value> (required) Prefix for the repos to clone, such as 'tf_'
|
|
123
|
+
|
|
124
|
+
DESCRIPTION
|
|
125
|
+
Clones repos from your Github account, useful for pulling down generated repos for manual modifications. Requires the
|
|
126
|
+
`gh` CLI to be installed. To install, run `brew install gh`.
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
_See code: [src/commands/gh/clone-repos.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/gh/clone-repos.ts)_
|
|
130
|
+
|
|
131
|
+
## `terrafaker gh delete-repos`
|
|
132
|
+
|
|
133
|
+
Deletes repos from your Github account, useful for cleaning up generated test data. Requires the `gh` CLI to be installed. To install, run `brew install gh`.
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
USAGE
|
|
137
|
+
$ terrafaker gh delete-repos --prefix <value>
|
|
138
|
+
|
|
139
|
+
FLAGS
|
|
140
|
+
--prefix=<value> (required) Prefix for the repos to delete, such as 'tf_'
|
|
141
|
+
|
|
142
|
+
DESCRIPTION
|
|
143
|
+
Deletes repos from your Github account, useful for cleaning up generated test data. Requires the `gh` CLI to be
|
|
144
|
+
installed. To install, run `brew install gh`.
|
|
145
|
+
|
|
146
|
+
If the deletion fails, you may need to refresh your CLI permissions with `gh auth refresh -s delete_repo`
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
_See code: [src/commands/gh/delete-repos.ts](https://github.com/brandongregoryscott/terrafaker/blob/v0.0.0/src/commands/gh/delete-repos.ts)_
|
|
150
|
+
|
|
151
|
+
## `terrafaker help [COMMAND]`
|
|
152
|
+
|
|
153
|
+
Display help for terrafaker.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
USAGE
|
|
157
|
+
$ terrafaker help [COMMAND...] [-n]
|
|
158
|
+
|
|
159
|
+
ARGUMENTS
|
|
160
|
+
[COMMAND...] Command to show help for.
|
|
161
|
+
|
|
162
|
+
FLAGS
|
|
163
|
+
-n, --nested-commands Include all nested commands in the output.
|
|
164
|
+
|
|
165
|
+
DESCRIPTION
|
|
166
|
+
Display help for terrafaker.
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.36/src/commands/help.ts)_
|
|
170
|
+
<!-- commandsstop -->
|
|
171
|
+
<!-- prettier-ignore-end -->
|
package/bin/dev.cmd
ADDED
package/bin/dev.js
ADDED
package/bin/run.cmd
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
declare class File extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
provider: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
"resource-count": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
format: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export { File };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Flags } from "@oclif/core";
|
|
2
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
3
|
+
import { formatFlag, providerFlag, quietFlag, resourceCountFlag, } from "../../utilities/flags.js";
|
|
4
|
+
import { success } from "../../utilities/string-utils.js";
|
|
5
|
+
import { generateFileByProvider, randomProvider, } from "../../utilities/generators/generator-utils.js";
|
|
6
|
+
class File extends BaseCommand {
|
|
7
|
+
static description = "Generates a terraform file.";
|
|
8
|
+
static flags = {
|
|
9
|
+
name: Flags.string({
|
|
10
|
+
description: "Name for the generated file, which must end in .tf",
|
|
11
|
+
}),
|
|
12
|
+
provider: providerFlag,
|
|
13
|
+
"resource-count": resourceCountFlag,
|
|
14
|
+
format: formatFlag,
|
|
15
|
+
quiet: quietFlag,
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(File);
|
|
19
|
+
const { name, quiet, format, "resource-count": resourceCount } = flags;
|
|
20
|
+
const provider = flags.provider ?? randomProvider();
|
|
21
|
+
let tfFilename = name ?? "main.tf";
|
|
22
|
+
if (!tfFilename.endsWith(".tf")) {
|
|
23
|
+
tfFilename = `${tfFilename}.tf`;
|
|
24
|
+
}
|
|
25
|
+
const tfg = generateFileByProvider({ provider, resourceCount });
|
|
26
|
+
tfg.write({ format, tfFilename });
|
|
27
|
+
if (!quiet) {
|
|
28
|
+
this.log(success(`Successfully generated ${tfFilename}`));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export { File };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
class Generate extends BaseCommand {
|
|
3
|
+
static hidden = true;
|
|
4
|
+
static description = "Commands for generating terraform files.";
|
|
5
|
+
async run() {
|
|
6
|
+
await this.showHelp();
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export { Generate };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
declare class Repo extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
count: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
"file-count": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
"resource-count": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
prefix: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
provider: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
format: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
"create-remote": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
public: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export { Repo };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Flags } from "@oclif/core";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { generateRepo, randomProvider, } from "../../utilities/generators/generator-utils.js";
|
|
4
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
5
|
+
import { formatFlag, providerFlag, quietFlag, resourceCountFlag, } from "../../utilities/flags.js";
|
|
6
|
+
import { $ } from "zx";
|
|
7
|
+
import { HelpMessages } from "../../enums/help-messages.js";
|
|
8
|
+
class Repo extends BaseCommand {
|
|
9
|
+
static description = "Generates repo(s) with multiple terraform files.";
|
|
10
|
+
static flags = {
|
|
11
|
+
directory: Flags.string({
|
|
12
|
+
description: "Directory to generate the repo(s) in",
|
|
13
|
+
default: ".",
|
|
14
|
+
}),
|
|
15
|
+
count: Flags.integer({
|
|
16
|
+
description: "Number of repos to generate",
|
|
17
|
+
default: 1,
|
|
18
|
+
}),
|
|
19
|
+
"file-count": Flags.integer({
|
|
20
|
+
description: "Number of files per repo to generate",
|
|
21
|
+
default: 3,
|
|
22
|
+
}),
|
|
23
|
+
"resource-count": resourceCountFlag,
|
|
24
|
+
prefix: Flags.string({
|
|
25
|
+
description: "Prefix for repo names, useful for quickly identifying generated content",
|
|
26
|
+
default: "tf_",
|
|
27
|
+
}),
|
|
28
|
+
provider: providerFlag,
|
|
29
|
+
format: formatFlag,
|
|
30
|
+
"create-remote": Flags.boolean({
|
|
31
|
+
description: `Create and push a remote GitHub repo. ${HelpMessages.RequiresGhCli}`,
|
|
32
|
+
}),
|
|
33
|
+
public: Flags.boolean({
|
|
34
|
+
description: "Whether the remote repo(s) created are public.",
|
|
35
|
+
default: false,
|
|
36
|
+
}),
|
|
37
|
+
quiet: quietFlag,
|
|
38
|
+
};
|
|
39
|
+
async run() {
|
|
40
|
+
const { flags } = await this.parse(Repo);
|
|
41
|
+
const { format, prefix, count, public: isPublic, quiet, "resource-count": resourceCount, "file-count": fileCount, "create-remote": createRemote, } = flags;
|
|
42
|
+
const provider = flags.provider;
|
|
43
|
+
const directory = path.resolve(process.cwd(), flags.directory);
|
|
44
|
+
for (let i = 0; i < count; i++) {
|
|
45
|
+
const { name, path } = await generateRepo({
|
|
46
|
+
directory,
|
|
47
|
+
fileCount,
|
|
48
|
+
format,
|
|
49
|
+
prefix,
|
|
50
|
+
provider: provider ?? randomProvider(),
|
|
51
|
+
resourceCount,
|
|
52
|
+
quiet,
|
|
53
|
+
});
|
|
54
|
+
if (createRemote) {
|
|
55
|
+
await $ `gh repo create ${name} --source ${path} ${isPublic ? "--public" : "--private"} --push`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export { Repo };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
declare class CloneRepos extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
prefix: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export { CloneRepos };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Flags } from "@oclif/core";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { confirm } from "@inquirer/prompts";
|
|
4
|
+
import { isEmpty } from "lodash-es";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { listRepos, stringifyRepos } from "../../utilities/github.js";
|
|
7
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
8
|
+
import { HelpMessages } from "../../enums/help-messages.js";
|
|
9
|
+
class CloneRepos extends BaseCommand {
|
|
10
|
+
static description = `Clones repos from your Github account, useful for pulling down generated repos for manual modifications. ${HelpMessages.RequiresGhCli}`;
|
|
11
|
+
static flags = {
|
|
12
|
+
directory: Flags.string({
|
|
13
|
+
description: "Directory to clone the repo(s) in",
|
|
14
|
+
default: ".",
|
|
15
|
+
}),
|
|
16
|
+
prefix: Flags.string({
|
|
17
|
+
description: "Prefix for the repos to clone, such as 'tf_'",
|
|
18
|
+
required: true,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
async run() {
|
|
22
|
+
const { flags } = await this.parse(CloneRepos);
|
|
23
|
+
const { prefix } = flags;
|
|
24
|
+
const allRepos = listRepos();
|
|
25
|
+
const repos = allRepos.filter((repo) => repo.name.startsWith(prefix));
|
|
26
|
+
if (isEmpty(repos)) {
|
|
27
|
+
this.log(`Repos found:\n${stringifyRepos(allRepos)}`);
|
|
28
|
+
this.log(`No repos found with prefix '${prefix}'`);
|
|
29
|
+
this.exit();
|
|
30
|
+
}
|
|
31
|
+
this.log(`Repos to clone:\n${stringifyRepos(repos)}`);
|
|
32
|
+
const confirmation = await confirm({
|
|
33
|
+
message: "Continue with cloning these repos?",
|
|
34
|
+
});
|
|
35
|
+
if (!confirmation) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
repos.forEach((repo) => {
|
|
39
|
+
const directory = path.resolve(process.cwd(), flags.directory, repo.name);
|
|
40
|
+
execSync(`gh repo clone ${repo.nameWithOwner} ${directory}`, {
|
|
41
|
+
stdio: "inherit",
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export { CloneRepos };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
declare class DeleteRepos extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
prefix: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
};
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export { DeleteRepos };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { confirm } from "@inquirer/prompts";
|
|
4
|
+
import { isEmpty } from "lodash-es";
|
|
5
|
+
import { listRepos, stringifyRepos } from "../../utilities/github.js";
|
|
6
|
+
import { HelpMessages } from "../../enums/help-messages.js";
|
|
7
|
+
class DeleteRepos extends Command {
|
|
8
|
+
static description = `Deletes repos from your Github account, useful for cleaning up generated test data. ${HelpMessages.RequiresGhCli}
|
|
9
|
+
|
|
10
|
+
If the deletion fails, you may need to refresh your CLI permissions with \`gh auth refresh -s delete_repo\``;
|
|
11
|
+
static flags = {
|
|
12
|
+
prefix: Flags.string({
|
|
13
|
+
description: "Prefix for the repos to delete, such as 'tf_'",
|
|
14
|
+
required: true,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(DeleteRepos);
|
|
19
|
+
const { prefix } = flags;
|
|
20
|
+
const allRepos = listRepos();
|
|
21
|
+
const repos = allRepos.filter((repo) => repo.name.startsWith(prefix));
|
|
22
|
+
if (isEmpty(repos)) {
|
|
23
|
+
this.log(`Repos found:\n${stringifyRepos(allRepos)}`);
|
|
24
|
+
this.log(`No repos found with prefix '${prefix}'`);
|
|
25
|
+
this.exit();
|
|
26
|
+
}
|
|
27
|
+
this.log(`Repos to delete:\n${stringifyRepos(repos)}`);
|
|
28
|
+
const confirmation = await confirm({
|
|
29
|
+
message: "Continue with deletion of these repos?",
|
|
30
|
+
});
|
|
31
|
+
if (!confirmation) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
repos.forEach((repo) => {
|
|
35
|
+
execSync(`gh repo delete ${repo.nameWithOwner} --yes`, {
|
|
36
|
+
stdio: "inherit",
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export { DeleteRepos };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
import { HelpMessages } from "../../enums/help-messages.js";
|
|
3
|
+
class Gh extends BaseCommand {
|
|
4
|
+
static hidden = true;
|
|
5
|
+
static description = `Utility commands that wrap the \`gh\` CLI. ${HelpMessages.RequiresGhCli}`;
|
|
6
|
+
async run() {
|
|
7
|
+
await this.showHelp();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export { Gh };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
declare class FormatPsv extends BaseCommand {
|
|
3
|
+
static hidden: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
psv: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export { FormatPsv };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Args } from "@oclif/core";
|
|
2
|
+
import { compact, first } from "lodash-es";
|
|
3
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
4
|
+
import { stringifySingleLineArray } from "../../utilities/string-utils.js";
|
|
5
|
+
const EXAMPLE_INSTANCE_TYPES = ["m5.large", "m5.xlarge", "m5.2xlarge"];
|
|
6
|
+
class FormatPsv extends BaseCommand {
|
|
7
|
+
static hidden = true;
|
|
8
|
+
static description = "Utility command for formatting a PSV (pipe-separated value) into an array or object with array values. Primarily used for parsing data from the AWS docs.";
|
|
9
|
+
static args = {
|
|
10
|
+
psv: Args.string({
|
|
11
|
+
required: true,
|
|
12
|
+
description: `Pipe-separated value to format into a string array, i.e. '${EXAMPLE_INSTANCE_TYPES.join(" | ")}'.
|
|
13
|
+
If the string is multiple lines, it will be formatted into an object where the key is the first column before a tab, i.e. 'M5\t${EXAMPLE_INSTANCE_TYPES.join(" | ")}'`,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { args } = await this.parse(FormatPsv);
|
|
18
|
+
const { psv } = args;
|
|
19
|
+
const lines = psv.split("\n");
|
|
20
|
+
if (lines.length === 1) {
|
|
21
|
+
const values = splitPsv(first(lines) ?? "");
|
|
22
|
+
this.log(stringifySingleLineArray(values));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const value = lines.reduce((accumulated, line) => {
|
|
26
|
+
const [type, psv] = line.split("\t");
|
|
27
|
+
accumulated[type] = splitPsv(psv);
|
|
28
|
+
return accumulated;
|
|
29
|
+
}, {});
|
|
30
|
+
this.log(stringifyObjectWithSingleLineArrays(value));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const splitPsv = (psv) => compact(psv.split("|").map((value) => value.trim()));
|
|
34
|
+
/**
|
|
35
|
+
* In an effort to reduce the size of the AWS constants file, we're custom stringifying the object
|
|
36
|
+
* to ensure the arrays are a single line.
|
|
37
|
+
*/
|
|
38
|
+
const stringifyObjectWithSingleLineArrays = (object) => {
|
|
39
|
+
const lines = ["{"];
|
|
40
|
+
Object.entries(object).forEach(([key, values]) => {
|
|
41
|
+
lines.push(`\t"${key}": ${stringifySingleLineArray(values)},`);
|
|
42
|
+
});
|
|
43
|
+
lines.push("}");
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
};
|
|
46
|
+
export { FormatPsv };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
2
|
+
declare class FormatTsv extends BaseCommand {
|
|
3
|
+
static hidden: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
index: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
static args: {
|
|
9
|
+
tsv: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export { FormatTsv };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { BaseCommand } from "../../utilities/base-command.js";
|
|
3
|
+
import { stringifySingleLineArray } from "../../utilities/string-utils.js";
|
|
4
|
+
import { compact } from "lodash-es";
|
|
5
|
+
const EXAMPLE = `c4d-standard-2 2 7 No Up to 10 N/A`;
|
|
6
|
+
class FormatTsv extends BaseCommand {
|
|
7
|
+
static hidden = true;
|
|
8
|
+
static description = "Utility command for formatting a TSV (tab-separated value) into an array. Primarily used for parsing data from the GCP docs.";
|
|
9
|
+
static flags = {
|
|
10
|
+
index: Flags.integer({
|
|
11
|
+
char: "i",
|
|
12
|
+
description: "Column index to pull from each line.",
|
|
13
|
+
default: 0,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
static args = {
|
|
17
|
+
tsv: Args.string({
|
|
18
|
+
required: true,
|
|
19
|
+
description: `Tab-separated value to format into a string array, i.e. '${EXAMPLE}'.
|
|
20
|
+
If the string is multiple lines (which it generally is), the specified column index from each line will be placed in the array.`,
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
const { args, flags } = await this.parse(FormatTsv);
|
|
25
|
+
const { index } = flags;
|
|
26
|
+
const { tsv } = args;
|
|
27
|
+
const lines = tsv.split("\n");
|
|
28
|
+
const values = compact(lines.map((line) => splitTsv(line)[index]));
|
|
29
|
+
this.log(stringifySingleLineArray(values));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const splitTsv = (tsv) => compact(tsv.split("\t").map((value) => value.trim()));
|
|
33
|
+
export { FormatTsv };
|