@andwhy/e2e-pipeline 0.14.1 → 0.14.2
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/bin/init.js
CHANGED
|
@@ -120,9 +120,11 @@ const run = async () => {
|
|
|
120
120
|
}
|
|
121
121
|
const createdWorkflow = result.created.some((f) => f.includes(`.github${path.sep}workflows`));
|
|
122
122
|
if (createdWorkflow) {
|
|
123
|
+
const heading = result.replacedWorkflows.length > 0
|
|
124
|
+
? "\nGitHub workflows replaced with callers of the pipeline's reusable workflows. They\nuse the repository secrets the old ones used"
|
|
125
|
+
: "\nGitHub workflows created. They need repository secrets before they run";
|
|
123
126
|
console.log([
|
|
124
|
-
|
|
125
|
-
"(values in 1Password):",
|
|
127
|
+
`${heading} (values in 1Password):`,
|
|
126
128
|
" CHECKLY_API_KEY, CHECKLY_ACCOUNT_ID — deploy monitors, auto-heal",
|
|
127
129
|
" VERCEL_AUTOMATION_BYPASS_SECRET — PR tests through Vercel",
|
|
128
130
|
" deployment protection",
|
package/dist/utils/copy.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ interface CopyResult {
|
|
|
4
4
|
regenerated: string[];
|
|
5
5
|
/** Pre-plugin copies of package files deleted from the project (--force). */
|
|
6
6
|
removed: string[];
|
|
7
|
+
/** Workflows --update-workflows replaced (a subset of created). */
|
|
8
|
+
replacedWorkflows: string[];
|
|
7
9
|
/** Things the scaffold cannot fix itself and the user must act on. */
|
|
8
10
|
warnings: string[];
|
|
9
11
|
}
|
package/dist/utils/copy.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import fs from "fs-extra";
|
|
3
4
|
// The agents, the skill and the always-on rules ship as the `e2e-pipeline`
|
|
@@ -130,6 +131,8 @@ const writeWorkflows = async (githubSrc, projectRoot, updateWorkflows, result) =
|
|
|
130
131
|
await fs.ensureDir(path.dirname(destPath));
|
|
131
132
|
await fs.copy(srcPath, destPath);
|
|
132
133
|
result.created.push(destPath);
|
|
134
|
+
if (exists)
|
|
135
|
+
result.replacedWorkflows.push(destPath);
|
|
133
136
|
}
|
|
134
137
|
if (stale.length > 0) {
|
|
135
138
|
result.warnings.push(`Workflows from before 0.14.0: ${stale.join(", ")}. They still work, but changes to them ` +
|
|
@@ -254,12 +257,55 @@ export const findSpecsOutsideE2e = async (projectRoot) => {
|
|
|
254
257
|
await walk(testsRoot);
|
|
255
258
|
return [...found].sort();
|
|
256
259
|
};
|
|
260
|
+
// A repo that ignores `.claude/*` (a common pattern from before the plugin,
|
|
261
|
+
// keeping settings.local.json and session files out of git) silently drops
|
|
262
|
+
// the one file the plugin needs: nobody else gets the plugin entry, and
|
|
263
|
+
// nothing in the diff shows it is missing. Git decides: `check-ignore`
|
|
264
|
+
// applies every rule the repo has, so a negation is appended only when the
|
|
265
|
+
// file really is ignored, at the end of .gitignore where it wins over the
|
|
266
|
+
// rule above it. Outside a git repo there is nothing to do.
|
|
267
|
+
const SETTINGS_REL = ".claude/settings.json";
|
|
268
|
+
const isGitIgnored = (projectRoot, rel) => {
|
|
269
|
+
try {
|
|
270
|
+
execSync(`git check-ignore -q -- ${rel}`, {
|
|
271
|
+
cwd: projectRoot,
|
|
272
|
+
stdio: "ignore",
|
|
273
|
+
});
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Exit 1: not ignored. Exit 128: not a git repository. Either way, the
|
|
278
|
+
// file is not being dropped by an ignore rule.
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const unignoreClaudeSettings = async (projectRoot, result) => {
|
|
283
|
+
if (!isGitIgnored(projectRoot, SETTINGS_REL))
|
|
284
|
+
return;
|
|
285
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
286
|
+
const existing = (await fs.pathExists(gitignorePath))
|
|
287
|
+
? await fs.readFile(gitignorePath, "utf-8")
|
|
288
|
+
: "";
|
|
289
|
+
const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
290
|
+
await fs.appendFile(gitignorePath, `${separator}\n# The e2e-pipeline plugin entry is committed (settings.local.json stays ignored)\n!${SETTINGS_REL}\n`);
|
|
291
|
+
if (!result.created.includes(gitignorePath))
|
|
292
|
+
result.created.push(gitignorePath);
|
|
293
|
+
if (isGitIgnored(projectRoot, SETTINGS_REL)) {
|
|
294
|
+
result.warnings.push(`.gitignore still ignores ${SETTINGS_REL} after appending \`!${SETTINGS_REL}\` ` +
|
|
295
|
+
`(a rule ignores the .claude directory itself, which no negation can undo). ` +
|
|
296
|
+
`Change that rule to \`.claude/*\` so the plugin entry can be committed.`);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
result.warnings.push(`.gitignore ignored ${SETTINGS_REL}, which carries the ${PLUGIN_ID} plugin entry every ` +
|
|
300
|
+
`collaborator needs. Appended \`!${SETTINGS_REL}\`; commit both files.`);
|
|
301
|
+
};
|
|
257
302
|
export const scaffold = async (templatesRoot, projectRoot, { force = false, fileFormat = "ts", resetConfig = false, updateWorkflows = false, } = {}) => {
|
|
258
303
|
const result = {
|
|
259
304
|
created: [],
|
|
260
305
|
skipped: [],
|
|
261
306
|
regenerated: [],
|
|
262
307
|
removed: [],
|
|
308
|
+
replacedWorkflows: [],
|
|
263
309
|
warnings: [],
|
|
264
310
|
};
|
|
265
311
|
const configExt = fileFormat === "mjs" ? "mjs" : "ts";
|
|
@@ -308,7 +354,9 @@ export const scaffold = async (templatesRoot, projectRoot, { force = false, file
|
|
|
308
354
|
const srcPath = path.join(sharedSrc, src);
|
|
309
355
|
const destPath = path.join(projectRoot, dest);
|
|
310
356
|
const exists = await fs.pathExists(destPath);
|
|
311
|
-
if (exists &&
|
|
357
|
+
if (exists &&
|
|
358
|
+
resetConfig &&
|
|
359
|
+
src.endsWith(`.config.template.${configExt}`)) {
|
|
312
360
|
// checkly.config.new.ts, not checkly.config.ts.new — keeping the real
|
|
313
361
|
// extension means prettier can format it and the editor highlights it,
|
|
314
362
|
// so the diff against your config shows content rather than style.
|
|
@@ -332,5 +380,6 @@ export const scaffold = async (templatesRoot, projectRoot, { force = false, file
|
|
|
332
380
|
// walks the user through adding them.
|
|
333
381
|
await writeWorkflows(path.join(templatesRoot, "github"), projectRoot, updateWorkflows, result);
|
|
334
382
|
await appendGitignore(projectRoot, result);
|
|
383
|
+
await unignoreClaudeSettings(projectRoot, result);
|
|
335
384
|
return result;
|
|
336
385
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andwhy/e2e-pipeline",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "Scaffolds the full e2e testing pipeline: agent-assisted Playwright tests, CI runs against Vercel previews, and Checkly monitors that follow production deploys",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "e2e-pipeline",
|
|
3
3
|
"displayName": "&why e2e pipeline",
|
|
4
|
-
"version": "0.14.
|
|
4
|
+
"version": "0.14.2",
|
|
5
5
|
"description": "Agent-assisted Playwright e2e tests: planner, generator and healer agents plus the playwright-test-pipeline skill that drives Plan → Generate → Heal, Checkly preview validation and deployment.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "&why",
|
|
@@ -7,7 +7,7 @@ description: Guides the full workflow for creating and maintaining Playwright
|
|
|
7
7
|
tests, asks to "test" a page/feature/flow, or asks how the test pipeline
|
|
8
8
|
works.
|
|
9
9
|
metadata:
|
|
10
|
-
version: "0.14.
|
|
10
|
+
version: "0.14.2"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Playwright Test Pipeline
|
|
@@ -502,7 +502,7 @@ Set up once per project:
|
|
|
502
502
|
6. **One Slack Workflow Builder rule** routes this project's messages from
|
|
503
503
|
the shared e2e channel to the project channel. All notifications post to
|
|
504
504
|
the e2e channel tagged `[e2e:<repo-name>]`; the rule matches the **full
|
|
505
|
-
bracketed tag** — never a short name like `
|
|
505
|
+
bracketed tag** — never a short name like `shop`, which collides with
|
|
506
506
|
other text — and sends the message to the project channel. The sent
|
|
507
507
|
message's template is just the message-text variable (plus the
|
|
508
508
|
link-to-original variable when available, so threads happen on the
|