complete-cli 1.0.1-dev.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.
Files changed (61) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +7 -0
  3. package/dist/commands/CheckCommand.js +141 -0
  4. package/dist/commands/InitCommand.js +64 -0
  5. package/dist/commands/NukeCommand.js +13 -0
  6. package/dist/commands/PublishCommand.js +158 -0
  7. package/dist/commands/UpdateCommand.js +16 -0
  8. package/dist/commands/check/check.test.js +86 -0
  9. package/dist/commands/check/getTruncatedText.js +139 -0
  10. package/dist/commands/init/checkIfProjectPathExists.js +21 -0
  11. package/dist/commands/init/createProject.js +123 -0
  12. package/dist/commands/init/getAuthorName.js +17 -0
  13. package/dist/commands/init/getProjectPath.js +80 -0
  14. package/dist/commands/init/packageManager.js +35 -0
  15. package/dist/commands/init/vsCodeInit.js +74 -0
  16. package/dist/constants.js +17 -0
  17. package/dist/git.js +128 -0
  18. package/dist/interfaces/GitHubCLIHostsYAML.js +1 -0
  19. package/dist/main.js +26 -0
  20. package/dist/prompt.js +46 -0
  21. package/dist/validateNoteVersion.js +25 -0
  22. package/file-templates/dynamic/.github/workflows/setup/action.yml +13 -0
  23. package/file-templates/dynamic/Node.gitignore +130 -0
  24. package/file-templates/dynamic/README.md +3 -0
  25. package/file-templates/dynamic/_gitignore +9 -0
  26. package/file-templates/dynamic/package.json +37 -0
  27. package/file-templates/static/.github/workflows/ci.yml +49 -0
  28. package/file-templates/static/.prettierignore +12 -0
  29. package/file-templates/static/.vscode/extensions.json +9 -0
  30. package/file-templates/static/.vscode/settings.json +75 -0
  31. package/file-templates/static/LICENSE +674 -0
  32. package/file-templates/static/_cspell.config.jsonc +25 -0
  33. package/file-templates/static/_gitattributes +37 -0
  34. package/file-templates/static/eslint.config.mjs +18 -0
  35. package/file-templates/static/knip.config.js +20 -0
  36. package/file-templates/static/prettier.config.mjs +24 -0
  37. package/file-templates/static/scripts/build.ts +5 -0
  38. package/file-templates/static/scripts/lint.ts +30 -0
  39. package/file-templates/static/scripts/tsconfig.json +14 -0
  40. package/file-templates/static/src/main.ts +5 -0
  41. package/file-templates/static/tsconfig.json +12 -0
  42. package/package.json +59 -0
  43. package/src/commands/CheckCommand.ts +249 -0
  44. package/src/commands/InitCommand.ts +105 -0
  45. package/src/commands/NukeCommand.ts +17 -0
  46. package/src/commands/PublishCommand.ts +242 -0
  47. package/src/commands/UpdateCommand.ts +20 -0
  48. package/src/commands/check/check.test.ts +123 -0
  49. package/src/commands/check/getTruncatedText.ts +187 -0
  50. package/src/commands/init/checkIfProjectPathExists.ts +36 -0
  51. package/src/commands/init/createProject.ts +197 -0
  52. package/src/commands/init/getAuthorName.ts +23 -0
  53. package/src/commands/init/getProjectPath.ts +112 -0
  54. package/src/commands/init/packageManager.ts +64 -0
  55. package/src/commands/init/vsCodeInit.ts +115 -0
  56. package/src/constants.ts +39 -0
  57. package/src/git.ts +182 -0
  58. package/src/interfaces/GitHubCLIHostsYAML.ts +7 -0
  59. package/src/main.ts +34 -0
  60. package/src/prompt.ts +72 -0
  61. package/src/validateNoteVersion.ts +39 -0
@@ -0,0 +1,197 @@
1
+ import chalk from "chalk";
2
+ import { repeat } from "complete-common";
3
+ import type { PackageManager } from "complete-node";
4
+ import {
5
+ $,
6
+ copyFileOrDirectory,
7
+ getFileNamesInDirectory,
8
+ getPackageManagerInstallCICommand,
9
+ getPackageManagerInstallCommand,
10
+ isFile,
11
+ makeDirectory,
12
+ readFile,
13
+ renameFile,
14
+ updatePackageJSONDependencies,
15
+ writeFile,
16
+ } from "complete-node";
17
+ import path from "node:path";
18
+ import {
19
+ ACTION_YML,
20
+ ACTION_YML_TEMPLATE_PATH,
21
+ TEMPLATES_DYNAMIC_DIR,
22
+ TEMPLATES_STATIC_DIR,
23
+ } from "../../constants.js";
24
+ import { initGitRepository } from "../../git.js";
25
+ import { promptError, promptLog } from "../../prompt.js";
26
+
27
+ export async function createProject(
28
+ projectName: string,
29
+ authorName: string | undefined,
30
+ projectPath: string,
31
+ createNewDir: boolean,
32
+ gitRemoteURL: string | undefined,
33
+ skipInstall: boolean,
34
+ packageManager: PackageManager,
35
+ ): Promise<void> {
36
+ if (createNewDir) {
37
+ makeDirectory(projectPath);
38
+ }
39
+
40
+ copyStaticFiles(projectPath);
41
+ copyDynamicFiles(projectName, authorName, projectPath, packageManager);
42
+
43
+ // There is no package manager lock files yet, so we have to pass "false" to this function.
44
+ const updated = updatePackageJSONDependencies(projectPath, false, true);
45
+ if (!updated) {
46
+ promptError(
47
+ 'Failed to update the dependencies in the "package.json" file.',
48
+ );
49
+ }
50
+
51
+ await installNodeModules(projectPath, skipInstall, packageManager);
52
+ await formatFiles(projectPath);
53
+
54
+ // Only make the initial commit once all of the files have been copied and formatted.
55
+ await initGitRepository(projectPath, gitRemoteURL);
56
+
57
+ promptLog(`Successfully created project: ${chalk.green(projectName)}`);
58
+ }
59
+
60
+ /** Copy static files, like "eslint.config.mjs", "tsconfig.json", etc. */
61
+ function copyStaticFiles(projectPath: string) {
62
+ copyTemplateDirectoryWithoutOverwriting(TEMPLATES_STATIC_DIR, projectPath);
63
+
64
+ // Rename "_gitattributes" to ".gitattributes". (If it is kept as ".gitattributes", then it won't
65
+ // be committed to git.)
66
+ const gitAttributesPath = path.join(projectPath, "_gitattributes");
67
+ const correctGitAttributesPath = path.join(projectPath, ".gitattributes");
68
+ renameFile(gitAttributesPath, correctGitAttributesPath);
69
+
70
+ // Rename "_cspell.config.jsonc" to "cspell.config.jsonc". (If it is kept as
71
+ // "cspell.config.jsonc", then local spell checking will fail.)
72
+ const cSpellConfigPath = path.join(projectPath, "_cspell.config.jsonc");
73
+ const correctCSpellConfigPath = path.join(projectPath, "cspell.config.jsonc");
74
+ renameFile(cSpellConfigPath, correctCSpellConfigPath);
75
+ }
76
+
77
+ function copyTemplateDirectoryWithoutOverwriting(
78
+ templateDirPath: string,
79
+ projectPath: string,
80
+ ) {
81
+ const fileNames = getFileNamesInDirectory(templateDirPath);
82
+ for (const fileName of fileNames) {
83
+ const templateFilePath = path.join(templateDirPath, fileName);
84
+ const destinationFilePath = path.join(projectPath, fileName);
85
+ if (!isFile(destinationFilePath)) {
86
+ copyFileOrDirectory(templateFilePath, destinationFilePath);
87
+ }
88
+ }
89
+ }
90
+
91
+ /** Copy files that need to have text replaced inside of them. */
92
+ function copyDynamicFiles(
93
+ projectName: string,
94
+ authorName: string | undefined,
95
+ projectPath: string,
96
+ packageManager: PackageManager,
97
+ ) {
98
+ // `.github/workflows/setup/action.yml`
99
+ {
100
+ const fileName = ACTION_YML;
101
+ const templatePath = ACTION_YML_TEMPLATE_PATH;
102
+ const template = readFile(templatePath);
103
+
104
+ const installCommand = getPackageManagerInstallCICommand(packageManager);
105
+ const actionYML = template
106
+ .replaceAll("PACKAGE_MANAGER_NAME", packageManager)
107
+ .replaceAll("PACKAGE_MANAGER_INSTALL_COMMAND", installCommand);
108
+
109
+ const setupPath = path.join(projectPath, ".github", "workflows", "setup");
110
+ makeDirectory(setupPath);
111
+ const destinationPath = path.join(setupPath, fileName);
112
+ writeFile(destinationPath, actionYML);
113
+ }
114
+
115
+ // `.gitignore`
116
+ {
117
+ const templatePath = path.join(
118
+ TEMPLATES_DYNAMIC_DIR,
119
+ "_gitignore", // Not named ".gitignore" to prevent npm from deleting it.
120
+ );
121
+ const template = readFile(templatePath);
122
+
123
+ // Prepend a header with the project name.
124
+ let separatorLine = "# ";
125
+ repeat(projectName.length, () => {
126
+ separatorLine += "-";
127
+ });
128
+ separatorLine += "\n";
129
+ const gitIgnoreHeader = `${separatorLine}# ${projectName}\n${separatorLine}\n`;
130
+ const nodeGitIgnorePath = path.join(
131
+ TEMPLATES_DYNAMIC_DIR,
132
+ "Node.gitignore",
133
+ );
134
+ const nodeGitIgnore = readFile(nodeGitIgnorePath);
135
+
136
+ // eslint-disable-next-line prefer-template
137
+ const gitignore = gitIgnoreHeader + template + "\n" + nodeGitIgnore;
138
+
139
+ // We need to replace the underscore with a period.
140
+ const destinationPath = path.join(projectPath, ".gitignore");
141
+ writeFile(destinationPath, gitignore);
142
+ }
143
+
144
+ // `package.json`
145
+ {
146
+ const templatePath = path.join(TEMPLATES_DYNAMIC_DIR, "package.json");
147
+ const template = readFile(templatePath);
148
+
149
+ const packageJSON = template
150
+ .replaceAll("PROJECT_NAME", projectName)
151
+ .replaceAll("AUTHOR_NAME", authorName ?? "unknown");
152
+
153
+ const destinationPath = path.join(projectPath, "package.json");
154
+ writeFile(destinationPath, packageJSON);
155
+ }
156
+
157
+ // `README.md`
158
+ {
159
+ const templatePath = path.join(TEMPLATES_DYNAMIC_DIR, "README.md");
160
+ const template = readFile(templatePath);
161
+
162
+ // "PROJECT-NAME" must be hyphenated, as using an underscore will break Prettier for some
163
+ // reason.
164
+ const command = getPackageManagerInstallCICommand(packageManager);
165
+ const readmeMD = template
166
+ .replaceAll("PROJECT-NAME", projectName)
167
+ .replaceAll("PACKAGE-MANAGER-INSTALL-COMMAND", command);
168
+ const destinationPath = path.join(projectPath, "README.md");
169
+ writeFile(destinationPath, readmeMD);
170
+ }
171
+
172
+ const srcPath = path.join(projectPath, "src");
173
+ makeDirectory(srcPath);
174
+ }
175
+
176
+ async function installNodeModules(
177
+ projectPath: string,
178
+ skipInstall: boolean,
179
+ packageManager: PackageManager,
180
+ ) {
181
+ if (skipInstall) {
182
+ return;
183
+ }
184
+
185
+ const command = getPackageManagerInstallCommand(packageManager);
186
+ promptLog(
187
+ `Installing node modules with "${command}"... (This can take a long time.)`,
188
+ );
189
+ const $$ = $({ cwd: projectPath });
190
+ const commandParts = command.split(" ");
191
+ await $$`${commandParts}`;
192
+ }
193
+
194
+ async function formatFiles(projectPath: string) {
195
+ const $$ = $({ cwd: projectPath });
196
+ await $$`prettier --write ${projectPath}`;
197
+ }
@@ -0,0 +1,23 @@
1
+ import { getGitHubUsername } from "../../git.js";
2
+ import { getInputString, promptError, promptLog } from "../../prompt.js";
3
+
4
+ export async function getAuthorName(): Promise<string | undefined> {
5
+ const gitHubUsername = getGitHubUsername();
6
+ if (gitHubUsername !== undefined) {
7
+ return gitHubUsername;
8
+ }
9
+
10
+ return await getNewAuthorName();
11
+ }
12
+
13
+ async function getNewAuthorName(): Promise<string> {
14
+ promptLog(
15
+ "The author name was not found from the GitHub CLI configuration file.",
16
+ );
17
+ const authorName = await getInputString("Enter the author of the project:");
18
+ if (authorName === "") {
19
+ promptError("You must enter an author name.");
20
+ }
21
+
22
+ return authorName;
23
+ }
@@ -0,0 +1,112 @@
1
+ import chalk from "chalk";
2
+ import { hasWhitespace, isKebabCase } from "complete-common";
3
+ import path from "node:path";
4
+ import { CURRENT_DIRECTORY_NAME, CWD } from "../../constants.js";
5
+ import {
6
+ getInputString,
7
+ getInputYesNo,
8
+ promptError,
9
+ promptLog,
10
+ } from "../../prompt.js";
11
+
12
+ // From: https://gist.github.com/doctaphred/d01d05291546186941e1b7ddc02034d3
13
+ const ILLEGAL_CHARACTERS_FOR_WINDOWS_FILENAMES = [
14
+ "<",
15
+ ">",
16
+ ":",
17
+ '"',
18
+ "/",
19
+ "\\",
20
+ "|",
21
+ "?",
22
+ "*",
23
+ ] as const;
24
+
25
+ export async function getProjectPath(
26
+ name: string | undefined,
27
+ useCurrentDirectory: boolean,
28
+ customDirectory: string | undefined,
29
+ yes: boolean,
30
+ forceName: boolean,
31
+ ): Promise<{ projectPath: string; createNewDir: boolean }> {
32
+ let projectName = name;
33
+ let projectPath: string;
34
+ let createNewDir: boolean;
35
+ if (useCurrentDirectory) {
36
+ // The "--use-current-directory" command-line flag was specified, so there is no need to prompt
37
+ // the user.
38
+ projectName = CURRENT_DIRECTORY_NAME;
39
+ projectPath = CWD;
40
+ createNewDir = false;
41
+ } else if (projectName !== undefined) {
42
+ // The project name was specified on the command-line.
43
+ const baseDirectory =
44
+ customDirectory === undefined ? CWD : path.join(CWD, customDirectory);
45
+ projectPath = path.join(baseDirectory, projectName);
46
+ createNewDir = true;
47
+ } else if (yes) {
48
+ // The "--yes" command-line flag was specified and the project name was not specified on the
49
+ // command-line, so default to using the current directory.
50
+ projectName = CURRENT_DIRECTORY_NAME;
51
+ projectPath = CWD;
52
+ createNewDir = false;
53
+ } else {
54
+ // The project name was not specified on the command-line, so prompt the user for it.
55
+ [projectName, projectPath, createNewDir] = await getNewProjectName();
56
+ }
57
+
58
+ validateProjectName(projectName, forceName);
59
+
60
+ promptLog(`Using a project name of: ${chalk.green(projectName)}`);
61
+ return { projectPath, createNewDir };
62
+ }
63
+
64
+ async function getNewProjectName(): Promise<[string, string, boolean]> {
65
+ promptLog("You did not specify a project name as a command-line argument.");
66
+ const shouldUseCurrentDir = await getInputYesNo(
67
+ `Would you like to create a new project using the current directory "${chalk.green(
68
+ CURRENT_DIRECTORY_NAME,
69
+ )}" as the root?`,
70
+ );
71
+
72
+ if (shouldUseCurrentDir) {
73
+ return [CURRENT_DIRECTORY_NAME, CWD, false];
74
+ }
75
+
76
+ const projectName = await getInputString("Enter the name of the project:");
77
+ const projectPath = path.join(CWD, projectName);
78
+
79
+ return [projectName, projectPath, true];
80
+ }
81
+
82
+ function validateProjectName(projectName: string, forceName: boolean) {
83
+ if (projectName === "") {
84
+ promptError("You cannot have a blank project name.");
85
+ }
86
+
87
+ if (process.platform === "win32") {
88
+ for (const character of ILLEGAL_CHARACTERS_FOR_WINDOWS_FILENAMES) {
89
+ if (projectName.includes(character)) {
90
+ promptError(
91
+ `The "${character}" character is not allowed in a Windows file name.`,
92
+ );
93
+ }
94
+ }
95
+ }
96
+
97
+ if (forceName) {
98
+ return;
99
+ }
100
+
101
+ if (hasWhitespace(projectName)) {
102
+ promptError(
103
+ 'The project name has whitespace in it, which is not allowed. Use kebab-case for your project name. (e.g. "green-candle")',
104
+ );
105
+ }
106
+
107
+ if (!isKebabCase(projectName)) {
108
+ promptError(
109
+ 'The project name is not in kebab-case. (Kebab-case is the style of using all lowercase letters, with words separated by hyphens.) Project names must use kebab-case to match GitHub repository standards. If necessary, you can override this check with the "--force-name" flag.',
110
+ );
111
+ }
112
+ }
@@ -0,0 +1,64 @@
1
+ import chalk from "chalk";
2
+ import { PackageManager, commandExists } from "complete-node";
3
+ import { DEFAULT_PACKAGE_MANAGER } from "../../constants.js";
4
+ import { promptError } from "../../prompt.js";
5
+
6
+ interface PackageManagerOptions {
7
+ npm: boolean;
8
+ yarn: boolean;
9
+ pnpm: boolean;
10
+ }
11
+
12
+ export function getPackageManagerUsedForNewProject(
13
+ options: PackageManagerOptions,
14
+ ): PackageManager {
15
+ const packageManagerFromOptions = getPackageManagerFromOptions(options);
16
+ if (packageManagerFromOptions !== undefined) {
17
+ return packageManagerFromOptions;
18
+ }
19
+
20
+ return DEFAULT_PACKAGE_MANAGER;
21
+ }
22
+
23
+ function getPackageManagerFromOptions(options: PackageManagerOptions) {
24
+ if (options.npm) {
25
+ const npmExists = commandExists("npm");
26
+ if (!npmExists) {
27
+ promptError(
28
+ `You specified the "--npm" option, but "${chalk.green(
29
+ "npm",
30
+ )}" does not seem to be a valid command.`,
31
+ );
32
+ }
33
+
34
+ return PackageManager.npm;
35
+ }
36
+
37
+ if (options.yarn) {
38
+ const yarnExists = commandExists("yarn");
39
+ if (!yarnExists) {
40
+ promptError(
41
+ `You specified the "--yarn" option, but "${chalk.green(
42
+ "yarn",
43
+ )}" does not seem to be a valid command.`,
44
+ );
45
+ }
46
+
47
+ return PackageManager.yarn;
48
+ }
49
+
50
+ if (options.pnpm) {
51
+ const pnpmExists = commandExists("pnpm");
52
+ if (!pnpmExists) {
53
+ promptError(
54
+ `You specified the "--pnpm" option, but "${chalk.green(
55
+ "pnpm",
56
+ )}" does not seem to be a valid command.`,
57
+ );
58
+ }
59
+
60
+ return PackageManager.pnpm;
61
+ }
62
+
63
+ return undefined;
64
+ }
@@ -0,0 +1,115 @@
1
+ import { $, commandExists, getJSONC, isFile } from "complete-node";
2
+ import path from "node:path";
3
+ import { getInputYesNo, promptError, promptLog } from "../../prompt.js";
4
+
5
+ const VS_CODE_COMMANDS = [
6
+ "code",
7
+ "codium",
8
+ "code-oss",
9
+ "code-insiders",
10
+ ] as const;
11
+
12
+ export async function vsCodeInit(
13
+ projectPath: string,
14
+ vscode: boolean,
15
+ yes: boolean,
16
+ ): Promise<void> {
17
+ const VSCodeCommand = getVSCodeCommand();
18
+ if (VSCodeCommand === undefined) {
19
+ promptLog(
20
+ 'VSCode does not seem to be installed. (The "code" command is not in the path.) Skipping VSCode-related things.',
21
+ );
22
+ return;
23
+ }
24
+
25
+ await installVSCodeExtensions(projectPath, VSCodeCommand);
26
+ await promptVSCode(projectPath, VSCodeCommand, vscode, yes);
27
+ }
28
+
29
+ function getVSCodeCommand(): string | undefined {
30
+ return VS_CODE_COMMANDS.find((command) => commandExists(command));
31
+ }
32
+
33
+ async function installVSCodeExtensions(
34
+ projectPath: string,
35
+ vsCodeCommand: string,
36
+ ) {
37
+ // Installing extensions from inside WSL on Windows will result in the VSCode process never
38
+ // exiting for some reason. Thus, skip this step on Linux. (Linux users will probably be smart
39
+ // enough to install the extensions on their own.)
40
+ if (process.platform === "linux") {
41
+ return;
42
+ }
43
+
44
+ const extensions = getExtensionsFromJSON(projectPath);
45
+ for (const extensionName of extensions) {
46
+ // eslint-disable-next-line no-await-in-loop
47
+ await $`${vsCodeCommand} --install-extension ${extensionName}`;
48
+ }
49
+ }
50
+
51
+ function getExtensionsFromJSON(projectPath: string): readonly string[] {
52
+ const extensionsJSONPath = path.join(
53
+ projectPath,
54
+ ".vscode",
55
+ "extensions.json",
56
+ );
57
+
58
+ if (!isFile(extensionsJSONPath)) {
59
+ return [];
60
+ }
61
+
62
+ const extensionsJSON = getJSONC(extensionsJSONPath);
63
+
64
+ const { recommendations } = extensionsJSON;
65
+ if (!Array.isArray(recommendations)) {
66
+ promptError(
67
+ 'The "recommendations" field in the "extensions.json" file is not an array.',
68
+ );
69
+ }
70
+
71
+ for (const recommendation of recommendations) {
72
+ if (typeof recommendation !== "string") {
73
+ promptError(
74
+ 'One of the entries in the "recommendations" field in the "extensions.json" file is not a string.',
75
+ );
76
+ }
77
+ }
78
+
79
+ return recommendations as string[];
80
+ }
81
+
82
+ async function promptVSCode(
83
+ projectPath: string,
84
+ VSCodeCommand: string,
85
+ vscode: boolean,
86
+ yes: boolean,
87
+ ): Promise<void> {
88
+ if (vscode) {
89
+ // They supplied the "--vscode" command-line flag, so there is no need to prompt the user.
90
+ await openVSCode(projectPath, VSCodeCommand);
91
+ return;
92
+ }
93
+
94
+ if (yes) {
95
+ // They supplied the "--yes" command-line flag, which implies that they want a silent install,
96
+ // so skip opening VSCode.
97
+ return;
98
+ }
99
+
100
+ // The VSCode command does not work properly inside WSL on Windows.
101
+ if (process.platform === "linux") {
102
+ return;
103
+ }
104
+
105
+ const shouldOpenVSCode = await getInputYesNo(
106
+ "Do you want to open your new project in VSCode now?",
107
+ );
108
+ if (shouldOpenVSCode) {
109
+ await openVSCode(projectPath, VSCodeCommand);
110
+ }
111
+ }
112
+
113
+ async function openVSCode(projectPath: string, VSCodeCommand: string) {
114
+ await $`${VSCodeCommand} ${projectPath}`;
115
+ }
@@ -0,0 +1,39 @@
1
+ import {
2
+ findPackageRoot,
3
+ getPackageJSONFieldsMandatory,
4
+ PackageManager,
5
+ } from "complete-node";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+
9
+ export const CWD = process.cwd();
10
+ export const CURRENT_DIRECTORY_NAME = path.basename(CWD);
11
+
12
+ export const HOME_DIR = os.homedir();
13
+
14
+ const packageRoot = findPackageRoot();
15
+ const { name, version } = getPackageJSONFieldsMandatory(
16
+ packageRoot,
17
+ "name",
18
+ "version",
19
+ );
20
+
21
+ export const PROJECT_NAME = name;
22
+ export const PROJECT_VERSION = version;
23
+
24
+ export const DEFAULT_PACKAGE_MANAGER = PackageManager.npm;
25
+
26
+ // ---------
27
+
28
+ const TEMPLATES_DIR = path.join(packageRoot, "file-templates");
29
+ export const TEMPLATES_STATIC_DIR = path.join(TEMPLATES_DIR, "static");
30
+ export const TEMPLATES_DYNAMIC_DIR = path.join(TEMPLATES_DIR, "dynamic");
31
+
32
+ export const ACTION_YML = "action.yml";
33
+ export const ACTION_YML_TEMPLATE_PATH = path.join(
34
+ TEMPLATES_DYNAMIC_DIR,
35
+ ".github",
36
+ "workflows",
37
+ "setup",
38
+ ACTION_YML,
39
+ );