gorig-cli 1.0.23 → 1.0.25
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 +112 -22
- package/commands/create.js +267 -112
- package/commands/doc.js +21 -8
- package/commands/init.js +316 -255
- package/commands/skill.js +55 -17
- package/package.json +1 -1
- package/templates/config.go.ejs +6 -5
- package/templates/config.yaml.ejs +3 -38
- package/templates/controller.go.ejs +11 -42
- package/templates/crud.controller.go.ejs +71 -0
- package/templates/crud.doc.md.ejs +60 -0
- package/templates/crud.dto.go.ejs +103 -0
- package/templates/crud.integration.init_test.go.ejs +17 -0
- package/templates/crud.integration_test.go.ejs +66 -0
- package/templates/crud.model.go.ejs +25 -0
- package/templates/crud.module.README.md.ejs +70 -0
- package/templates/crud.mongo.config.yaml.ejs +19 -0
- package/templates/crud.mysql.config.yaml.ejs +14 -0
- package/templates/crud.router.go.ejs +18 -0
- package/templates/crud.service.go.ejs +179 -0
- package/templates/crud.test.go.ejs +52 -0
- package/templates/dto.go.ejs +16 -0
- package/templates/gitignore.ejs +18 -49
- package/templates/hello.controller.go.ejs +19 -0
- package/templates/hello.router.go.ejs +12 -0
- package/templates/hello.service.go.ejs +31 -0
- package/templates/hello.test.go.ejs +34 -0
- package/templates/init.go.ejs +1 -27
- package/templates/main.go.ejs +2 -5
- package/templates/model.go.ejs +3 -4
- package/templates/project.README.md.ejs +35 -0
- package/templates/router.go.ejs +4 -8
- package/templates/service.go.ejs +25 -77
- package/templates/skills/gorig-backend/SKILL.md +89 -0
- package/templates/skills/gorig-backend/agents/openai.yaml +4 -0
- package/templates/skills/gorig-backend/assets/api-doc-template.md +59 -0
- package/templates/skills/gorig-backend/assets/gorig.gitignore +65 -0
- package/templates/skills/gorig-backend/assets/module-readme-template.md +58 -0
- package/templates/skills/gorig-backend/references/advanced-data-access.md +275 -0
- package/templates/skills/gorig-backend/references/auth-security.md +194 -0
- package/templates/skills/gorig-backend/references/business-scenarios.md +155 -0
- package/templates/skills/gorig-backend/references/cache.md +301 -0
- package/templates/skills/gorig-backend/references/capability-matrix.md +37 -0
- package/templates/skills/gorig-backend/references/configuration.md +48 -0
- package/templates/skills/gorig-backend/references/framework-api.md +190 -0
- package/templates/skills/gorig-backend/references/messaging.md +143 -0
- package/templates/skills/gorig-backend/references/onboarding-files.md +46 -0
- package/templates/skills/gorig-backend/references/outbound-http.md +162 -0
- package/templates/skills/gorig-backend/references/persistent-crud.md +332 -0
- package/templates/skills/gorig-backend/references/project-bootstrap.md +128 -0
- package/templates/skills/gorig-backend/references/scheduled-tasks.md +231 -0
- package/templates/skills/gorig-backend/references/service-lifecycle.md +51 -0
- package/templates/skills/gorig-backend/references/source-map.md +43 -0
- package/templates/skills/gorig-backend/references/source-policy.md +58 -0
- package/templates/skills/gorig-backend/references/sse.md +121 -0
- package/templates/skills/gorig-backend/references/testing.md +171 -0
- package/templates/skills/gorig-backend/scripts/check-source-links.sh +48 -0
- package/templates/skills/gorig-backend/scripts/detect-gorig-context.sh +67 -0
- package/templates/skills/gorig-backend/scripts/verify-basic-project.sh +108 -0
- package/npm_publish copy.sh +0 -65
- package/templates/internal.go.ejs +0 -49
- package/templates/req.go.ejs +0 -8
- package/templates/resp.go.ejs +0 -8
- package/templates/service.pub.go.ejs +0 -22
- package/templates/skills/claude/gorig-backend/SKILL.md +0 -189
- package/templates/skills/claude/gorig-backend/assets/api-doc-template.md +0 -50
- package/templates/skills/claude/gorig-backend/assets/module-readme-template.md +0 -46
- package/templates/skills/claude/gorig-backend/references/onboarding-files.md +0 -38
- package/templates/skills/codex/gorig-backend/SKILL.md +0 -189
- package/templates/skills/codex/gorig-backend/agents/openai.yaml +0 -4
- package/templates/skills/codex/gorig-backend/assets/api-doc-template.md +0 -50
- package/templates/skills/codex/gorig-backend/assets/module-readme-template.md +0 -46
- package/templates/skills/codex/gorig-backend/references/onboarding-files.md +0 -38
package/commands/init.js
CHANGED
|
@@ -2,292 +2,353 @@ import fs from 'fs-extra';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ejs from 'ejs';
|
|
5
|
-
import {
|
|
5
|
+
import { execFile, spawn } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
6
7
|
import { fileURLToPath } from 'url';
|
|
7
8
|
import readline from 'readline';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = path.dirname(__filename);
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
});
|
|
14
|
+
const DEFAULT_GORIG_VERSION = 'latest';
|
|
15
|
+
const DEFAULT_PORT = 9527;
|
|
16
|
+
const ENVIRONMENTS = ['local', 'dev', 'prod'];
|
|
17
|
+
|
|
18
|
+
const printUsage = () => {
|
|
19
|
+
console.log(chalk.yellow(
|
|
20
|
+
'Usage: gorig-cli init <project-name> [--module <go-module>] [--gorig-version <version>] ' +
|
|
21
|
+
'[--gorig-replace <path>] [--port <port>] [--force] [--start|--no-start] [--no-git]',
|
|
22
|
+
));
|
|
24
23
|
};
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
25
|
+
const readOptionValue = (args, index, name) => {
|
|
26
|
+
const arg = args[index];
|
|
27
|
+
const prefix = `${name}=`;
|
|
28
|
+
if (arg.startsWith(prefix)) {
|
|
29
|
+
return { value: arg.slice(prefix.length), nextIndex: index };
|
|
30
|
+
}
|
|
31
|
+
if (index + 1 >= args.length || args[index + 1].startsWith('--')) {
|
|
32
|
+
throw new Error(`Missing value for ${name}`);
|
|
33
|
+
}
|
|
34
|
+
return { value: args[index + 1], nextIndex: index + 1 };
|
|
37
35
|
};
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
export const parseInitArgs = (args) => {
|
|
38
|
+
if (args.length === 0 || args[0].startsWith('--')) {
|
|
39
|
+
throw new Error('Project name is required');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const projectName = args[0];
|
|
43
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(projectName)) {
|
|
44
|
+
throw new Error('Project name may contain only letters, digits, dot, underscore, and hyphen');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const options = {
|
|
48
|
+
projectName,
|
|
49
|
+
moduleName: projectName,
|
|
50
|
+
gorigVersion: DEFAULT_GORIG_VERSION,
|
|
51
|
+
gorigReplace: '',
|
|
52
|
+
port: DEFAULT_PORT,
|
|
53
|
+
force: false,
|
|
54
|
+
start: false,
|
|
55
|
+
git: true,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
let startFlag = '';
|
|
59
|
+
|
|
60
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
61
|
+
const arg = args[i];
|
|
62
|
+
if (arg === '--force') {
|
|
63
|
+
options.force = true;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (arg === '--start') {
|
|
67
|
+
options.start = true;
|
|
68
|
+
startFlag = startFlag && startFlag !== arg ? 'conflict' : arg;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (arg === '--no-start') {
|
|
72
|
+
options.start = false;
|
|
73
|
+
startFlag = startFlag && startFlag !== arg ? 'conflict' : arg;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (arg === '--no-git') {
|
|
77
|
+
options.git = false;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const valueOptions = ['--module', '--gorig-version', '--gorig-replace', '--port'];
|
|
82
|
+
const optionName = valueOptions.find((name) => arg === name || arg.startsWith(`${name}=`));
|
|
83
|
+
if (!optionName) {
|
|
84
|
+
throw new Error(`Unknown init option: ${arg}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const { value, nextIndex } = readOptionValue(args, i, optionName);
|
|
88
|
+
i = nextIndex;
|
|
89
|
+
|
|
90
|
+
if (optionName === '--module') {
|
|
91
|
+
options.moduleName = value;
|
|
92
|
+
} else if (optionName === '--gorig-version') {
|
|
93
|
+
options.gorigVersion = value;
|
|
94
|
+
} else if (optionName === '--gorig-replace') {
|
|
95
|
+
options.gorigReplace = value;
|
|
96
|
+
} else if (optionName === '--port') {
|
|
97
|
+
options.port = Number(value);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (startFlag === 'conflict') {
|
|
102
|
+
throw new Error('Use only one of --start or --no-start');
|
|
103
|
+
}
|
|
104
|
+
if (!options.moduleName || /\s/.test(options.moduleName)) {
|
|
105
|
+
throw new Error('Go module name must be non-empty and contain no whitespace');
|
|
106
|
+
}
|
|
107
|
+
if (!options.gorigVersion || options.gorigVersion.startsWith('-')) {
|
|
108
|
+
throw new Error('Gorig version must be a version, commit, branch, or latest');
|
|
109
|
+
}
|
|
110
|
+
if (!Number.isInteger(options.port) || options.port < 1 || options.port > 65533) {
|
|
111
|
+
throw new Error('Port must be an integer between 1 and 65533');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return options;
|
|
50
115
|
};
|
|
51
116
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
117
|
+
const run = async (command, args, cwd) => {
|
|
118
|
+
try {
|
|
119
|
+
return await execFileAsync(command, args, {
|
|
120
|
+
cwd,
|
|
121
|
+
env: process.env,
|
|
122
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
58
123
|
});
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (answer.toLowerCase() === 'y') {
|
|
64
|
-
resolve(true);
|
|
65
|
-
} else {
|
|
66
|
-
resolve(false);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
});
|
|
124
|
+
} catch (error) {
|
|
125
|
+
const detail = error.stderr?.trim() || error.stdout?.trim() || error.message;
|
|
126
|
+
throw new Error(`${command} ${args.join(' ')} failed: ${detail}`);
|
|
127
|
+
}
|
|
71
128
|
};
|
|
72
129
|
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
130
|
+
const getGoVersion = async () => {
|
|
131
|
+
const { stdout } = await run('go', ['version'], process.cwd());
|
|
132
|
+
const match = stdout.match(/go version go(\d+)\.(\d+)(?:\.(\d+))?/);
|
|
133
|
+
if (!match) {
|
|
134
|
+
throw new Error(`Unable to parse Go version: ${stdout.trim()}`);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
raw: stdout.trim(),
|
|
138
|
+
major: Number(match[1]),
|
|
139
|
+
minor: Number(match[2]),
|
|
140
|
+
};
|
|
141
|
+
};
|
|
80
142
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
143
|
+
const readGoDirective = async (goModPath) => {
|
|
144
|
+
const content = await fs.readFile(goModPath, 'utf8');
|
|
145
|
+
const match = content.match(/^go\s+(\d+)\.(\d+)(?:\.\d+)?$/m);
|
|
146
|
+
if (!match) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return { major: Number(match[1]), minor: Number(match[2]), value: `${match[1]}.${match[2]}` };
|
|
150
|
+
};
|
|
86
151
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
});
|
|
96
|
-
});
|
|
152
|
+
const assertCompatibleGo = (installed, required) => {
|
|
153
|
+
if (!required) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (installed.major < required.major ||
|
|
157
|
+
(installed.major === required.major && installed.minor < required.minor)) {
|
|
158
|
+
throw new Error(`Gorig requires Go ${required.value}+, but ${installed.raw} is installed`);
|
|
159
|
+
}
|
|
97
160
|
};
|
|
98
161
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
162
|
+
const configureGorig = async (projectDir, invocationDir, options, installedGo) => {
|
|
163
|
+
if (options.gorigReplace) {
|
|
164
|
+
const source = path.resolve(invocationDir, options.gorigReplace);
|
|
165
|
+
const sourceGoMod = path.join(source, 'go.mod');
|
|
166
|
+
if (!await fs.pathExists(sourceGoMod)) {
|
|
167
|
+
throw new Error(`Gorig replacement does not contain go.mod: ${source}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const requiredGo = await readGoDirective(sourceGoMod);
|
|
171
|
+
assertCompatibleGo(installedGo, requiredGo);
|
|
172
|
+
|
|
173
|
+
const requiredVersion = options.gorigVersion === 'latest' ? 'v0.0.0' : options.gorigVersion;
|
|
174
|
+
await run('go', ['mod', 'edit', `-require=github.com/jom-io/gorig@${requiredVersion}`], projectDir);
|
|
175
|
+
await run('go', ['mod', 'edit', `-replace=github.com/jom-io/gorig=${source}`], projectDir);
|
|
176
|
+
} else {
|
|
177
|
+
await run('go', ['get', `github.com/jom-io/gorig@${options.gorigVersion}`], projectDir);
|
|
104
178
|
}
|
|
105
179
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
180
|
+
const { stdout } = await run(
|
|
181
|
+
'go',
|
|
182
|
+
['list', '-m', '-json', 'github.com/jom-io/gorig'],
|
|
183
|
+
projectDir,
|
|
184
|
+
);
|
|
185
|
+
const moduleInfo = JSON.parse(stdout);
|
|
186
|
+
return {
|
|
187
|
+
version: moduleInfo.Version || options.gorigVersion,
|
|
188
|
+
replacement: moduleInfo.Replace?.Dir || '',
|
|
189
|
+
};
|
|
190
|
+
};
|
|
110
191
|
|
|
111
|
-
|
|
112
|
-
const
|
|
192
|
+
const askOverwriteConfirmation = (projectDir) => new Promise((resolve) => {
|
|
193
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
194
|
+
rl.question(
|
|
195
|
+
chalk.yellow(`Directory ${chalk.bold(projectDir)} is not empty. Overwrite it? (y/N): `),
|
|
196
|
+
(answer) => {
|
|
197
|
+
rl.close();
|
|
198
|
+
resolve(answer.toLowerCase() === 'y');
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
});
|
|
113
202
|
|
|
114
|
-
|
|
203
|
+
const prepareProjectDirectory = async (projectDir, force) => {
|
|
204
|
+
if (!await fs.pathExists(projectDir)) {
|
|
205
|
+
await fs.ensureDir(projectDir);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const entries = await fs.readdir(projectDir);
|
|
210
|
+
if (entries.length === 0) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let overwrite = force;
|
|
215
|
+
if (!overwrite && process.stdin.isTTY) {
|
|
216
|
+
overwrite = await askOverwriteConfirmation(projectDir);
|
|
217
|
+
}
|
|
218
|
+
if (!overwrite) {
|
|
219
|
+
throw new Error(`Directory is not empty: ${projectDir}. Use --force to replace it.`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await fs.remove(projectDir);
|
|
223
|
+
await fs.ensureDir(projectDir);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const render = async (templateName, destination, data) => {
|
|
227
|
+
const templatePath = path.join(__dirname, '../templates', templateName);
|
|
228
|
+
const content = await ejs.renderFile(templatePath, data);
|
|
229
|
+
await fs.ensureDir(path.dirname(destination));
|
|
230
|
+
await fs.writeFile(destination, content);
|
|
231
|
+
};
|
|
115
232
|
|
|
233
|
+
const initializeGit = async (projectDir) => {
|
|
116
234
|
try {
|
|
117
|
-
|
|
118
|
-
await
|
|
119
|
-
console.log(chalk.green('
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
235
|
+
await run('git', ['--version'], projectDir);
|
|
236
|
+
await run('git', ['init'], projectDir);
|
|
237
|
+
console.log(chalk.green('Git repository initialized.'));
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.log(chalk.yellow(`Skipping Git initialization: ${error.message}`));
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const startProject = async (projectDir, mode) => new Promise((resolve, reject) => {
|
|
244
|
+
console.log(chalk.blue(`Starting project with GORIG_SYS_MODE=${mode}...`));
|
|
245
|
+
const child = spawn('go', ['run', './_cmd'], {
|
|
246
|
+
cwd: projectDir,
|
|
247
|
+
env: { ...process.env, GORIG_SYS_MODE: mode },
|
|
248
|
+
stdio: 'inherit',
|
|
249
|
+
});
|
|
250
|
+
child.once('error', reject);
|
|
251
|
+
child.once('close', (code, signal) => {
|
|
252
|
+
if (code === 0 || signal === 'SIGINT') {
|
|
253
|
+
resolve();
|
|
254
|
+
return;
|
|
131
255
|
}
|
|
256
|
+
reject(new Error(`Project exited with code ${code ?? 'unknown'}`));
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
export const initProject = async (options, runtime = {}) => {
|
|
261
|
+
const invocationDir = runtime.cwd || process.cwd();
|
|
262
|
+
const projectDir = path.join(invocationDir, options.projectName);
|
|
263
|
+
const projectNameUpper = options.projectName.toUpperCase().replace(/[^A-Z0-9]+/g, '_');
|
|
264
|
+
const projectPrefix = options.projectName.toLowerCase().replace(/[^a-z0-9]+/g, '_');
|
|
265
|
+
const installedGo = await getGoVersion();
|
|
266
|
+
|
|
267
|
+
console.log(chalk.blue(`Starting project initialization: ${chalk.bold(options.projectName)}`));
|
|
268
|
+
console.log(chalk.green(installedGo.raw));
|
|
269
|
+
|
|
270
|
+
await prepareProjectDirectory(projectDir, options.force);
|
|
271
|
+
await Promise.all([
|
|
272
|
+
'_bin',
|
|
273
|
+
'_cmd',
|
|
274
|
+
'domain/hello',
|
|
275
|
+
'global',
|
|
276
|
+
'test/_bin',
|
|
277
|
+
].map((dir) => fs.ensureDir(path.join(projectDir, dir))));
|
|
278
|
+
|
|
279
|
+
await run('go', ['mod', 'init', options.moduleName], projectDir);
|
|
280
|
+
const dependency = await configureGorig(projectDir, invocationDir, options, installedGo);
|
|
281
|
+
|
|
282
|
+
for (let index = 0; index < ENVIRONMENTS.length; index += 1) {
|
|
283
|
+
const mode = ENVIRONMENTS[index];
|
|
284
|
+
await render('config.yaml.ejs', path.join(projectDir, '_bin', `${mode}.yaml`), {
|
|
285
|
+
projectNameUpper,
|
|
286
|
+
projectPrefix,
|
|
287
|
+
mode,
|
|
288
|
+
port: options.port + index,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
132
291
|
|
|
133
|
-
|
|
134
|
-
|
|
292
|
+
const commonData = {
|
|
293
|
+
projectName: options.projectName,
|
|
294
|
+
projectNameUpper,
|
|
295
|
+
moduleName: options.moduleName,
|
|
296
|
+
localPort: options.port,
|
|
297
|
+
devPort: options.port + 1,
|
|
298
|
+
prodPort: options.port + 2,
|
|
299
|
+
gorigVersion: dependency.version,
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
await Promise.all([
|
|
303
|
+
render('main.go.ejs', path.join(projectDir, '_cmd/main.go'), commonData),
|
|
304
|
+
render('init.go.ejs', path.join(projectDir, 'domain/init.go'), commonData),
|
|
305
|
+
render('hello.router.go.ejs', path.join(projectDir, 'domain/hello/router.go'), commonData),
|
|
306
|
+
render('hello.controller.go.ejs', path.join(projectDir, 'domain/hello/controller.go'), commonData),
|
|
307
|
+
render('hello.service.go.ejs', path.join(projectDir, 'domain/hello/service.go'), commonData),
|
|
308
|
+
render('config.go.ejs', path.join(projectDir, 'global/config.go'), commonData),
|
|
309
|
+
render('hello.test.go.ejs', path.join(projectDir, 'test/hello_test.go'), commonData),
|
|
310
|
+
render('project.README.md.ejs', path.join(projectDir, 'README.md'), commonData),
|
|
311
|
+
render('gitignore.ejs', path.join(projectDir, '.gitignore'), commonData),
|
|
312
|
+
render('config.yaml.ejs', path.join(projectDir, 'test/_bin/local.yaml'), {
|
|
313
|
+
projectNameUpper,
|
|
314
|
+
projectPrefix,
|
|
315
|
+
mode: 'local',
|
|
316
|
+
port: options.port,
|
|
317
|
+
}),
|
|
318
|
+
]);
|
|
319
|
+
|
|
320
|
+
await run('go', ['mod', 'tidy'], projectDir);
|
|
321
|
+
await run('go', ['fmt', './...'], projectDir);
|
|
322
|
+
if (options.git) {
|
|
323
|
+
await initializeGit(projectDir);
|
|
324
|
+
}
|
|
135
325
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const goModPath = path.join(projectDir, 'go.mod');
|
|
145
|
-
const goModContent = `module ${projectName}\n\ngo 1.20\n`;
|
|
146
|
-
await fs.writeFile(goModPath, goModContent);
|
|
147
|
-
console.log(chalk.green(`Successfully created ${chalk.bold('go.mod')} file`));
|
|
148
|
-
|
|
149
|
-
// 添加 gorig 依赖
|
|
150
|
-
console.log(chalk.blue('Adding gorig dependency, please wait...'));
|
|
151
|
-
await addGorigDependency(projectDir);
|
|
152
|
-
console.log(chalk.green(`Successfully added the latest version of github.com/jom-io/gorig dependency`));
|
|
153
|
-
|
|
154
|
-
// 创建 _bin 目录下的配置文件
|
|
155
|
-
const binDir = path.join(projectDir, '_bin');
|
|
156
|
-
const configTemplatePath = path.join(__dirname, '../templates/config.yaml.ejs');
|
|
157
|
-
|
|
158
|
-
const environments = ['dev', 'local', 'prod'];
|
|
159
|
-
for (const env of environments) {
|
|
160
|
-
const configFilePath = path.join(binDir, `${env}.yaml`);
|
|
161
|
-
const configContent = await ejs.renderFile(configTemplatePath, {
|
|
162
|
-
projectNameUpper,
|
|
163
|
-
projectPrefix,
|
|
164
|
-
mode: env,
|
|
165
|
-
});
|
|
166
|
-
await fs.writeFile(configFilePath, configContent);
|
|
167
|
-
console.log(chalk.green(`Successfully created ${chalk.bold(`${env}.yaml`)} file`));
|
|
168
|
-
}
|
|
326
|
+
console.log(chalk.green(`Project created at ${projectDir}`));
|
|
327
|
+
console.log(chalk.green(`Gorig version: ${dependency.version}`));
|
|
328
|
+
if (dependency.replacement) {
|
|
329
|
+
console.log(chalk.green(`Gorig replacement: ${dependency.replacement}`));
|
|
330
|
+
}
|
|
331
|
+
console.log(chalk.cyan(`Run: cd ${options.projectName} && GORIG_SYS_MODE=local go run ./_cmd`));
|
|
332
|
+
console.log(chalk.cyan(`Verify: curl 'http://127.0.0.1:${options.port}/ping'`));
|
|
333
|
+
console.log(chalk.cyan(`Verify: curl 'http://127.0.0.1:${options.port}/hello?name=Gorig'`));
|
|
169
334
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
console.log(chalk.green(`Successfully created ${chalk.bold('init.go')} file`));
|
|
177
|
-
|
|
178
|
-
// 创建 _cmd/main.go 文件
|
|
179
|
-
const cmdDir = path.join(projectDir, '_cmd');
|
|
180
|
-
const mainGoPath = path.join(cmdDir, 'main.go');
|
|
181
|
-
const mainGoTemplatePath = path.join(__dirname, '../templates/main.go.ejs');
|
|
182
|
-
const mainGoContent = await ejs.renderFile(mainGoTemplatePath, { projectName });
|
|
183
|
-
await fs.writeFile(mainGoPath, mainGoContent);
|
|
184
|
-
console.log(chalk.green(`Successfully created ${chalk.bold('main.go')} file`));
|
|
185
|
-
|
|
186
|
-
// 创建 global/config.go 文件
|
|
187
|
-
const globalDir = path.join(projectDir, 'global');
|
|
188
|
-
const configGoPath = path.join(globalDir, 'config.go');
|
|
189
|
-
const configGoTemplatePath = path.join(__dirname, '../templates/config.go.ejs');
|
|
190
|
-
const configGoContent = await ejs.renderFile(configGoTemplatePath, { projectNameUpper });
|
|
191
|
-
await fs.writeFile(configGoPath, configGoContent);
|
|
192
|
-
console.log(chalk.green(`Successfully created ${chalk.bold('config.go')} file`));
|
|
193
|
-
|
|
194
|
-
// 创建 cron/cron.go 文件
|
|
195
|
-
const cronDir = path.join(projectDir, 'cron');
|
|
196
|
-
const cronGoPath = path.join(cronDir, 'cron.go');
|
|
197
|
-
const cronGoTemplatePath = path.join(__dirname, '../templates/cron.go.ejs');
|
|
198
|
-
const cronGoContent = await ejs.renderFile(cronGoTemplatePath, {});
|
|
199
|
-
await fs.writeFile(cronGoPath, cronGoContent);
|
|
200
|
-
console.log(chalk.green(`Successfully created ${chalk.bold('cron.go')} file`));
|
|
201
|
-
|
|
202
|
-
// 创建.gitignore 文件 从 templates 目录中复制 gitignore.ejs 文件
|
|
203
|
-
const gitignoreTemplatePath = path.join(__dirname, '../templates/gitignore.ejs');
|
|
204
|
-
const gitignorePath = path.join(projectDir, '.gitignore');
|
|
205
|
-
await fs.copyFile(gitignoreTemplatePath, gitignorePath);
|
|
206
|
-
|
|
207
|
-
// 检测如果本机存在git,则初始化git仓库
|
|
208
|
-
try {
|
|
209
|
-
exec('git', ['--version']);
|
|
210
|
-
exec('git init', { cwd: projectDir }, (err) => {
|
|
211
|
-
if (err) {
|
|
212
|
-
console.error(chalk.red('Git initialization failed:'), err);
|
|
213
|
-
} else {
|
|
214
|
-
console.log(chalk.green('Git repository initialized.'));
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
} catch {
|
|
218
|
-
console.log(chalk.yellow('Git is not installed on this system. Skipping Git initialization.'));
|
|
219
|
-
}
|
|
220
|
-
// 运行 go mod tidy
|
|
221
|
-
console.log(chalk.blue('Organizing Go module dependencies (go mod tidy), please wait...'));
|
|
222
|
-
await runGoModTidy(projectDir);
|
|
223
|
-
console.log(chalk.green('Successfully organized Go module dependencies'));
|
|
224
|
-
|
|
225
|
-
// 提示用户项目创建成功
|
|
226
|
-
console.log(chalk.blue(`\nProject ${chalk.bold(projectName)} has been successfully created in ${chalk.bold(projectDir)} directory`));
|
|
227
|
-
console.log(chalk.yellow('\nHow to run the project:'));
|
|
228
|
-
console.log(chalk.green(`1. Enter the project directory: cd ${projectName}`));
|
|
229
|
-
console.log(chalk.green(`2. Use Go command to run the project:`));
|
|
230
|
-
console.log(chalk.cyan(` go run _cmd/main.go`));
|
|
231
|
-
console.log(chalk.green(`\nOr compile and run directly:`));
|
|
232
|
-
console.log(chalk.cyan(` go build -o ${projectName} _cmd/main.go && ./${projectName}`));
|
|
233
|
-
|
|
234
|
-
// 询问用户是否启动项目
|
|
235
|
-
const shouldStart = await askStartConfirmation();
|
|
236
|
-
if (shouldStart) {
|
|
237
|
-
// 启动项目
|
|
238
|
-
console.log(chalk.blue('\nStarting the project...'));
|
|
239
|
-
try {
|
|
240
|
-
const goProcess = spawn('go', ['run', '_cmd/main.go'], {
|
|
241
|
-
cwd: projectDir,
|
|
242
|
-
stdio: ['inherit', 'pipe', 'pipe'] // 继承 stdin 和 stdout,pipe stderr
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
goProcess.on('error', (err) => {
|
|
246
|
-
console.error(chalk.red('Error starting project:'), chalk.redBright(err.message));
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
goProcess.on('close', (code) => {
|
|
250
|
-
if (code !== 0) {
|
|
251
|
-
console.error(chalk.red(`Project process exited with code ${code}`));
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// 检查 goProcess.stdout 是否存在
|
|
256
|
-
if (goProcess.stdout) {
|
|
257
|
-
goProcess.stdout.on('data', (data) => { // 监听 stdout
|
|
258
|
-
const output = data.toString();
|
|
259
|
-
process.stdout.write(output); // 将输出写入控制台
|
|
260
|
-
if (output.includes('System startup successful')) {
|
|
261
|
-
console.log(chalk.green(`\nVisit ${chalk.bold('http://localhost:9527')} to view the project`));
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
} else {
|
|
265
|
-
console.error(chalk.red('stdout is not available.'));
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// 检查 goProcess.stderr 是否存在
|
|
269
|
-
// if (goProcess.stderr) {
|
|
270
|
-
// goProcess.stderr.on('data', (data) => { // 监听 stderr
|
|
271
|
-
// const errorOutput = data.toString();
|
|
272
|
-
// if (errorOutput.includes('System startup successful')) {
|
|
273
|
-
// console.log(chalk.green(`\nVisit ${chalk.bold('http://localhost:9527')} to view the project`));
|
|
274
|
-
// } else {
|
|
275
|
-
// console.error(chalk.red(`Error: ${errorOutput}`));
|
|
276
|
-
// }
|
|
277
|
-
// });
|
|
278
|
-
// } else {
|
|
279
|
-
// console.error(chalk.red('stderr is not available.'));
|
|
280
|
-
// }
|
|
281
|
-
|
|
282
|
-
} catch (error) {
|
|
283
|
-
console.error(chalk.red('Error starting project:'), chalk.redBright(error.message));
|
|
284
|
-
}
|
|
285
|
-
} else {
|
|
286
|
-
console.log(chalk.blue('\nProject initialization completed without starting the project.'));
|
|
287
|
-
}
|
|
335
|
+
if (options.start) {
|
|
336
|
+
await startProject(projectDir, 'local');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return { projectDir, dependency };
|
|
340
|
+
};
|
|
288
341
|
|
|
342
|
+
const initModule = async (args) => {
|
|
343
|
+
try {
|
|
344
|
+
const options = parseInitArgs(args);
|
|
345
|
+
await initProject(options);
|
|
346
|
+
return 0;
|
|
289
347
|
} catch (error) {
|
|
290
|
-
console.error(chalk.red('
|
|
348
|
+
console.error(chalk.red('Failed to initialize project:'), chalk.redBright(error.message));
|
|
349
|
+
printUsage();
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
return 1;
|
|
291
352
|
}
|
|
292
353
|
};
|
|
293
354
|
|