cmyr-template-cli 1.32.2 → 1.33.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/dist/plopfile.js CHANGED
@@ -148,7 +148,7 @@ const TEMPLATES_META_LIST = [
148
148
  language: 'typescript',
149
149
  runtime: 'nodejs',
150
150
  vueVersion: 0,
151
- docker: false,
151
+ docker: true,
152
152
  priority: 0,
153
153
  },
154
154
  {
@@ -349,6 +349,28 @@ async function createGithubRepo(authToken, data) {
349
349
  return null;
350
350
  }
351
351
  }
352
+ async function replaceGithubRepositoryTopics(authToken, data) {
353
+ try {
354
+ const { owner, repo, topics } = data;
355
+ const resp = await axios__default["default"]({
356
+ url: `/repos/${owner}/${repo}/topics`,
357
+ baseURL: GITHUB_API_URL,
358
+ method: 'PUT',
359
+ headers: {
360
+ Authorization: `Bearer ${authToken}`,
361
+ Accept: 'application/vnd.github+json',
362
+ },
363
+ data: {
364
+ names: topics,
365
+ },
366
+ });
367
+ return resp.data;
368
+ }
369
+ catch (error) {
370
+ console.error(error);
371
+ return null;
372
+ }
373
+ }
352
374
  async function loadTemplateCliConfig() {
353
375
  const paths = [process.cwd(), os__default["default"].homedir()].map((e) => path__default["default"].join(e, '.ctrc'));
354
376
  const [local, home] = (await Promise.all(paths.map(async (p) => {
@@ -433,7 +455,7 @@ async function initProject(answers) {
433
455
  }
434
456
  async function init(projectPath, answers) {
435
457
  var _a;
436
- const { template, isOpenSource, isInitReadme, isInitContributing, isInitHusky, isInitSemanticRelease, isInitDocker, isInitJest } = answers;
458
+ const { template, isOpenSource, isInitReadme, isInitContributing, isInitHusky, isInitSemanticRelease, isInitDocker, isInitTest } = answers;
437
459
  try {
438
460
  const templateMeta = getTemplateMeta(template);
439
461
  await asyncExec('git --version', {
@@ -477,8 +499,8 @@ async function init(projectPath, answers) {
477
499
  await initTsconfig(projectPath, answers);
478
500
  await initEslint(projectPath, answers);
479
501
  await initStylelint(projectPath);
480
- if (isInitJest) {
481
- await initJest(projectPath);
502
+ if (isInitTest) {
503
+ await initTest(projectPath, answers);
482
504
  }
483
505
  await sortProjectJson(projectPath);
484
506
  await initYarn(projectPath, answers);
@@ -574,10 +596,11 @@ async function getGitUserName() {
574
596
  return username === null || username === void 0 ? void 0 : username.trim();
575
597
  }
576
598
  async function initRemoteGitRepo(projectPath, answers) {
577
- var _a, _b;
599
+ var _a, _b, _c, _d, _e;
578
600
  const loading = ora__default["default"]('正在初始化远程 Git 仓库……').start();
579
601
  try {
580
- const { name, description, gitRemoteUrl, isOpenSource, isInitRemoteRepo } = answers;
602
+ const { name, description, gitRemoteUrl, isOpenSource, isInitRemoteRepo, keywords, template } = answers;
603
+ const templateMeta = getTemplateMeta(template);
581
604
  if (!gitRemoteUrl) {
582
605
  loading.fail('未找到远程 Git 仓库地址,请自行初始化!');
583
606
  return;
@@ -613,6 +636,29 @@ async function initRemoteGitRepo(projectPath, answers) {
613
636
  if ((resp === null || resp === void 0 ? void 0 : resp.status) >= 200) {
614
637
  loading.succeed('远程 Git 仓库初始化成功!');
615
638
  console.info(colors__default["default"].green(`远程 Git 仓库地址 ${(_a = resp.data) === null || _a === void 0 ? void 0 : _a.html_url}`));
639
+ const owner = (_c = (_b = resp.data) === null || _b === void 0 ? void 0 : _b.owner) === null || _c === void 0 ? void 0 : _c.login;
640
+ const repo = (_d = resp.data) === null || _d === void 0 ? void 0 : _d.name;
641
+ if (owner && repo) {
642
+ console.info(colors__default["default"].green('正在初始化仓库 topics !'));
643
+ if (templateMeta.docker) {
644
+ keywords.push('docker');
645
+ }
646
+ if (templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.language) {
647
+ keywords.push(templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.language);
648
+ }
649
+ if (templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.runtime) {
650
+ keywords.push(templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.runtime);
651
+ }
652
+ if ((templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.vueVersion) === 3) {
653
+ keywords.push('vue3');
654
+ }
655
+ await replaceGithubRepositoryTopics(authToken, {
656
+ owner,
657
+ repo,
658
+ topics: lodash.uniq(keywords).map((e) => kebabCase(e)),
659
+ });
660
+ console.info(colors__default["default"].green('仓库 topics 初始化成功!'));
661
+ }
616
662
  }
617
663
  else {
618
664
  loading.fail('远程 Git 仓库初始化失败!');
@@ -633,7 +679,7 @@ async function initRemoteGitRepo(projectPath, answers) {
633
679
  });
634
680
  if ((resp === null || resp === void 0 ? void 0 : resp.status) >= 200) {
635
681
  loading.succeed('远程 Git 仓库初始化成功!');
636
- console.info(colors__default["default"].green(`远程 Git 仓库地址 ${(_b = resp.data) === null || _b === void 0 ? void 0 : _b.html_url}`));
682
+ console.info(colors__default["default"].green(`远程 Git 仓库地址 ${(_e = resp.data) === null || _e === void 0 ? void 0 : _e.html_url}`));
637
683
  }
638
684
  else {
639
685
  loading.fail('远程 Git 仓库初始化失败!');
@@ -1300,7 +1346,7 @@ async function initDocker(projectPath, answers) {
1300
1346
  const loading = ora__default["default"]('正在初始化 Docker ……').start();
1301
1347
  try {
1302
1348
  const templateMeta = getTemplateMeta(answers.template);
1303
- const files = ['.dockerignore', 'docker-compose.yml'];
1349
+ const files = ['.dockerignore', 'docker-compose.yml', '.github/workflows/docker.yml'];
1304
1350
  await copyFilesFromTemplates(projectPath, files);
1305
1351
  let dockerfile = 'Dockerfile';
1306
1352
  const newPath = path__default["default"].join(projectPath, 'Dockerfile');
@@ -1319,7 +1365,7 @@ async function initDocker(projectPath, answers) {
1319
1365
  if (!await fs__default["default"].pathExists(scriptsDir)) {
1320
1366
  await fs__default["default"].mkdir(scriptsDir);
1321
1367
  }
1322
- await copyFilesFromTemplates(projectPath, ['scripts/minify-docker.js']);
1368
+ await copyFilesFromTemplates(projectPath, ['scripts/minify-docker.cjs']);
1323
1369
  }
1324
1370
  const pkg = await getProjectJson(projectPath);
1325
1371
  const mainFile = pkg === null || pkg === void 0 ? void 0 : pkg.main;
@@ -1347,35 +1393,69 @@ async function initDocker(projectPath, answers) {
1347
1393
  loading.fail('Docker 初始化失败!');
1348
1394
  }
1349
1395
  }
1350
- async function initJest(projectPath) {
1351
- const loading = ora__default["default"]('正在初始化 Jest ……').start();
1396
+ async function initTest(projectPath, answers) {
1397
+ var _a, _b;
1398
+ const loading = ora__default["default"]('正在初始化测试 ……').start();
1352
1399
  try {
1353
- const files = ['jest.config.ts'];
1354
- await copyFilesFromTemplates(projectPath, files);
1355
- const pkg = await getProjectJson(projectPath);
1356
- const devDependencies = {
1357
- '@types/jest': '^29.5.12',
1358
- jest: '^29.7.0',
1359
- 'ts-jest': '^29.1.2',
1360
- 'ts-node': '^10.9.2',
1361
- };
1362
- const newPkg = lodash.merge({}, pkg, {
1363
- scripts: {
1364
- test: 'jest --config jest.config.ts',
1365
- 'test:coverage': 'jest --config jest.config.ts --coverage',
1366
- ...pkg === null || pkg === void 0 ? void 0 : pkg.scripts,
1367
- },
1368
- devDependencies: {
1369
- ...devDependencies,
1370
- ...pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies,
1371
- },
1372
- });
1373
- newPkg.jest = undefined;
1374
- await saveProjectJson(projectPath, newPkg);
1375
- loading.succeed('Jest 初始化成功!');
1400
+ if (answers.isInitTest === 'vitest') {
1401
+ const files = ['vitest.config.ts'];
1402
+ await copyFilesFromTemplates(projectPath, files);
1403
+ const pkg = await getProjectJson(projectPath);
1404
+ const devDependencies = {
1405
+ vitest: '^2.1.6',
1406
+ };
1407
+ if (!((_a = pkg === null || pkg === void 0 ? void 0 : pkg.dependencies) === null || _a === void 0 ? void 0 : _a.vite) && !((_b = pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies) === null || _b === void 0 ? void 0 : _b.vite)) {
1408
+ devDependencies.vite = '^6.0.1';
1409
+ }
1410
+ const newPkg = lodash.merge({}, pkg, {
1411
+ scripts: {
1412
+ test: 'vitest run',
1413
+ 'test:coverage': 'vitest run --coverage',
1414
+ ...pkg === null || pkg === void 0 ? void 0 : pkg.scripts,
1415
+ },
1416
+ devDependencies: {
1417
+ ...devDependencies,
1418
+ ...pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies,
1419
+ },
1420
+ });
1421
+ await saveProjectJson(projectPath, newPkg);
1422
+ loading.succeed('Vitest 初始化成功!');
1423
+ return;
1424
+ }
1425
+ if (answers.isInitTest === 'jest') {
1426
+ const files = ['jest.config.ts'];
1427
+ await copyFilesFromTemplates(projectPath, files);
1428
+ const pkg = await getProjectJson(projectPath);
1429
+ const devDependencies = {
1430
+ '@types/jest': '^29.5.12',
1431
+ jest: '^29.7.0',
1432
+ 'ts-jest': '^29.1.2',
1433
+ 'ts-node': '^10.9.2',
1434
+ };
1435
+ const newPkg = lodash.merge({}, pkg, {
1436
+ scripts: {
1437
+ test: 'jest --config jest.config.ts',
1438
+ 'test:coverage': 'jest --config jest.config.ts --coverage',
1439
+ ...pkg === null || pkg === void 0 ? void 0 : pkg.scripts,
1440
+ },
1441
+ devDependencies: {
1442
+ ...devDependencies,
1443
+ ...pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies,
1444
+ },
1445
+ });
1446
+ newPkg.jest = undefined;
1447
+ await saveProjectJson(projectPath, newPkg);
1448
+ loading.succeed('Jest 初始化成功!');
1449
+ return;
1450
+ }
1451
+ if (answers.isInitTest === 'none') {
1452
+ loading.succeed('未选择测试框架,跳过测试初始化');
1453
+ return;
1454
+ }
1455
+ loading.succeed('未选择测试框架,跳过测试初始化');
1376
1456
  }
1377
1457
  catch (error) {
1378
- loading.fail('Jest 初始化失败!');
1458
+ loading.fail('测试初始化失败!');
1379
1459
  }
1380
1460
  }
1381
1461
  async function jsFileExtRename(projectPath) {
@@ -1693,7 +1773,11 @@ module.exports = function (plop) {
1693
1773
  },
1694
1774
  default(answers) {
1695
1775
  const templateMeta = getTemplateMeta(answers.template);
1696
- return ['nodejs'].includes(templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.runtime) ? 'cjs' : '';
1776
+ if (!['nodejs'].includes(templateMeta === null || templateMeta === void 0 ? void 0 : templateMeta.runtime)) {
1777
+ return '';
1778
+ }
1779
+ const nodeVersion = Number(process.version.split('.')[0].slice(1)) - 4;
1780
+ return nodeVersion >= 18 ? 'esm' : 'cjs';
1697
1781
  },
1698
1782
  when(answers) {
1699
1783
  const templateMeta = getTemplateMeta(answers.template);
@@ -1840,11 +1924,14 @@ module.exports = function (plop) {
1840
1924
  },
1841
1925
  },
1842
1926
  {
1843
- type: 'confirm',
1844
- name: 'isInitJest',
1845
- message: '是否初始化 jest?',
1927
+ type: 'list',
1928
+ name: 'isInitTest',
1929
+ message: '请选择测试框架',
1930
+ choices() {
1931
+ return ['vitest', 'jest', 'none'];
1932
+ },
1846
1933
  default(answers) {
1847
- return answers.isPublishToNpm;
1934
+ return answers.isPublishToNpm ? 'vitest' : 'none';
1848
1935
  },
1849
1936
  when(answers) {
1850
1937
  return answers.isOpenSource;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cmyr-template-cli",
3
- "version": "1.32.2",
3
+ "version": "1.33.0",
4
4
  "description": "草梅友仁自制的项目模板创建器",
5
5
  "author": "CaoMeiYouRen",
6
6
  "license": "MIT",
@@ -0,0 +1,108 @@
1
+ name: Publish Docker Image
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ # 仅取消针对当前工作流正在进行的作业或运行
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ test:
16
+ name: Test
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Setup pnpm
22
+ uses: pnpm/action-setup@v4
23
+ with:
24
+ version: "latest"
25
+ - name: Setup Node.js@lts environment
26
+ uses: actions/setup-node@v4
27
+ with:
28
+ node-version: "lts/*"
29
+ cache: "pnpm"
30
+ - name: Cache Dependency
31
+ uses: actions/cache@v4
32
+ with:
33
+ path: |
34
+ ~/.npm
35
+ ~/.yarn
36
+ ~/.cache/pnpm
37
+ ~/cache
38
+ !~/cache/exclude
39
+ **/node_modules
40
+ key: pnpm-${{ runner.os }}-${{ hashFiles('package.json') }}
41
+ restore-keys: pnpm-${{ runner.os }}
42
+ - run: pnpm i --frozen-lockfile
43
+ - run: pnpm run lint
44
+ - run: pnpm run build
45
+ - run: pnpm run test
46
+ build:
47
+ needs: test # 等待 test 执行成功
48
+ runs-on: ubuntu-latest
49
+ timeout-minutes: 30
50
+ permissions:
51
+ packages: write
52
+ contents: read
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ with:
56
+ persist-credentials: false
57
+ - name: Set up QEMU
58
+ uses: docker/setup-qemu-action@v3
59
+ - name: Set up Docker Buildx
60
+ uses: docker/setup-buildx-action@v3
61
+ - name: Login to GitHub Container Registry
62
+ uses: docker/login-action@v3
63
+ with:
64
+ registry: ghcr.io
65
+ username: ${{ github.actor }}
66
+ password: ${{ secrets.GITHUB_TOKEN }}
67
+ # - name: Login to Docker Hub
68
+ # uses: docker/login-action@v3
69
+ # with:
70
+ # username: ${{ secrets.DOCKER_USERNAME }}
71
+ # password: ${{ secrets.DOCKER_PASSWORD }}
72
+ # - name: Login to Alibaba Cloud Container Registry
73
+ # uses: docker/login-action@v3
74
+ # with:
75
+ # registry: registry.cn-hangzhou.aliyuncs.com
76
+ # username: ${{ secrets.ALIYUN_USERNAME }}
77
+ # password: ${{ secrets.ALIYUN_PASSWORD }}
78
+ - name: Extract Docker metadata
79
+ id: metadata
80
+ uses: docker/metadata-action@v5
81
+ with:
82
+ # 发布到 docker.io / ghcr.io / registry.cn-hangzhou.aliyuncs.com
83
+ # registry.cn-hangzhou.aliyuncs.com/${{ github.repository }}
84
+ images: |
85
+ ${{ github.repository }}
86
+ ghcr.io/${{ github.repository }}
87
+ tags: |
88
+ type=raw,value=latest,enable=true
89
+ type=raw,value={{date 'YYYY-MM-DD' tz='Asia/Shanghai'}},enable=true
90
+ type=sha,format=short,prefix=sha-,enable=true
91
+ flavor: latest=false
92
+ - name: Build and push Docker images
93
+ uses: docker/build-push-action@v5
94
+ with:
95
+ context: .
96
+ file: ./Dockerfile
97
+ # 推送到 dockerhub
98
+ push: false
99
+ tags: ${{ steps.metadata.outputs.tags }}
100
+ labels: ${{ steps.metadata.outputs.labels }}
101
+ platforms: linux/amd64,linux/arm64
102
+ # - name: Docker Hub README & description sync
103
+ # uses: meeDamian/sync-readme@v1.0.6
104
+ # with:
105
+ # user: ${{ secrets.DOCKER_USERNAME }}
106
+ # pass: ${{ secrets.DOCKER_PASSWORD }}
107
+ # slug: ${{ github.repository }}
108
+ # description: "基于 Hono 和 TypeScript 的云函数模板"
@@ -1,7 +1,7 @@
1
1
  FROM caomeiyouren/alpine-nodejs:latest AS nodejs
2
2
 
3
- RUN npm config set registry https://registry.npmmirror.com && \
4
- pnpm config set registry https://registry.npmmirror.com
3
+ # RUN npm config set registry https://registry.npmmirror.com && \
4
+ # pnpm config set registry https://registry.npmmirror.com
5
5
 
6
6
  FROM caomeiyouren/alpine-nodejs-minimize:latest AS runtime
7
7
 
@@ -28,7 +28,7 @@ RUN pnpm add @vercel/nft@0.24.4 fs-extra@11.2.0 --save-prod
28
28
  COPY --from=builder /app /app
29
29
 
30
30
  RUN export PROJECT_ROOT=/app/ && \
31
- node /app/scripts/minify-docker.js && \
31
+ node /app/scripts/minify-docker.cjs && \
32
32
  rm -rf /app/node_modules /app/scripts && \
33
33
  mv /app/app-minimal/node_modules /app/ && \
34
34
  rm -rf /app/app-minimal
@@ -0,0 +1,19 @@
1
+ import path from 'path'
2
+ import { defineConfig } from 'vitest/config'
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ globals: true,
7
+ environment: 'node',
8
+ },
9
+ resolve: {
10
+ alias: {
11
+ '@': path.resolve(__dirname, 'src'),
12
+ },
13
+ },
14
+ root: path.resolve('./'),
15
+ coverage: {
16
+ clean: true,
17
+ reportsDirectory: path.resolve('./coverage'),
18
+ },
19
+ })