@pixpilot/scaffoldfy-configs 0.40.4 → 0.42.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @pixpilot/scaffoldfy-configs
2
2
 
3
+ ## 0.42.0
4
+
5
+ ### Minor Changes
6
+
7
+ - add `--set <key=value>` option for preset prompt answers
8
+ - 0319f19: workspace-initializer: create multiple packages at once from a comma separated list of names
9
+
10
+ ## 0.41.0
11
+
12
+ ### Minor Changes
13
+
14
+ - add CodeQL workflow for private repositories
15
+
3
16
  ## 0.40.4
4
17
 
5
18
  ### Patch Changes
package/README.md CHANGED
@@ -14,6 +14,16 @@ This package provides the following scaffoldfy templates:
14
14
 
15
15
  <!-- scaffoldfy-templates:start -->
16
16
 
17
+ ### codeql-private-repo
18
+
19
+ Replaces the CodeQL workflow with the pixpilot/codeql-scanner action for private repositories
20
+
21
+ Usage:
22
+
23
+ ```sh
24
+ npx @pixpilot/scaffoldfy@latest --config https://unpkg.com/@pixpilot/scaffoldfy-configs@latest/codeql-private-repo/scaffoldfy.json
25
+ ```
26
+
17
27
  ### license-file
18
28
 
19
29
  Generate a LICENSE file with common open-source licenses
@@ -0,0 +1,39 @@
1
+ name: CodeQL Analyser
2
+
3
+ permissions:
4
+ security-events: write
5
+ actions: read
6
+ contents: read
7
+ issues: write # Required for pixpilot/codeql-scanner@main
8
+
9
+ on:
10
+ push:
11
+ branches:
12
+ - main
13
+ - master
14
+ pull_request:
15
+ branches:
16
+ - main
17
+ - master
18
+ schedule:
19
+ # ┌───────────── minute (0 - 59)
20
+ # │ ┌───────────── hour (0 - 23)
21
+ # │ │ ┌───────────── day of the month (1 - 31)
22
+ # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
23
+ # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
24
+ # │ │ │ │ │
25
+ # * * * * *
26
+ - cron: '30 1 * * 0' # Every Sunday at 01:30 UTC
27
+
28
+ jobs:
29
+ analyze:
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - name: Checkout repository
33
+ uses: actions/checkout@v4
34
+
35
+ - name: Run CodeQL Scanner
36
+ uses: pixpilot/codeql-scanner@main
37
+ with:
38
+ token: ${{ secrets.GITHUB_TOKEN }}
39
+ config-file: .github/codeql/codeql-config.yml
@@ -0,0 +1,32 @@
1
+ {
2
+ "$schema": "../node_modules/@pixpilot/scaffoldfy/schema/scaffoldfy.schema.json",
3
+ "name": "codeql-private-repo",
4
+ "description": "Replaces the CodeQL workflow with the pixpilot/codeql-scanner action for private repositories",
5
+ "prompts": [
6
+ {
7
+ "id": "isPrivateRepo",
8
+ "type": "confirm",
9
+ "message": "Is this a private repository?",
10
+ "default": {
11
+ "type": "exec",
12
+ "value": "node -e \"try{process.stdout.write(require('child_process').execSync('gh repo view --json isPrivate -q .isPrivate',{stdio:['ignore','pipe','ignore']}).toString().trim())}catch{process.stdout.write('false')}\""
13
+ }
14
+ }
15
+ ],
16
+ "tasks": [
17
+ {
18
+ "id": "codeql-private-repo-workflow",
19
+ "name": "Replace CodeQL workflow for private repo",
20
+ "description": "Overwrites the CodeQL workflow to use pixpilot/codeql-scanner",
21
+ "enabled": {
22
+ "type": "condition",
23
+ "value": "isPrivateRepo === true"
24
+ },
25
+ "type": "write",
26
+ "config": {
27
+ "templateFile": "codeql-analysis.yml",
28
+ "file": ".github/workflows/codeql-analysis.yml"
29
+ }
30
+ }
31
+ ]
32
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pixpilot/scaffoldfy-configs",
3
3
  "type": "module",
4
- "version": "0.40.4",
4
+ "version": "0.42.0",
5
5
  "author": "PixPilot <m.doaie@hotmail.com>",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -29,11 +29,11 @@
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.18.11",
31
31
  "eslint": "^9.38.0",
32
- "@internal/vitest-config": "0.1.0",
32
+ "@internal/tsdown-config": "0.1.0",
33
33
  "@internal/eslint-config": "0.3.0",
34
+ "@internal/vitest-config": "0.1.0",
34
35
  "@internal/prettier-config": "0.0.1",
35
- "@pixpilot/scaffoldfy": "0.55.1",
36
- "@internal/tsdown-config": "0.1.0"
36
+ "@pixpilot/scaffoldfy": "0.56.0"
37
37
  },
38
38
  "prettier": "@internal/prettier-config",
39
39
  "publishConfig": {
@@ -0,0 +1,101 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import process from 'node:process';
6
+ import { afterEach, describe, expect, it } from 'vitest';
7
+
8
+ const SCRIPT_PATH = path.join(
9
+ __dirname,
10
+ '..',
11
+ 'workspace-initializer',
12
+ 'scripts',
13
+ 'create-packages.cjs',
14
+ );
15
+ const temporaryDirectories: string[] = [];
16
+
17
+ afterEach(() => {
18
+ for (const directory of temporaryDirectories.splice(0)) {
19
+ fs.rmSync(directory, { force: true, recursive: true });
20
+ }
21
+ });
22
+
23
+ /**
24
+ * Put a fake `pnpm` on PATH that appends its arguments to a log file
25
+ */
26
+ function createFakePnpm(): { binDirectory: string; logPath: string } {
27
+ const testDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'create-packages-'));
28
+ temporaryDirectories.push(testDirectory);
29
+
30
+ const binDirectory = path.join(testDirectory, 'bin');
31
+ const logPath = path.join(testDirectory, 'calls.log');
32
+ const fakePnpmScript = path.join(binDirectory, 'fake-pnpm.cjs');
33
+ fs.mkdirSync(binDirectory, { recursive: true });
34
+ fs.writeFileSync(
35
+ fakePnpmScript,
36
+ `require('node:fs').appendFileSync(${JSON.stringify(logPath)}, process.argv.slice(2).join(' ') + '\\n');`,
37
+ );
38
+
39
+ if (process.platform === 'win32') {
40
+ fs.writeFileSync(
41
+ path.join(binDirectory, 'pnpm.cmd'),
42
+ `@"${process.execPath}" "${fakePnpmScript}" %*\r\n`,
43
+ );
44
+ } else {
45
+ const pnpmPath = path.join(binDirectory, 'pnpm');
46
+ fs.writeFileSync(
47
+ pnpmPath,
48
+ `#!/bin/sh\n"${process.execPath}" "${fakePnpmScript}" "$@"\n`,
49
+ );
50
+ fs.chmodSync(pnpmPath, 0o755);
51
+ }
52
+
53
+ return { binDirectory, logPath };
54
+ }
55
+
56
+ function runScript(packageNames: string, binDirectory: string) {
57
+ const pathKey =
58
+ Object.keys(process.env).find((key) => key.toUpperCase() === 'PATH') ?? 'PATH';
59
+ return spawnSync(process.execPath, [SCRIPT_PATH], {
60
+ encoding: 'utf8',
61
+ env: {
62
+ ...process.env,
63
+ [pathKey]: `${binDirectory}${path.delimiter}${process.env[pathKey] ?? ''}`,
64
+ PACKAGE_NAMES: packageNames,
65
+ },
66
+ });
67
+ }
68
+
69
+ describe('workspace-initializer create-packages script', () => {
70
+ it('runs the package generator once per comma separated name', () => {
71
+ const { binDirectory, logPath } = createFakePnpm();
72
+
73
+ const result = runScript(' pkg-a, pkg-b ,,@scope/pkg-c ', binDirectory);
74
+
75
+ expect(result.status).toBe(0);
76
+ expect(fs.readFileSync(logPath, 'utf8').trim().split(/\r?\n/u)).toEqual([
77
+ 'run gen:package --set packageBaseName=pkg-a',
78
+ 'run gen:package --set packageBaseName=pkg-b',
79
+ 'run gen:package --set packageBaseName=@scope/pkg-c',
80
+ ]);
81
+ });
82
+
83
+ it('skips when no names are given', () => {
84
+ const { binDirectory, logPath } = createFakePnpm();
85
+
86
+ const result = runScript(' , ', binDirectory);
87
+
88
+ expect(result.status).toBe(0);
89
+ expect(fs.existsSync(logPath)).toBe(false);
90
+ });
91
+
92
+ it('rejects names with shell characters', () => {
93
+ const { binDirectory, logPath } = createFakePnpm();
94
+
95
+ const result = runScript('pkg-a, bad;rm -rf', binDirectory);
96
+
97
+ expect(result.status).toBe(1);
98
+ expect(result.stderr).toContain('Invalid package name(s): bad;rm -rf');
99
+ expect(fs.existsSync(logPath)).toBe(false);
100
+ });
101
+ });
@@ -7,6 +7,7 @@
7
7
  "../license-file/scaffoldfy.json",
8
8
  "../update-root-package-json/scaffoldfy.json",
9
9
  "../security-policy/scaffoldfy.json",
10
+ "../codeql-private-repo/scaffoldfy.json",
10
11
  "../monorepo-generate-packages-section/scaffoldfy.json"
11
12
  ],
12
13
  "name": "pnpm-turbo-monorepo-template-setup",
@@ -21,8 +22,18 @@
21
22
  {
22
23
  "id": "createFirstPackagePrompt",
23
24
  "type": "confirm",
24
- "message": "Create the first package now?",
25
+ "message": "Create packages now?",
25
26
  "default": false
27
+ },
28
+ {
29
+ "id": "packageNames",
30
+ "type": "input",
31
+ "message": "Enter package names (comma separated, e.g. my-package, my-other-package)",
32
+ "required": true,
33
+ "enabled": {
34
+ "type": "condition",
35
+ "value": "createFirstPackagePrompt === true"
36
+ }
26
37
  }
27
38
  ],
28
39
  "tasks": [
@@ -87,12 +98,19 @@
87
98
  },
88
99
  {
89
100
  "id": "create-first-package",
90
- "name": "Create first package",
91
- "description": "Generate the first package in the monorepo using the package generator",
92
- "type": "exec",
101
+ "name": "Create packages",
102
+ "description": "Generate each requested package in the monorepo using the package generator",
103
+ "type": "exec-file",
104
+ "enabled": {
105
+ "type": "condition",
106
+ "value": "createFirstPackagePrompt === true"
107
+ },
93
108
  "config": {
94
- "command": "pnpm run gen:package",
95
- "condition": "createFirstPackagePrompt"
109
+ "file": "./scripts/create-packages.cjs",
110
+ "runtime": "node",
111
+ "parameters": {
112
+ "PACKAGE_NAMES": "{{packageNames}}"
113
+ }
96
114
  }
97
115
  },
98
116
  {
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable node/prefer-global/process */
3
+ /**
4
+ * Runs the workspace package generator once per package name, pre-filling
5
+ * the package name prompt so only the remaining prompts are asked.
6
+ *
7
+ * Usage:
8
+ * PACKAGE_NAMES="pkg-a, pkg-b" node create-packages.cjs
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ const { spawnSync } = require('node:child_process');
14
+
15
+ const SAFE_NAME = /^[\w.@/-]+$/u;
16
+
17
+ const names = (process.env.PACKAGE_NAMES || '')
18
+ .split(',')
19
+ .map((name) => name.trim())
20
+ .filter(Boolean);
21
+
22
+ if (names.length === 0) {
23
+ console.log('No package names provided, skipping package creation.');
24
+ process.exit(0);
25
+ }
26
+
27
+ const invalid = names.filter((name) => !SAFE_NAME.test(name));
28
+ if (invalid.length > 0) {
29
+ console.error(`Invalid package name(s): ${invalid.join(', ')}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ for (const [index, name] of names.entries()) {
34
+ console.log(`\nCreating package ${index + 1}/${names.length}: ${name}\n`);
35
+
36
+ const result = spawnSync(
37
+ 'pnpm',
38
+ ['run', 'gen:package', '--set', `packageBaseName=${name}`],
39
+ { stdio: 'inherit', shell: true },
40
+ );
41
+
42
+ if (result.status !== 0) {
43
+ console.error(`Failed to create package: ${name}`);
44
+ process.exit(result.status ?? 1);
45
+ }
46
+ }