Skip to content

Commit 8f920ec

Browse files
committed
✨ Add git detection API to plugin services
Adds `services.git.detect()` to the plugin API, providing plugins with correct git information detection that handles CI environments properly (GitHub Actions PR merge commits, GitLab, CircleCI, etc.). This replaces the fragile dynamic import approach in storybook and static-site plugins with a clean API contract. Plugins now use the CLI's battle-tested git detection instead of duplicating the logic. Changes: - Add `services.git.detect({ buildPrefix })` to plugin-api.js - Update storybook plugin to use new API with graceful fallback - Update static-site plugin to use new API with graceful fallback - Bump peer dependency to >=0.25.0 (with fallback for older CLIs)
1 parent f940ebf commit 8f920ec

5 files changed

Lines changed: 82 additions & 72 deletions

File tree

clients/static-site/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"registry": "https://registry.npmjs.org/"
6363
},
6464
"peerDependencies": {
65-
"@vizzly-testing/cli": ">=0.9.0"
65+
"@vizzly-testing/cli": ">=0.25.0"
6666
},
6767
"dependencies": {
6868
"cosmiconfig": "^9.0.0",

clients/static-site/src/index.js

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -166,43 +166,30 @@ export async function run(buildPath, options = {}, context = {}) {
166166
}
167167
});
168168

169-
// Detect git info - use dynamic import to access internal utils
170-
let gitUtils;
171-
try {
172-
// Try to import from the installed CLI package
173-
let cliPath = await import.meta.resolve?.('@vizzly-testing/cli');
174-
if (cliPath) {
175-
gitUtils = await import(
176-
'@vizzly-testing/cli/dist/utils/git.js'
177-
).catch(() => null);
178-
}
179-
} catch {
180-
// Fallback: try relative path if in monorepo
181-
try {
182-
gitUtils = await import('../../../src/utils/git.js').catch(
183-
() => null
184-
);
185-
} catch {
186-
gitUtils = null;
187-
}
169+
// Detect git info using CLI's plugin API (preferred) or fallback to env vars
170+
let branch, commit, message, buildName, pullRequestNumber;
171+
172+
if (services.git?.detect) {
173+
// Use CLI's git detection (correct handling of CI environments)
174+
let gitInfo = await services.git.detect({
175+
buildPrefix: 'Static Site',
176+
});
177+
branch = gitInfo.branch;
178+
commit = gitInfo.commit;
179+
message = gitInfo.message;
180+
buildName = gitInfo.buildName;
181+
pullRequestNumber = gitInfo.prNumber;
182+
} else {
183+
// Fallback for older CLI versions - use environment variables
184+
branch = process.env.VIZZLY_BRANCH || 'main';
185+
commit = process.env.VIZZLY_COMMIT_SHA || undefined;
186+
message = process.env.VIZZLY_COMMIT_MESSAGE || undefined;
187+
buildName = `Static Site ${new Date().toISOString()}`;
188+
pullRequestNumber = process.env.VIZZLY_PR_NUMBER
189+
? parseInt(process.env.VIZZLY_PR_NUMBER, 10)
190+
: undefined;
188191
}
189192

190-
let branch = gitUtils
191-
? await gitUtils.detectBranch()
192-
: process.env.VIZZLY_BRANCH || 'main';
193-
let commit = gitUtils
194-
? await gitUtils.detectCommit()
195-
: process.env.VIZZLY_COMMIT_SHA || undefined;
196-
let message = gitUtils
197-
? await gitUtils.detectCommitMessage()
198-
: process.env.VIZZLY_COMMIT_MESSAGE || undefined;
199-
let buildName = gitUtils
200-
? await gitUtils.generateBuildNameWithGit('Static Site')
201-
: `Static Site ${new Date().toISOString()}`;
202-
let pullRequestNumber = gitUtils
203-
? gitUtils.detectPullRequestNumber()
204-
: process.env.VIZZLY_PR_NUMBER || undefined;
205-
206193
// Build options for API
207194
let runOptions = {
208195
port: vizzlyConfig?.server?.port || 47392,

clients/storybook/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"registry": "https://registry.npmjs.org/"
5959
},
6060
"peerDependencies": {
61-
"@vizzly-testing/cli": ">=0.9.0"
61+
"@vizzly-testing/cli": ">=0.25.0"
6262
},
6363
"dependencies": {
6464
"playwright-core": "^1.50.0",

clients/storybook/src/index.js

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -112,43 +112,28 @@ export async function run(storybookPath, options = {}, context = {}) {
112112
}
113113
});
114114

115-
// Detect git info - use dynamic import to access internal utils
116-
let gitUtils;
117-
try {
118-
// Try to import from the installed CLI package
119-
let cliPath = await import.meta.resolve?.('@vizzly-testing/cli');
120-
if (cliPath) {
121-
gitUtils = await import(
122-
'@vizzly-testing/cli/dist/utils/git.js'
123-
).catch(() => null);
124-
}
125-
} catch {
126-
// Fallback: try relative path if in monorepo
127-
try {
128-
gitUtils = await import('../../../src/utils/git.js').catch(
129-
() => null
130-
);
131-
} catch {
132-
gitUtils = null;
133-
}
115+
// Detect git info using CLI's plugin API (preferred) or fallback to env vars
116+
let branch, commit, message, buildName, pullRequestNumber;
117+
118+
if (services.git?.detect) {
119+
// Use CLI's git detection (correct handling of CI environments)
120+
let gitInfo = await services.git.detect({ buildPrefix: 'Storybook' });
121+
branch = gitInfo.branch;
122+
commit = gitInfo.commit;
123+
message = gitInfo.message;
124+
buildName = gitInfo.buildName;
125+
pullRequestNumber = gitInfo.prNumber;
126+
} else {
127+
// Fallback for older CLI versions - use environment variables
128+
branch = process.env.VIZZLY_BRANCH || 'main';
129+
commit = process.env.VIZZLY_COMMIT_SHA || undefined;
130+
message = process.env.VIZZLY_COMMIT_MESSAGE || undefined;
131+
buildName = `Storybook ${new Date().toISOString()}`;
132+
pullRequestNumber = process.env.VIZZLY_PR_NUMBER
133+
? parseInt(process.env.VIZZLY_PR_NUMBER, 10)
134+
: undefined;
134135
}
135136

136-
let branch = gitUtils
137-
? await gitUtils.detectBranch()
138-
: process.env.VIZZLY_BRANCH || 'main';
139-
let commit = gitUtils
140-
? await gitUtils.detectCommit()
141-
: process.env.VIZZLY_COMMIT_SHA || undefined;
142-
let message = gitUtils
143-
? await gitUtils.detectCommitMessage()
144-
: process.env.VIZZLY_COMMIT_MESSAGE || undefined;
145-
let buildName = gitUtils
146-
? await gitUtils.generateBuildNameWithGit('Storybook')
147-
: `Storybook ${new Date().toISOString()}`;
148-
let pullRequestNumber = gitUtils
149-
? gitUtils.detectPullRequestNumber()
150-
: process.env.VIZZLY_PR_NUMBER || undefined;
151-
152137
// Build options for API
153138
let runOptions = {
154139
port: vizzlyConfig?.server?.port || 47392,

src/plugin-api.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@
99
* exposed to plugins to prevent coupling to implementation details.
1010
*/
1111

12+
import {
13+
detectBranch,
14+
detectCommit,
15+
detectCommitMessage,
16+
detectPullRequestNumber,
17+
generateBuildNameWithGit,
18+
} from './utils/git.js';
19+
1220
/**
1321
* Creates a stable plugin services object from the internal services
1422
*
1523
* Only exposes:
24+
* - git: Git information detection (branch, commit, PR number, etc.)
1625
* - testRunner: Build lifecycle management (createBuild, finalizeBuild, events)
1726
* - serverManager: Screenshot server control (start, stop)
1827
*
@@ -23,6 +32,35 @@ export function createPluginServices(services) {
2332
let { testRunner, serverManager } = services;
2433

2534
return Object.freeze({
35+
// Git detection utilities - provides correct git info from CI environments
36+
git: Object.freeze({
37+
/**
38+
* Detect git information for build creation
39+
* Handles CI environment variables correctly (GitHub Actions, GitLab, etc.)
40+
*
41+
* @param {Object} [options] - Detection options
42+
* @param {string} [options.buildPrefix] - Prefix for generated build name
43+
* @returns {Promise<Object>} Git info: { branch, commit, message, prNumber, buildName }
44+
*/
45+
async detect(options = {}) {
46+
let [branch, commit, message] = await Promise.all([
47+
detectBranch(),
48+
detectCommit(),
49+
detectCommitMessage(),
50+
]);
51+
let prNumber = detectPullRequestNumber();
52+
let buildName = await generateBuildNameWithGit(options.buildPrefix);
53+
54+
return {
55+
branch,
56+
commit,
57+
message,
58+
prNumber,
59+
buildName,
60+
};
61+
},
62+
}),
63+
2664
testRunner: Object.freeze({
2765
// EventEmitter methods for build lifecycle events
2866
once: testRunner.once.bind(testRunner),

0 commit comments

Comments
 (0)