browser-commander 0.4.0 → 0.5.3
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 +53 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/scripts/validate-changeset.mjs +11 -2
- package/scripts/version-and-commit.mjs +3 -1
- package/src/core/engine-adapter.js +14 -2
- package/tests/helpers/mocks.js +5 -18
- package/tests/unit/core/engine-adapter.test.js +83 -0
- package/.github/workflows/release.yml +0 -296
- package/LICENSE +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8b86dd7: Include README.md in npm package
|
|
8
|
+
|
|
9
|
+
Added language-specific README.md files for each implementation:
|
|
10
|
+
- js/README.md: JavaScript/npm-specific documentation with installation and API usage
|
|
11
|
+
- rust/README.md: Rust/Cargo-specific documentation
|
|
12
|
+
- Root README.md: Common overview linking to both implementations
|
|
13
|
+
|
|
14
|
+
The npm package now includes the JavaScript-specific README.md directly from the js/ directory.
|
|
15
|
+
|
|
16
|
+
## 0.5.2
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 87224ee: Fix package.json path in version-and-commit.mjs for monorepo structure
|
|
21
|
+
|
|
22
|
+
The git show command uses repository root paths, not the workflow's working directory. Since this is a monorepo with js/ and rust/ folders, the path must be js/package.json instead of just package.json.
|
|
23
|
+
|
|
24
|
+
This was causing "Unexpected end of JSON input" errors when the script tried to read package.json from the repository root (which doesn't exist) instead of js/package.json.
|
|
25
|
+
|
|
26
|
+
## 0.5.1
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 2b22f43: Fix PlaywrightAdapter.evaluateOnPage() to spread multiple arguments correctly
|
|
31
|
+
|
|
32
|
+
When using `evaluateOnPage()` with multiple arguments, the arguments are now properly spread to the function in the browser context, matching Puppeteer's behavior.
|
|
33
|
+
|
|
34
|
+
Previously, the function would receive the entire array as its first parameter instead of spread arguments, causing issues like invalid selectors when passing selector + array combinations.
|
|
35
|
+
|
|
36
|
+
## 0.5.0
|
|
37
|
+
|
|
38
|
+
### Minor Changes
|
|
39
|
+
|
|
40
|
+
- adfccde: Add Rust implementation with parallel JavaScript codebase reorganization
|
|
41
|
+
|
|
42
|
+
This introduces a complete Rust translation of the browser-commander library alongside the existing JavaScript implementation. The codebase is now organized into two parallel structures:
|
|
43
|
+
- `js/` - JavaScript implementation (all existing functionality preserved)
|
|
44
|
+
- `rust/` - New Rust implementation with the same modular architecture
|
|
45
|
+
|
|
46
|
+
Key features of the Rust implementation:
|
|
47
|
+
- Unified API across multiple browser engines (chromiumoxide, fantoccini)
|
|
48
|
+
- Core types and traits (constants, engine adapter, logger)
|
|
49
|
+
- Element operations (selectors, visibility, content)
|
|
50
|
+
- User interactions (click, scroll, fill)
|
|
51
|
+
- Browser management (launcher, navigation)
|
|
52
|
+
- General utilities (URL handling, wait operations)
|
|
53
|
+
- High-level DRY utilities
|
|
54
|
+
- Comprehensive test coverage with 106 tests
|
|
55
|
+
|
|
3
56
|
## 0.4.0
|
|
4
57
|
|
|
5
58
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Browser Commander
|
|
2
2
|
|
|
3
|
-
A universal browser automation library that supports both Playwright and Puppeteer with a unified API. The key focus is on **stoppable page triggers** - ensuring automation logic is properly mounted/unmounted during page navigation.
|
|
3
|
+
A universal browser automation library for JavaScript/TypeScript that supports both Playwright and Puppeteer with a unified API. The key focus is on **stoppable page triggers** - ensuring automation logic is properly mounted/unmounted during page navigation.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -332,4 +332,4 @@ See [src/ARCHITECTURE.md](src/ARCHITECTURE.md) for detailed architecture documen
|
|
|
332
332
|
|
|
333
333
|
## License
|
|
334
334
|
|
|
335
|
-
[UNLICENSE](LICENSE)
|
|
335
|
+
[UNLICENSE](../LICENSE)
|
package/package.json
CHANGED
|
@@ -15,7 +15,10 @@ import { readFileSync, readdirSync, existsSync } from 'fs';
|
|
|
15
15
|
import { join } from 'path';
|
|
16
16
|
|
|
17
17
|
const PACKAGE_NAME = 'browser-commander';
|
|
18
|
+
// When running from js/ directory, the changeset dir is local
|
|
18
19
|
const CHANGESET_DIR = '.changeset';
|
|
20
|
+
// But git diff output uses repository-root relative paths
|
|
21
|
+
const GIT_CHANGESET_PATH = 'js/.changeset';
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Ensure a git commit is available locally, fetching if necessary
|
|
@@ -46,13 +49,19 @@ function parseAddedChangesets(diffOutput) {
|
|
|
46
49
|
continue;
|
|
47
50
|
}
|
|
48
51
|
const [status, filePath] = line.split('\t');
|
|
52
|
+
// Check both local (.changeset/) and repo-root (js/.changeset/) paths
|
|
53
|
+
const isChangeset =
|
|
54
|
+
filePath.startsWith(`${CHANGESET_DIR}/`) ||
|
|
55
|
+
filePath.startsWith(`${GIT_CHANGESET_PATH}/`);
|
|
49
56
|
if (
|
|
50
57
|
status === 'A' &&
|
|
51
|
-
|
|
58
|
+
isChangeset &&
|
|
52
59
|
filePath.endsWith('.md') &&
|
|
53
60
|
!filePath.endsWith('README.md')
|
|
54
61
|
) {
|
|
55
|
-
|
|
62
|
+
// Extract just the filename
|
|
63
|
+
const fileName = filePath.split('/').pop();
|
|
64
|
+
addedChangesets.push(fileName);
|
|
56
65
|
}
|
|
57
66
|
}
|
|
58
67
|
return addedChangesets;
|
|
@@ -126,7 +126,9 @@ function countChangesets() {
|
|
|
126
126
|
*/
|
|
127
127
|
async function getVersion(source = 'local') {
|
|
128
128
|
if (source === 'remote') {
|
|
129
|
-
|
|
129
|
+
// Use js/package.json for monorepo structure
|
|
130
|
+
// The workflow runs with working-directory: js, but git show uses repo root paths
|
|
131
|
+
const result = await $`git show origin/main:js/package.json`.run({
|
|
130
132
|
capture: true,
|
|
131
133
|
});
|
|
132
134
|
return JSON.parse(result.stdout).version;
|
|
@@ -304,13 +304,25 @@ export class PlaywrightAdapter extends EngineAdapter {
|
|
|
304
304
|
|
|
305
305
|
async evaluateOnPage(fn, args = []) {
|
|
306
306
|
// Playwright only accepts a single argument (can be array/object)
|
|
307
|
+
// To match Puppeteer's behavior where args are spread, we wrap the function
|
|
308
|
+
// and pass all args as a single array, then apply them in the browser context
|
|
307
309
|
if (args.length === 0) {
|
|
308
310
|
return await this.page.evaluate(fn);
|
|
309
311
|
} else if (args.length === 1) {
|
|
310
312
|
return await this.page.evaluate(fn, args[0]);
|
|
311
313
|
} else {
|
|
312
|
-
// Multiple args -
|
|
313
|
-
|
|
314
|
+
// Multiple args - wrap function to accept array and spread them
|
|
315
|
+
// This makes Playwright behave like Puppeteer's spread behavior
|
|
316
|
+
// We pass the function string and args array, then reconstruct and call in browser
|
|
317
|
+
const fnString = fn.toString();
|
|
318
|
+
return await this.page.evaluate(
|
|
319
|
+
({ fnStr, argsArray }) => {
|
|
320
|
+
// Reconstruct the function in browser context and call with spread args
|
|
321
|
+
const reconstructedFn = new Function(`return (${fnStr})`)();
|
|
322
|
+
return reconstructedFn(...argsArray);
|
|
323
|
+
},
|
|
324
|
+
{ fnStr: fnString, argsArray: args }
|
|
325
|
+
);
|
|
314
326
|
}
|
|
315
327
|
}
|
|
316
328
|
|
package/tests/helpers/mocks.js
CHANGED
|
@@ -105,28 +105,15 @@ export function createMockPlaywrightPage(options = {}) {
|
|
|
105
105
|
return locs.map((l) => l.evaluate(fn, ...args));
|
|
106
106
|
},
|
|
107
107
|
locator: locatorMock,
|
|
108
|
-
evaluate
|
|
108
|
+
// Playwright's page.evaluate() only accepts a single argument (not spread)
|
|
109
|
+
// This is the key difference from Puppeteer
|
|
110
|
+
evaluate: async (fn, arg) => {
|
|
109
111
|
if (evaluateResult !== null) {
|
|
110
112
|
return evaluateResult;
|
|
111
113
|
}
|
|
112
|
-
// Create mock window/document context
|
|
113
|
-
const mockContext = {
|
|
114
|
-
innerHeight: 800,
|
|
115
|
-
innerWidth: 1200,
|
|
116
|
-
sessionStorage: {
|
|
117
|
-
_data: {},
|
|
118
|
-
getItem: (key) => mockContext.sessionStorage._data[key] || null,
|
|
119
|
-
setItem: (key, val) => {
|
|
120
|
-
mockContext.sessionStorage._data[key] = val;
|
|
121
|
-
},
|
|
122
|
-
removeItem: (key) => {
|
|
123
|
-
delete mockContext.sessionStorage._data[key];
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
querySelectorAll: () => [],
|
|
127
|
-
};
|
|
128
114
|
try {
|
|
129
|
-
|
|
115
|
+
// Playwright passes exactly one argument (can be object/array)
|
|
116
|
+
return fn(arg);
|
|
130
117
|
} catch {
|
|
131
118
|
return fn;
|
|
132
119
|
}
|
|
@@ -78,6 +78,53 @@ describe('engine-adapter', () => {
|
|
|
78
78
|
const count = await adapter.count('button');
|
|
79
79
|
assert.strictEqual(count, 5);
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
describe('evaluateOnPage', () => {
|
|
83
|
+
it('should handle zero arguments', async () => {
|
|
84
|
+
page = createMockPlaywrightPage();
|
|
85
|
+
adapter = new PlaywrightAdapter(page);
|
|
86
|
+
const result = await adapter.evaluateOnPage(() => 42);
|
|
87
|
+
assert.strictEqual(result, 42);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should handle single argument', async () => {
|
|
91
|
+
page = createMockPlaywrightPage();
|
|
92
|
+
adapter = new PlaywrightAdapter(page);
|
|
93
|
+
const result = await adapter.evaluateOnPage((x) => x * 2, [5]);
|
|
94
|
+
assert.strictEqual(result, 10);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle multiple arguments by spreading them', async () => {
|
|
98
|
+
page = createMockPlaywrightPage();
|
|
99
|
+
adapter = new PlaywrightAdapter(page);
|
|
100
|
+
// This is the bug case - multiple args should be spread, not passed as array
|
|
101
|
+
const result = await adapter.evaluateOnPage((a, b) => a + b, [3, 7]);
|
|
102
|
+
assert.strictEqual(result, 10);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should handle selector + array arguments (real-world bug case)', async () => {
|
|
106
|
+
page = createMockPlaywrightPage();
|
|
107
|
+
adapter = new PlaywrightAdapter(page);
|
|
108
|
+
// This reproduces the original bug: selector and processedIds
|
|
109
|
+
const result = await adapter.evaluateOnPage(
|
|
110
|
+
(selector, processedIds) =>
|
|
111
|
+
`Selector: ${selector}, Count: ${processedIds.length}`,
|
|
112
|
+
['[data-qa="test"]', ['id1', 'id2']]
|
|
113
|
+
);
|
|
114
|
+
assert.ok(result.includes('Selector: [data-qa="test"]'));
|
|
115
|
+
assert.ok(result.includes('Count: 2'));
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should handle multiple arguments of different types', async () => {
|
|
119
|
+
page = createMockPlaywrightPage();
|
|
120
|
+
adapter = new PlaywrightAdapter(page);
|
|
121
|
+
const result = await adapter.evaluateOnPage(
|
|
122
|
+
(str, num, obj) => `${str}-${num}-${obj.key}`,
|
|
123
|
+
['hello', 42, { key: 'world' }]
|
|
124
|
+
);
|
|
125
|
+
assert.strictEqual(result, 'hello-42-world');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
81
128
|
});
|
|
82
129
|
|
|
83
130
|
describe('PuppeteerAdapter', () => {
|
|
@@ -130,6 +177,42 @@ describe('engine-adapter', () => {
|
|
|
130
177
|
const count = await adapter.count('button');
|
|
131
178
|
assert.strictEqual(count, 5);
|
|
132
179
|
});
|
|
180
|
+
|
|
181
|
+
describe('evaluateOnPage', () => {
|
|
182
|
+
it('should handle zero arguments', async () => {
|
|
183
|
+
page = createMockPuppeteerPage();
|
|
184
|
+
adapter = new PuppeteerAdapter(page);
|
|
185
|
+
const result = await adapter.evaluateOnPage(() => 42);
|
|
186
|
+
assert.strictEqual(result, 42);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should handle single argument', async () => {
|
|
190
|
+
page = createMockPuppeteerPage();
|
|
191
|
+
adapter = new PuppeteerAdapter(page);
|
|
192
|
+
const result = await adapter.evaluateOnPage((x) => x * 2, [5]);
|
|
193
|
+
assert.strictEqual(result, 10);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should handle multiple arguments by spreading them', async () => {
|
|
197
|
+
page = createMockPuppeteerPage();
|
|
198
|
+
adapter = new PuppeteerAdapter(page);
|
|
199
|
+
// Puppeteer natively spreads args - ensure same behavior as Playwright fix
|
|
200
|
+
const result = await adapter.evaluateOnPage((a, b) => a + b, [3, 7]);
|
|
201
|
+
assert.strictEqual(result, 10);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should handle selector + array arguments (parity with PlaywrightAdapter)', async () => {
|
|
205
|
+
page = createMockPuppeteerPage();
|
|
206
|
+
adapter = new PuppeteerAdapter(page);
|
|
207
|
+
const result = await adapter.evaluateOnPage(
|
|
208
|
+
(selector, processedIds) =>
|
|
209
|
+
`Selector: ${selector}, Count: ${processedIds.length}`,
|
|
210
|
+
['[data-qa="test"]', ['id1', 'id2']]
|
|
211
|
+
);
|
|
212
|
+
assert.ok(result.includes('Selector: [data-qa="test"]'));
|
|
213
|
+
assert.ok(result.includes('Count: 2'));
|
|
214
|
+
});
|
|
215
|
+
});
|
|
133
216
|
});
|
|
134
217
|
|
|
135
218
|
describe('createEngineAdapter', () => {
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
name: Checks and release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
types: [opened, synchronize, reopened]
|
|
9
|
-
# Manual release support - consolidated here to work with npm trusted publishing
|
|
10
|
-
# npm only allows ONE workflow file as trusted publisher, so all publishing
|
|
11
|
-
# must go through this workflow (release.yml)
|
|
12
|
-
workflow_dispatch:
|
|
13
|
-
inputs:
|
|
14
|
-
release_mode:
|
|
15
|
-
description: 'Manual release mode'
|
|
16
|
-
required: true
|
|
17
|
-
type: choice
|
|
18
|
-
default: 'instant'
|
|
19
|
-
options:
|
|
20
|
-
- instant
|
|
21
|
-
- changeset-pr
|
|
22
|
-
bump_type:
|
|
23
|
-
description: 'Manual release type'
|
|
24
|
-
required: true
|
|
25
|
-
type: choice
|
|
26
|
-
options:
|
|
27
|
-
- patch
|
|
28
|
-
- minor
|
|
29
|
-
- major
|
|
30
|
-
description:
|
|
31
|
-
description: 'Manual release description (optional)'
|
|
32
|
-
required: false
|
|
33
|
-
type: string
|
|
34
|
-
|
|
35
|
-
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
36
|
-
|
|
37
|
-
jobs:
|
|
38
|
-
# Changeset check - only runs on PRs
|
|
39
|
-
changeset-check:
|
|
40
|
-
name: Check for Changesets
|
|
41
|
-
runs-on: ubuntu-latest
|
|
42
|
-
if: github.event_name == 'pull_request'
|
|
43
|
-
steps:
|
|
44
|
-
- uses: actions/checkout@v4
|
|
45
|
-
with:
|
|
46
|
-
fetch-depth: 0
|
|
47
|
-
|
|
48
|
-
- name: Setup Node.js
|
|
49
|
-
uses: actions/setup-node@v4
|
|
50
|
-
with:
|
|
51
|
-
node-version: '20.x'
|
|
52
|
-
|
|
53
|
-
- name: Install dependencies
|
|
54
|
-
run: npm install
|
|
55
|
-
|
|
56
|
-
- name: Check for changesets
|
|
57
|
-
env:
|
|
58
|
-
# Pass PR context to the validation script
|
|
59
|
-
GITHUB_BASE_REF: ${{ github.base_ref }}
|
|
60
|
-
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
61
|
-
GITHUB_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
62
|
-
run: |
|
|
63
|
-
# Skip changeset check for automated version PRs
|
|
64
|
-
if [[ "${{ github.head_ref }}" == "changeset-release/"* ]]; then
|
|
65
|
-
echo "Skipping changeset check for automated release PR"
|
|
66
|
-
exit 0
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
# Run changeset validation script
|
|
70
|
-
# This validates that exactly ONE changeset was ADDED by this PR
|
|
71
|
-
# Pre-existing changesets from other merged PRs are ignored
|
|
72
|
-
node scripts/validate-changeset.mjs
|
|
73
|
-
|
|
74
|
-
# Linting and formatting - runs after changeset check on PRs, immediately on main
|
|
75
|
-
lint:
|
|
76
|
-
name: Lint and Format Check
|
|
77
|
-
runs-on: ubuntu-latest
|
|
78
|
-
needs: [changeset-check]
|
|
79
|
-
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
|
|
80
|
-
steps:
|
|
81
|
-
- uses: actions/checkout@v4
|
|
82
|
-
|
|
83
|
-
- name: Setup Node.js
|
|
84
|
-
uses: actions/setup-node@v4
|
|
85
|
-
with:
|
|
86
|
-
node-version: '20.x'
|
|
87
|
-
|
|
88
|
-
- name: Install dependencies
|
|
89
|
-
run: npm install
|
|
90
|
-
|
|
91
|
-
- name: Run ESLint
|
|
92
|
-
run: npm run lint
|
|
93
|
-
|
|
94
|
-
- name: Check formatting
|
|
95
|
-
run: npm run format:check
|
|
96
|
-
|
|
97
|
-
- name: Check code duplication
|
|
98
|
-
run: npm run check:duplication
|
|
99
|
-
|
|
100
|
-
# Test job - runs on Node.js only (browser automation requires specific setup)
|
|
101
|
-
test:
|
|
102
|
-
name: Test (Node.js on ${{ matrix.os }})
|
|
103
|
-
runs-on: ${{ matrix.os }}
|
|
104
|
-
needs: [changeset-check]
|
|
105
|
-
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
|
|
106
|
-
strategy:
|
|
107
|
-
fail-fast: false
|
|
108
|
-
matrix:
|
|
109
|
-
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
110
|
-
steps:
|
|
111
|
-
- uses: actions/checkout@v4
|
|
112
|
-
|
|
113
|
-
- name: Setup Node.js
|
|
114
|
-
uses: actions/setup-node@v4
|
|
115
|
-
with:
|
|
116
|
-
node-version: '20.x'
|
|
117
|
-
|
|
118
|
-
- name: Install dependencies
|
|
119
|
-
run: npm install
|
|
120
|
-
|
|
121
|
-
- name: Run unit tests
|
|
122
|
-
run: npm test
|
|
123
|
-
|
|
124
|
-
# Release - only runs on main after tests pass (for push events)
|
|
125
|
-
release:
|
|
126
|
-
name: Release
|
|
127
|
-
needs: [lint, test]
|
|
128
|
-
# Use always() to ensure this job runs even if changeset-check was skipped
|
|
129
|
-
# This is needed because lint/test jobs have a transitive dependency on changeset-check
|
|
130
|
-
if: always() && github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success'
|
|
131
|
-
runs-on: ubuntu-latest
|
|
132
|
-
# Permissions required for npm OIDC trusted publishing
|
|
133
|
-
permissions:
|
|
134
|
-
contents: write
|
|
135
|
-
pull-requests: write
|
|
136
|
-
id-token: write
|
|
137
|
-
steps:
|
|
138
|
-
- uses: actions/checkout@v4
|
|
139
|
-
with:
|
|
140
|
-
fetch-depth: 0
|
|
141
|
-
|
|
142
|
-
- name: Setup Node.js
|
|
143
|
-
uses: actions/setup-node@v4
|
|
144
|
-
with:
|
|
145
|
-
node-version: '20.x'
|
|
146
|
-
registry-url: 'https://registry.npmjs.org'
|
|
147
|
-
|
|
148
|
-
- name: Install dependencies
|
|
149
|
-
run: npm install
|
|
150
|
-
|
|
151
|
-
- name: Update npm for OIDC trusted publishing
|
|
152
|
-
run: node scripts/setup-npm.mjs
|
|
153
|
-
|
|
154
|
-
- name: Check for changesets
|
|
155
|
-
id: check_changesets
|
|
156
|
-
run: |
|
|
157
|
-
# Count changeset files (excluding README.md and config.json)
|
|
158
|
-
CHANGESET_COUNT=$(find .changeset -name "*.md" ! -name "README.md" | wc -l)
|
|
159
|
-
echo "Found $CHANGESET_COUNT changeset file(s)"
|
|
160
|
-
echo "has_changesets=$([[ $CHANGESET_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
|
|
161
|
-
echo "changeset_count=$CHANGESET_COUNT" >> $GITHUB_OUTPUT
|
|
162
|
-
|
|
163
|
-
- name: Merge multiple changesets
|
|
164
|
-
if: steps.check_changesets.outputs.has_changesets == 'true' && steps.check_changesets.outputs.changeset_count > 1
|
|
165
|
-
run: |
|
|
166
|
-
echo "Multiple changesets detected, merging..."
|
|
167
|
-
node scripts/merge-changesets.mjs
|
|
168
|
-
|
|
169
|
-
- name: Version packages and commit to main
|
|
170
|
-
if: steps.check_changesets.outputs.has_changesets == 'true'
|
|
171
|
-
id: version
|
|
172
|
-
run: node scripts/version-and-commit.mjs --mode changeset
|
|
173
|
-
|
|
174
|
-
- name: Publish to npm
|
|
175
|
-
# Run if version was committed OR if a previous attempt already committed (for re-runs)
|
|
176
|
-
if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true'
|
|
177
|
-
id: publish
|
|
178
|
-
run: node scripts/publish-to-npm.mjs --should-pull
|
|
179
|
-
|
|
180
|
-
- name: Create GitHub Release
|
|
181
|
-
if: steps.publish.outputs.published == 'true'
|
|
182
|
-
env:
|
|
183
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
184
|
-
run: node scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}"
|
|
185
|
-
|
|
186
|
-
- name: Format GitHub release notes
|
|
187
|
-
if: steps.publish.outputs.published == 'true'
|
|
188
|
-
env:
|
|
189
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
190
|
-
run: node scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}"
|
|
191
|
-
|
|
192
|
-
# Manual Instant Release - triggered via workflow_dispatch with instant mode
|
|
193
|
-
# This job is in release.yml because npm trusted publishing
|
|
194
|
-
# only allows one workflow file to be registered as a trusted publisher
|
|
195
|
-
instant-release:
|
|
196
|
-
name: Instant Release
|
|
197
|
-
if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'instant'
|
|
198
|
-
runs-on: ubuntu-latest
|
|
199
|
-
# Permissions required for npm OIDC trusted publishing
|
|
200
|
-
permissions:
|
|
201
|
-
contents: write
|
|
202
|
-
pull-requests: write
|
|
203
|
-
id-token: write
|
|
204
|
-
steps:
|
|
205
|
-
- uses: actions/checkout@v4
|
|
206
|
-
with:
|
|
207
|
-
fetch-depth: 0
|
|
208
|
-
|
|
209
|
-
- name: Setup Node.js
|
|
210
|
-
uses: actions/setup-node@v4
|
|
211
|
-
with:
|
|
212
|
-
node-version: '20.x'
|
|
213
|
-
registry-url: 'https://registry.npmjs.org'
|
|
214
|
-
|
|
215
|
-
- name: Install dependencies
|
|
216
|
-
run: npm install
|
|
217
|
-
|
|
218
|
-
- name: Update npm for OIDC trusted publishing
|
|
219
|
-
run: node scripts/setup-npm.mjs
|
|
220
|
-
|
|
221
|
-
- name: Version packages and commit to main
|
|
222
|
-
id: version
|
|
223
|
-
run: node scripts/version-and-commit.mjs --mode instant --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}"
|
|
224
|
-
|
|
225
|
-
- name: Publish to npm
|
|
226
|
-
# Run if version was committed OR if a previous attempt already committed (for re-runs)
|
|
227
|
-
if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true'
|
|
228
|
-
id: publish
|
|
229
|
-
run: node scripts/publish-to-npm.mjs
|
|
230
|
-
|
|
231
|
-
- name: Create GitHub Release
|
|
232
|
-
if: steps.publish.outputs.published == 'true'
|
|
233
|
-
env:
|
|
234
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
235
|
-
run: node scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}"
|
|
236
|
-
|
|
237
|
-
- name: Format GitHub release notes
|
|
238
|
-
if: steps.publish.outputs.published == 'true'
|
|
239
|
-
env:
|
|
240
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
241
|
-
run: node scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}"
|
|
242
|
-
|
|
243
|
-
# Manual Changeset PR - creates a pull request with the changeset for review
|
|
244
|
-
changeset-pr:
|
|
245
|
-
name: Create Changeset PR
|
|
246
|
-
if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'changeset-pr'
|
|
247
|
-
runs-on: ubuntu-latest
|
|
248
|
-
permissions:
|
|
249
|
-
contents: write
|
|
250
|
-
pull-requests: write
|
|
251
|
-
steps:
|
|
252
|
-
- uses: actions/checkout@v4
|
|
253
|
-
with:
|
|
254
|
-
fetch-depth: 0
|
|
255
|
-
|
|
256
|
-
- name: Setup Node.js
|
|
257
|
-
uses: actions/setup-node@v4
|
|
258
|
-
with:
|
|
259
|
-
node-version: '20.x'
|
|
260
|
-
|
|
261
|
-
- name: Install dependencies
|
|
262
|
-
run: npm install
|
|
263
|
-
|
|
264
|
-
- name: Create changeset file
|
|
265
|
-
run: node scripts/create-manual-changeset.mjs --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}"
|
|
266
|
-
|
|
267
|
-
- name: Format changeset with Prettier
|
|
268
|
-
run: |
|
|
269
|
-
# Run Prettier on the changeset file to ensure it matches project style
|
|
270
|
-
npx prettier --write ".changeset/*.md" || true
|
|
271
|
-
|
|
272
|
-
echo "Formatted changeset files"
|
|
273
|
-
|
|
274
|
-
- name: Create Pull Request
|
|
275
|
-
uses: peter-evans/create-pull-request@v7
|
|
276
|
-
with:
|
|
277
|
-
token: ${{ secrets.GITHUB_TOKEN }}
|
|
278
|
-
commit-message: 'chore: add changeset for manual ${{ github.event.inputs.bump_type }} release'
|
|
279
|
-
branch: changeset-manual-release-${{ github.run_id }}
|
|
280
|
-
delete-branch: true
|
|
281
|
-
title: 'chore: manual ${{ github.event.inputs.bump_type }} release'
|
|
282
|
-
body: |
|
|
283
|
-
## Manual Release Request
|
|
284
|
-
|
|
285
|
-
This PR was created by a manual workflow trigger to prepare a **${{ github.event.inputs.bump_type }}** release.
|
|
286
|
-
|
|
287
|
-
### Release Details
|
|
288
|
-
- **Type:** ${{ github.event.inputs.bump_type }}
|
|
289
|
-
- **Description:** ${{ github.event.inputs.description || 'Manual release' }}
|
|
290
|
-
- **Triggered by:** @${{ github.actor }}
|
|
291
|
-
|
|
292
|
-
### Next Steps
|
|
293
|
-
1. Review the changeset in this PR
|
|
294
|
-
2. Merge this PR to main
|
|
295
|
-
3. The automated release workflow will create a version PR
|
|
296
|
-
4. Merge the version PR to publish to npm and create a GitHub release
|
package/LICENSE
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
This is free and unencumbered software released into the public domain.
|
|
2
|
-
|
|
3
|
-
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
-
distribute this software, either in source code form or as a compiled
|
|
5
|
-
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
-
means.
|
|
7
|
-
|
|
8
|
-
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
-
of this software dedicate any and all copyright interest in the
|
|
10
|
-
software to the public domain. We make this dedication for the benefit
|
|
11
|
-
of the public at large and to the detriment of our heirs and
|
|
12
|
-
successors. We intend this dedication to be an overt act of
|
|
13
|
-
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
-
software under copyright law.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
-
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
-
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
-
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
-
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
-
|
|
24
|
-
For more information, please refer to <https://unlicense.org>
|