@regardio/dev 1.0.1 → 1.4.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 CHANGED
@@ -35,7 +35,7 @@ Exceptions are allowed but must be intentional and documented. The goal is code
35
35
 
36
36
  ## What's inside
37
37
 
38
- - **CLI bins**: exec-clean, exec-husky, exec-p, exec-s, exec-ts, exec-tsc, lint-biome, lint-commit, lint-md
38
+ - **CLI bins**: exec-clean, exec-husky, exec-p, exec-s, exec-ts, exec-tsc, flow-release, lint-biome, lint-commit, lint-md
39
39
  - **Config presets**: Biome, Commitlint, Markdownlint, TypeScript (base/react)
40
40
  - **Testing configs**: Vitest (node/react), Playwright base config, Testing Library setup
41
41
  - **Dev dependencies**: All commonly needed testing and linting packages bundled
@@ -316,31 +316,68 @@ When you add `@regardio/dev` as a dev dependency, you get access to:
316
316
 
317
317
  ## Releasing
318
318
 
319
- This package uses [Changesets](https://github.com/changesets/changesets) for versioning and npm publishing.
319
+ This package uses [Changesets](https://github.com/changesets/changesets) for versioning and npm publishing, with a streamlined `flow-release` command that automates the entire process.
320
320
 
321
- ### Adding a Changeset
321
+ ### Quick Release (Recommended)
322
322
 
323
- When making changes that should be released:
323
+ The `flow-release` command handles everything in one step:
324
324
 
325
325
  ```bash
326
- pnpm changeset
326
+ # From the package directory:
327
+ pnpm release minor "Add new vitest configs"
328
+
329
+ # Or use the bin directly after build:
330
+ flow-release patch "Fix typo in config"
331
+ flow-release minor "Add new feature"
332
+ flow-release major "Breaking API change"
327
333
  ```
328
334
 
329
- ### Automated Release (GitHub Action)
335
+ This command:
336
+
337
+ 1. Creates a changeset file with the specified bump type and message
338
+ 2. Runs `changeset version` to update package.json and CHANGELOG
339
+ 3. Updates the lockfile (`pnpm install --ignore-workspace`)
340
+ 4. Commits all changes with `chore(release): vX.Y.Z`
341
+ 5. Pushes to the current branch
330
342
 
331
- When changesets are merged to `main`:
343
+ The GitHub Action then publishes to npm automatically.
332
344
 
333
- 1. A "Version Packages" PR is created with updated version and CHANGELOG
334
- 2. Merging that PR publishes to npm
345
+ ### Manual Release (Step by Step)
335
346
 
336
- ### Manual Release
347
+ If you prefer more control:
337
348
 
338
349
  ```bash
339
- pnpm version # Update version and CHANGELOG
340
- pnpm build # Build the package
341
- pnpm release # Publish to npm
350
+ pnpm changeset # Interactive: create changeset file
351
+ git add . && git commit # Commit the changeset
352
+ git push # Push to trigger GitHub Action
353
+ # GitHub Action creates "Version Packages" PR
354
+ # Merge that PR → publishes to npm
342
355
  ```
343
356
 
357
+ ### Reusing in Other Packages
358
+
359
+ The `flow-release` bin is available to any package that depends on `@regardio/dev`:
360
+
361
+ ```json
362
+ {
363
+ "scripts": {
364
+ "release": "flow-release"
365
+ }
366
+ }
367
+ ```
368
+
369
+ Then run:
370
+
371
+ ```bash
372
+ pnpm release minor "Your release message"
373
+ ```
374
+
375
+ **Requirements for other packages:**
376
+
377
+ 1. A `.changeset/config.json` file (copy from this package and update `repo`)
378
+ 2. A `.github/workflows/release.yml` (copy from this package)
379
+ 3. GitHub repo configured with NPM_TOKEN secret and Actions permissions
380
+
344
381
  ### GitHub Repository Setup
345
382
 
346
383
  Before the release action works, configure these in **GitHub repo settings**:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=flow-release.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-release.d.ts","sourceRoot":"","sources":["../../src/bin/flow-release.ts"],"names":[],"mappings":""}
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'node:child_process';
3
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ const args = process.argv.slice(2);
6
+ const bumpType = args[0];
7
+ const message = args.slice(1).join(' ') || 'Release update';
8
+ if (!bumpType || !['patch', 'minor', 'major'].includes(bumpType)) {
9
+ console.error('Usage: flow-release <patch|minor|major> [message]');
10
+ console.error('Example: flow-release minor "Add new vitest configs"');
11
+ process.exit(1);
12
+ }
13
+ const run = (cmd) => {
14
+ console.log(`$ ${cmd}`);
15
+ execSync(cmd, { stdio: 'inherit' });
16
+ };
17
+ const runQuiet = (cmd) => {
18
+ return execSync(cmd, { encoding: 'utf-8' }).trim();
19
+ };
20
+ try {
21
+ const status = runQuiet('git status --porcelain');
22
+ if (status) {
23
+ console.log('Working directory has uncommitted changes. Staging all changes...');
24
+ }
25
+ }
26
+ catch {
27
+ console.error('Not in a git repository');
28
+ process.exit(1);
29
+ }
30
+ const changesetDir = join(process.cwd(), '.changeset');
31
+ const changesetId = `release-${Date.now()}`;
32
+ const changesetFile = join(changesetDir, `${changesetId}.md`);
33
+ const changesetContent = `---
34
+ "@regardio/dev": ${bumpType}
35
+ ---
36
+
37
+ ${message}
38
+ `;
39
+ mkdirSync(changesetDir, { recursive: true });
40
+ writeFileSync(changesetFile, changesetContent);
41
+ console.log(`Created changeset: .changeset/${changesetId}.md`);
42
+ run('pnpm changeset version');
43
+ console.log('Updating lockfile...');
44
+ run('pnpm install --ignore-workspace');
45
+ run('git add -A');
46
+ const packageJsonPath = join(process.cwd(), 'package.json');
47
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
48
+ const { version } = packageJson;
49
+ run(`git commit -m "chore(release): v${version}"`);
50
+ const branch = runQuiet('git branch --show-current');
51
+ run(`git push origin ${branch}`);
52
+ console.log(`\n✅ Released v${version}`);
53
+ console.log('The GitHub Action will now publish to npm.');
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -2,21 +2,21 @@
2
2
  "$schema": "https://www.schemastore.org/package.json",
3
3
  "author": "Bernd Matzner <bernd.matzner@regard.io>",
4
4
  "bin": {
5
- "exec-clean": "./dist/bin/exec-clean.js",
6
- "exec-husky": "./dist/bin/exec-husky.js",
7
- "exec-p": "./dist/bin/exec-p.js",
8
- "exec-s": "./dist/bin/exec-s.js",
9
- "exec-ts": "./dist/bin/exec-ts.js",
10
- "exec-tsc": "./dist/bin/exec-tsc.js",
11
- "lint-biome": "./dist/bin/lint-biome.js",
12
- "lint-commit": "./dist/bin/lint-commit.js",
13
- "lint-md": "./dist/bin/lint-md.js"
5
+ "exec-clean": "dist/bin/exec-clean.js",
6
+ "exec-husky": "dist/bin/exec-husky.js",
7
+ "exec-p": "dist/bin/exec-p.js",
8
+ "exec-s": "dist/bin/exec-s.js",
9
+ "exec-ts": "dist/bin/exec-ts.js",
10
+ "exec-tsc": "dist/bin/exec-tsc.js",
11
+ "flow-release": "dist/bin/flow-release.js",
12
+ "lint-biome": "dist/bin/lint-biome.js",
13
+ "lint-commit": "dist/bin/lint-commit.js",
14
+ "lint-md": "dist/bin/lint-md.js"
14
15
  },
15
16
  "bugs": {
16
17
  "url": "https://github.com/regardio/dev/issues"
17
18
  },
18
- "description": "Regardio developer tooling for testing, linting, and build workflows",
19
- "devDependencies": {
19
+ "dependencies": {
20
20
  "@biomejs/biome": "2.3.10",
21
21
  "@changesets/changelog-github": "0.5.2",
22
22
  "@changesets/cli": "2.29.8",
@@ -29,7 +29,7 @@
29
29
  "@types/node": "25.0.3",
30
30
  "@vitest/ui": "4.0.16",
31
31
  "husky": "9.1.7",
32
- "jsdom": "27.3.0",
32
+ "jsdom": "27.4.0",
33
33
  "markdownlint-cli2": "0.20.0",
34
34
  "npm-run-all": "4.1.5",
35
35
  "rimraf": "6.1.2",
@@ -38,14 +38,11 @@
38
38
  "vite": "7.3.0",
39
39
  "vitest": "4.0.16"
40
40
  },
41
+ "description": "Regardio developer tooling for testing, linting, and build workflows",
41
42
  "engines": {
42
43
  "node": ">=18"
43
44
  },
44
45
  "exports": {
45
- ".": {
46
- "default": "./dist/index.js",
47
- "types": "./dist/index.d.ts"
48
- },
49
46
  "./biome": "./src/biome/preset.json",
50
47
  "./commitlint": "./src/commitlint/commitlint.cjs",
51
48
  "./markdownlint": "./src/markdownlint/markdownlint.json",
@@ -75,13 +72,18 @@
75
72
  ],
76
73
  "homepage": "https://github.com/regardio/dev/blob/main/README.md",
77
74
  "keywords": [
75
+ "biome",
76
+ "changesets",
77
+ "commitlint",
78
78
  "dev",
79
- "tooling",
80
- "testing",
79
+ "husky",
81
80
  "linting",
82
- "biome",
83
- "vitest",
84
- "playwright"
81
+ "markdownlint",
82
+ "playwright",
83
+ "testing",
84
+ "tooling",
85
+ "typescript",
86
+ "vitest"
85
87
  ],
86
88
  "license": "MIT",
87
89
  "name": "@regardio/dev",
@@ -92,7 +94,7 @@
92
94
  "repository": {
93
95
  "directory": "packages/dev",
94
96
  "type": "git",
95
- "url": "https://github.com/regardio/dev.git"
97
+ "url": "git+https://github.com/regardio/dev.git"
96
98
  },
97
99
  "scripts": {
98
100
  "build": "pnpm exec tsc -p tsconfig.build.json",
@@ -104,12 +106,12 @@
104
106
  "lint:biome": "biome check .",
105
107
  "lint:md": "markdownlint-cli2 \"**/*.md\" \"**/*.mdx\" \"!**/node_modules/**\" \"!**/dist/**\"",
106
108
  "prepare": "pnpm run build && husky",
107
- "release": "pnpm changeset publish",
109
+ "release": "pnpm exec tsx src/bin/flow-release.ts",
108
110
  "test": "run-p test:*",
109
111
  "test:unit": "vitest run",
110
112
  "version": "pnpm changeset version"
111
113
  },
112
114
  "sideEffects": false,
113
115
  "type": "module",
114
- "version": "1.0.1"
116
+ "version": "1.4.0"
115
117
  }
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * flow-release: Automate the release flow for @regardio/dev.
4
+ *
5
+ * Usage: flow-release <patch|minor|major> [message]
6
+ *
7
+ * This script:
8
+ * 1. Creates a changeset file with the specified bump type
9
+ * 2. Runs `changeset version` to apply the version bump
10
+ * 3. Updates the lockfile (pnpm install --ignore-workspace)
11
+ * 4. Commits all changes
12
+ * 5. Pushes to the current branch
13
+ *
14
+ * The GitHub Action will then publish to npm automatically.
15
+ */
16
+ import { execSync } from 'node:child_process';
17
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
18
+ import { join } from 'node:path';
19
+
20
+ const args = process.argv.slice(2);
21
+ const bumpType = args[0];
22
+ const message = args.slice(1).join(' ') || 'Release update';
23
+
24
+ if (!bumpType || !['patch', 'minor', 'major'].includes(bumpType)) {
25
+ console.error('Usage: flow-release <patch|minor|major> [message]');
26
+ console.error('Example: flow-release minor "Add new vitest configs"');
27
+ process.exit(1);
28
+ }
29
+
30
+ const run = (cmd: string) => {
31
+ console.log(`$ ${cmd}`);
32
+ execSync(cmd, { stdio: 'inherit' });
33
+ };
34
+
35
+ const runQuiet = (cmd: string): string => {
36
+ return execSync(cmd, { encoding: 'utf-8' }).trim();
37
+ };
38
+
39
+ // Ensure we're in a clean git state
40
+ try {
41
+ const status = runQuiet('git status --porcelain');
42
+ if (status) {
43
+ console.log('Working directory has uncommitted changes. Staging all changes...');
44
+ }
45
+ } catch {
46
+ console.error('Not in a git repository');
47
+ process.exit(1);
48
+ }
49
+
50
+ // Generate a unique changeset filename
51
+ const changesetDir = join(process.cwd(), '.changeset');
52
+ const changesetId = `release-${Date.now()}`;
53
+ const changesetFile = join(changesetDir, `${changesetId}.md`);
54
+
55
+ // Create the changeset file
56
+ const changesetContent = `---
57
+ "@regardio/dev": ${bumpType}
58
+ ---
59
+
60
+ ${message}
61
+ `;
62
+
63
+ mkdirSync(changesetDir, { recursive: true });
64
+ writeFileSync(changesetFile, changesetContent);
65
+ console.log(`Created changeset: .changeset/${changesetId}.md`);
66
+
67
+ // Run changeset version to apply the bump
68
+ run('pnpm changeset version');
69
+
70
+ // Update lockfile to ensure it matches package.json
71
+ // Use --ignore-workspace to update this package's lockfile independently
72
+ console.log('Updating lockfile...');
73
+ run('pnpm install --ignore-workspace');
74
+
75
+ // Stage all changes
76
+ run('git add -A');
77
+
78
+ // Get the new version
79
+ const packageJsonPath = join(process.cwd(), 'package.json');
80
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as { version: string };
81
+ const { version } = packageJson;
82
+
83
+ // Commit
84
+ run(`git commit -m "chore(release): v${version}"`);
85
+
86
+ // Push
87
+ const branch = runQuiet('git branch --show-current');
88
+ run(`git push origin ${branch}`);
89
+
90
+ console.log(`\n✅ Released v${version}`);
91
+ console.log('The GitHub Action will now publish to npm.');
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=flow-branch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"flow-branch.d.ts","sourceRoot":"","sources":["../../src/bin/flow-branch.ts"],"names":[],"mappings":""}
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawnSync } from 'node:child_process';
3
- const [expectedBranch, deploymentLabel] = process.argv.slice(2);
4
- if (!expectedBranch || !deploymentLabel) {
5
- console.error('Usage: flow-branch <expected-branch> <deployment-label>');
6
- process.exit(1);
7
- }
8
- const envBranch = process.env.GITHUB_REF_NAME || process.env.GITHUB_HEAD_REF || process.env.BRANCH_NAME || '';
9
- let currentBranch = envBranch;
10
- if (!currentBranch) {
11
- const res = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
12
- encoding: 'utf8',
13
- stdio: ['ignore', 'pipe', 'pipe'],
14
- });
15
- if (res.status !== 0) {
16
- console.error('Failed to determine the current Git branch.');
17
- if (res.stderr)
18
- console.error(res.stderr.trim());
19
- process.exit(1);
20
- }
21
- currentBranch = (res.stdout || '').toString().trim();
22
- }
23
- if (currentBranch !== expectedBranch) {
24
- console.error(`Refusing to deploy ${deploymentLabel}. Expected branch "${expectedBranch}", but current branch is "${currentBranch}".`);
25
- process.exit(1);
26
- }
27
- console.log(`Branch check passed. Proceeding with ${deploymentLabel} deployment from "${expectedBranch}".`);
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=flow-version.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"flow-version.d.ts","sourceRoot":"","sources":["../../src/bin/flow-version.ts"],"names":[],"mappings":""}
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawnSync } from 'node:child_process';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- function fail(message) {
6
- console.error(message);
7
- process.exit(1);
8
- }
9
- function run(cmd, args, options = {}) {
10
- const result = spawnSync(cmd, args, { stdio: 'inherit', ...options });
11
- if (result.status !== 0) {
12
- fail(`Command failed: ${cmd} ${args.join(' ')}`);
13
- }
14
- }
15
- const type = process.argv[2];
16
- if (!type || !['patch', 'minor', 'major'].includes(type)) {
17
- fail('Usage: flow-version <patch|minor|major>');
18
- }
19
- const pkgPath = path.resolve(process.cwd(), 'package.json');
20
- if (!fs.existsSync(pkgPath)) {
21
- fail('Error: package.json not found in current directory');
22
- }
23
- const pkgRaw = fs.readFileSync(pkgPath, 'utf8');
24
- let pkg;
25
- try {
26
- pkg = JSON.parse(pkgRaw);
27
- }
28
- catch (_e) {
29
- fail('Error: Failed to parse package.json');
30
- }
31
- const current = pkg.version || '0.0.0';
32
- console.log(`Current version: ${current}`);
33
- const [majorStr, minorStr, patchStr] = String(current).split('.');
34
- let major = Number(majorStr);
35
- let minor = Number(minorStr);
36
- let patch = Number(patchStr);
37
- switch (type) {
38
- case 'major':
39
- major += 1;
40
- minor = 0;
41
- patch = 0;
42
- break;
43
- case 'minor':
44
- minor += 1;
45
- patch = 0;
46
- break;
47
- case 'patch':
48
- patch += 1;
49
- break;
50
- }
51
- const newVersion = `${major}.${minor}.${patch}`;
52
- console.log(`New version: ${newVersion}`);
53
- pkg.version = newVersion;
54
- fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
55
- run('pnpm', ['lint']);
56
- const isMajor = type === 'major';
57
- const isPatch = type === 'patch';
58
- const conventionalType = isPatch ? 'fix' : 'feat';
59
- const scope = 'release';
60
- const subject = `v${newVersion}`;
61
- const breakingBang = isMajor ? '!' : '';
62
- const commitMessage = `${conventionalType}(${scope})${breakingBang}: ${subject}` +
63
- (isMajor ? `\n\nBREAKING CHANGE: ${subject}` : '');
64
- const branchRes = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
65
- encoding: 'utf8',
66
- });
67
- if (branchRes.status !== 0)
68
- fail('Error: Not a git repository or git not available');
69
- const currentBranch = branchRes.stdout.trim();
70
- if (currentBranch !== 'develop') {
71
- fail(`Error: You must run releases from 'develop' (current: ${currentBranch})`);
72
- }
73
- run('git', ['add', 'package.json']);
74
- run('git', ['commit', '-m', commitMessage]);
75
- run('git', ['checkout', 'main']);
76
- run('git', ['merge', 'develop', '--no-ff', '-m', commitMessage]);
77
- run('git', ['tag', '-a', `v${newVersion}`, '-m', commitMessage]);
78
- run('git', ['push', 'origin', 'main']);
79
- run('git', ['push', 'origin', '--tags']);
80
- run('git', ['checkout', 'develop']);
81
- run('git', ['merge', 'main', '--ff-only']);
82
- run('git', ['push', 'origin', 'develop']);
83
- console.log(`Released version ${newVersion} successfully!`);