@juangadm/pre-post 0.1.0 → 0.1.1

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
@@ -2,11 +2,7 @@
2
2
 
3
3
  Visual diff tool that captures pre/post screenshots for PRs. Use it as a Claude Code skill for automatic visual documentation, or run it directly from the CLI.
4
4
 
5
- > Forked from [before-and-after](https://github.com/vercel-labs/before-and-after) by [James Clements](https://github.com/jamesclement) / Vercel Labs.
6
-
7
- ## TODO
8
-
9
- - [ ] Publish to npm so `npm i -g pre-post` and `npx pre-post` work out of the box
5
+ > Originally forked from [before-and-after](https://github.com/vercel-labs/before-and-after) by [James Clements](https://github.com/jamesclement) / Vercel Labs.
10
6
 
11
7
  ## What Changed from the Original
12
8
 
@@ -57,8 +53,11 @@ flowchart TD
57
53
 
58
54
  S --> T{Output}
59
55
  T -->|Default| U["Save to ~/Downloads"]
60
- T -->|--markdown| V[Commit to PR branch]
61
- V --> W[Markdown table for PR]
56
+ T -->|--markdown| V{Upload}
57
+ V -->|Default| W["Commit to .pre-post/ (blob+SHA URL)"]
58
+ V -->|--upload-url| Y["Custom storage"]
59
+ W --> Z[Markdown table for PR]
60
+ Y --> Z
62
61
 
63
62
  style A fill:#4f46e5,color:#fff
64
63
  style L fill:#2563eb,color:#fff
@@ -68,10 +67,9 @@ flowchart TD
68
67
  ## Prerequisites
69
68
 
70
69
  - **Node.js** 18+
71
- - **Chromium** (auto-installed on first run via Playwright)
70
+ - **Chromium** install once via Playwright:
72
71
 
73
72
  ```bash
74
- # Install Chromium browser for Playwright (one-time setup)
75
73
  npx playwright install chromium
76
74
  ```
77
75
 
@@ -115,7 +113,7 @@ Detect affected routes from git changes:
115
113
 
116
114
  ```bash
117
115
  pre-post detect # Auto-detect framework
118
- pre-post detect --framework nextjs # Force framework
116
+ pre-post detect --framework nextjs-app # Force framework
119
117
  ```
120
118
 
121
119
  Outputs JSON with route paths, confidence levels, and source files.
@@ -177,13 +175,13 @@ Save to a custom location:
177
175
  pre-post url1 url2 --output ./screenshots
178
176
  ```
179
177
 
180
- Override the default upload method:
178
+ Upload to a custom image storage service:
181
179
 
182
180
  ```bash
183
- pre-post url1 url2 --upload-url https://uploads.example.com
181
+ pre-post url1 url2 --markdown --upload-url https://my-s3-bucket.amazonaws.com
184
182
  ```
185
183
 
186
- By default, screenshots are committed directly to the PR branch (under `.pre-post/`) and served via `raw.githubusercontent.com`. Use `--upload-url` to override with a custom storage service. Screenshots auto-append to the PR body, newest on top.
184
+ By default, `--markdown` commits screenshots to the PR branch (under `.pre-post/`) and serves them via GitHub blob URLs pinned to the commit SHA. This works for both public and private repos. Use `--upload-url` to point at your own storage instead. It auto-detects the protocol for 0x0.st, Vercel Blob, and any generic PUT endpoint (like S3). Screenshots auto-append to the PR body, newest on top.
187
185
 
188
186
  ## Route Detection
189
187
 
package/dist/upload.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Image upload for generating shareable URLs.
3
- * Default: git-native (commits to .pre-post/ on current branch).
3
+ * Default: git-native (commits to .pre-post/, serves via blob+SHA URLs).
4
4
  * Opt-in: 0x0.st, Vercel Blob, generic PUT via --upload-url.
5
5
  */
6
6
  /**
@@ -9,18 +9,22 @@
9
9
  */
10
10
  export declare function uploadImage(image: Buffer, filename: string, uploadUrl?: string): Promise<string>;
11
11
  /**
12
- * Write an image to .pre-post/ in the repo root, stage it, and return
13
- * the raw.githubusercontent.com URL it will resolve to after push.
12
+ * Write an image to .pre-post/ in the repo root and stage it.
13
+ * Returns filename + ownerRepo caller constructs blob+SHA URL after commit.
14
14
  */
15
- export declare function uploadGitNative(image: Buffer, filename: string): string;
15
+ export declare function uploadGitNative(image: Buffer, filename: string): {
16
+ filename: string;
17
+ ownerRepo: string;
18
+ };
16
19
  /**
17
20
  * Commit and push all staged .pre-post/ screenshots in one batch.
21
+ * Returns the full 40-char commit SHA.
18
22
  */
19
- export declare function commitAndPushScreenshots(): void;
23
+ export declare function commitAndPushScreenshots(): string;
20
24
  /**
21
25
  * Upload before/after images and return URLs.
22
26
  * When uploadUrl is provided, uses the HTTP-based upload path.
23
- * Otherwise, uses git-native (commit to .pre-post/).
27
+ * Otherwise, uses git-native (commit to .pre-post/) with blob+SHA URLs.
24
28
  */
25
29
  export declare function uploadBeforeAfter(before: {
26
30
  image: Buffer;
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,MAAM,CAAC,CAajB;AAuDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkBvE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC3C,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC1C,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBlD"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,MAAM,CAAC,CAajB;AAuDD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAiBzC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CASjD;AAWD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC3C,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC1C,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBlD"}
package/dist/upload.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Image upload for generating shareable URLs.
3
- * Default: git-native (commits to .pre-post/ on current branch).
3
+ * Default: git-native (commits to .pre-post/, serves via blob+SHA URLs).
4
4
  * Opt-in: 0x0.st, Vercel Blob, generic PUT via --upload-url.
5
5
  */
6
6
  import { execSync } from 'child_process';
@@ -68,12 +68,11 @@ async function uploadGenericPut(image, filename, url) {
68
68
  return response.headers.get('location') || `${url}/${filename}`;
69
69
  }
70
70
  /**
71
- * Write an image to .pre-post/ in the repo root, stage it, and return
72
- * the raw.githubusercontent.com URL it will resolve to after push.
71
+ * Write an image to .pre-post/ in the repo root and stage it.
72
+ * Returns filename + ownerRepo caller constructs blob+SHA URL after commit.
73
73
  */
74
74
  export function uploadGitNative(image, filename) {
75
75
  const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
76
- const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
77
76
  const remoteUrl = execSync('git remote get-url origin', { encoding: 'utf-8' }).trim();
78
77
  // Parse owner/repo from HTTPS or SSH remote URL
79
78
  const ownerRepo = remoteUrl
@@ -84,19 +83,33 @@ export function uploadGitNative(image, filename) {
84
83
  const dest = path.join(destDir, filename);
85
84
  fs.writeFileSync(dest, image);
86
85
  execSync(`git add -f "${dest}"`);
87
- return `https://raw.githubusercontent.com/${ownerRepo}/${branch}/.pre-post/${filename}`;
86
+ return { filename, ownerRepo };
88
87
  }
89
88
  /**
90
89
  * Commit and push all staged .pre-post/ screenshots in one batch.
90
+ * Returns the full 40-char commit SHA.
91
91
  */
92
92
  export function commitAndPushScreenshots() {
93
93
  execSync('git commit -m "chore: add pre/post screenshots"');
94
94
  execSync('git push origin HEAD');
95
+ const sha = execSync('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
96
+ if (!/^[0-9a-f]{40}$/.test(sha)) {
97
+ throw new Error(`Failed to get commit SHA after push (got: "${sha}")`);
98
+ }
99
+ return sha;
100
+ }
101
+ /**
102
+ * Construct a GitHub blob URL with full SHA for an image in .pre-post/.
103
+ * Blob URLs are same-origin on GitHub — the markdown renderer resolves them
104
+ * with the viewer's auth, so they work for both public and private repos.
105
+ */
106
+ function buildBlobUrl(ownerRepo, sha, filename) {
107
+ return `https://github.com/${ownerRepo}/blob/${sha}/.pre-post/${filename}?raw=true`;
95
108
  }
96
109
  /**
97
110
  * Upload before/after images and return URLs.
98
111
  * When uploadUrl is provided, uses the HTTP-based upload path.
99
- * Otherwise, uses git-native (commit to .pre-post/).
112
+ * Otherwise, uses git-native (commit to .pre-post/) with blob+SHA URLs.
100
113
  */
101
114
  export async function uploadBeforeAfter(before, after, uploadUrl) {
102
115
  // If an explicit upload URL is provided, use HTTP upload
@@ -107,10 +120,14 @@ export async function uploadBeforeAfter(before, after, uploadUrl) {
107
120
  ]);
108
121
  return { beforeUrl, afterUrl };
109
122
  }
110
- // Default: git-native stage both, then commit+push once
111
- const beforeUrl = uploadGitNative(before.image, before.filename);
112
- const afterUrl = uploadGitNative(after.image, after.filename);
113
- commitAndPushScreenshots();
123
+ // Default: git-native with blob+SHA URLs.
124
+ // Works for both public and private repos — blob URLs are same-origin on GitHub,
125
+ // so the markdown renderer resolves them with the viewer's authentication context.
126
+ const beforeResult = uploadGitNative(before.image, before.filename);
127
+ const afterResult = uploadGitNative(after.image, after.filename);
128
+ const sha = commitAndPushScreenshots();
129
+ const beforeUrl = buildBlobUrl(beforeResult.ownerRepo, sha, beforeResult.filename);
130
+ const afterUrl = buildBlobUrl(afterResult.ownerRepo, sha, afterResult.filename);
114
131
  return { beforeUrl, afterUrl };
115
132
  }
116
133
  //# sourceMappingURL=upload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAE5C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,QAAgB,EAChB,YAAoB,kBAAkB;IAEtC,oCAAoC;IACpC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACjD,CAAC;IAED,6CAA6C;IAC7C,IAAI,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACtC,OAAO,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACtD,CAAC;IAED,yDAAyD;IACzD,OAAO,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAAa,EAAE,QAAgB,EAAE,GAAW;IACrE,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,YAAY,EAAE,sBAAsB,EAAE;QACjD,IAAI,EAAE,QAAQ;KACf,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,KAAa,EAAE,QAAgB,EAAE,GAAW;IAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,IAAI,QAAQ,EAAE,EAAE;QACjD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE;QACxC,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAqB,CAAC;IACxD,OAAO,MAAM,CAAC,GAAG,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,KAAa,EAAE,QAAgB,EAAE,GAAW;IAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,IAAI,QAAQ,EAAE,EAAE;QACjD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE;QACxC,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,uFAAuF;IACvF,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAsB,CAAC;QACzD,IAAI,MAAM,CAAC,GAAG;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC;IACpC,CAAC;IAED,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,IAAI,QAAQ,EAAE,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAa,EACb,QAAgB;IAEhB,MAAM,QAAQ,GAAG,QAAQ,CAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACzF,MAAM,SAAS,GAAG,QAAQ,CAAC,2BAA2B,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAEtF,gDAAgD;IAChD,MAAM,SAAS,GAAG,SAAS;SACxB,OAAO,CAAC,8CAA8C,EAAE,EAAE,CAAC;SAC3D,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACjD,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9B,QAAQ,CAAC,eAAe,IAAI,GAAG,CAAC,CAAC;IAEjC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACtC,QAAQ,CAAC,iDAAiD,CAAC,CAAC;IAC5D,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IAEjC,MAAM,GAAG,GAAG,QAAQ,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACzE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,8CAA8C,GAAG,IAAI,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,SAAiB,EAAE,GAAW,EAAE,QAAgB;IACpE,OAAO,sBAAsB,SAAS,SAAS,GAAG,cAAc,QAAQ,WAAW,CAAC;AACtF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA2C,EAC3C,KAA0C,EAC1C,SAAkB;IAElB,yDAAyD;IACzD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC9C,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC;YACrD,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC;SACpD,CAAC,CAAC;QACH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACjC,CAAC;IAED,0CAA0C;IAC1C,iFAAiF;IACjF,mFAAmF;IACnF,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,wBAAwB,EAAE,CAAC;IAEvC,MAAM,SAAS,GAAG,YAAY,CAAC,YAAY,CAAC,SAAS,EAAE,GAAG,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IACnF,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,CAAC,SAAS,EAAE,GAAG,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhF,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juangadm/pre-post",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Visual diff tool for PRs — captures before/after screenshots of web pages",
5
5
  "author": "Juan Gabriel Delgado (forked from James Clements)",
6
6
  "license": "MIT",
package/skill/SKILL.md CHANGED
@@ -222,17 +222,17 @@ npx pre-post compare --before-base URL --after-base URL
222
222
 
223
223
  ## Image Upload
224
224
 
225
- Screenshots are committed to `.pre-post/` on the current PR branch and served via `raw.githubusercontent.com`. This is the default — no external services needed.
225
+ Screenshots are committed to `.pre-post/` on the current PR branch and served via
226
+ GitHub blob URLs pinned to the commit SHA. This works for **both public and private
227
+ repos** — blob URLs are same-origin on GitHub, so the markdown renderer resolves them
228
+ with the viewer's authentication.
226
229
 
227
230
  ```bash
228
- # Default (git-native — commits to PR branch)
231
+ # Default (git-native — commits to PR branch, works on any repo)
229
232
  ./scripts/upload-and-copy.sh before.png after.png --markdown
230
233
 
231
- # Fallback: 0x0.st (no signup needed, 365-day expiry)
234
+ # Explicit override for external storage:
232
235
  IMAGE_ADAPTER=0x0st ./scripts/upload-and-copy.sh before.png after.png --markdown
233
-
234
- # GitHub Gist
235
- IMAGE_ADAPTER=gist ./scripts/upload-and-copy.sh before.png after.png --markdown
236
236
  ```
237
237
 
238
238
  ## Error Reference
@@ -244,3 +244,4 @@ IMAGE_ADAPTER=gist ./scripts/upload-and-copy.sh before.png after.png --markdown
244
244
  | 401/403 on production URL | See pre-flight section above |
245
245
  | Element not found | Verify selector exists on page |
246
246
  | No changed files detected | Specify routes manually with `--routes` |
247
+ | Could not determine commit SHA | Ensure `git push` succeeded and HEAD is valid |
@@ -1,17 +1,17 @@
1
1
  #!/bin/bash
2
- # Git-native adapter - Commit screenshots to .pre-post/ on the PR branch
2
+ # Git-native adapter - Stage a screenshot in .pre-post/ on the PR branch
3
3
  #
4
4
  # Usage: ./git-native.sh <file>
5
- # Output: raw.githubusercontent.com URL (stdout)
5
+ # Output: filename (stdout)
6
6
  #
7
7
  # Requirements:
8
- # - Inside a git repo with a remote named "origin"
9
- # - Current branch pushed to origin
8
+ # - Inside a git repo
10
9
  #
11
10
  # Notes:
12
11
  # - Stages only the specific file, never `git add .`
13
12
  # - Does NOT commit or push — the caller (upload-and-copy.sh) batches that
14
- # - Returns the raw GitHub URL the file will be available at after push
13
+ # - Returns filename only URL is constructed by upload-and-copy.sh after
14
+ # commit, using the SHA for blob URLs that work on public + private repos
15
15
 
16
16
  set -e
17
17
 
@@ -33,30 +33,6 @@ if ! git rev-parse --is-inside-work-tree &>/dev/null; then
33
33
  exit 1
34
34
  fi
35
35
 
36
- # Parse owner/repo from origin remote
37
- REMOTE_URL=$(git remote get-url origin 2>/dev/null)
38
- if [[ -z "$REMOTE_URL" ]]; then
39
- echo "Error: No 'origin' remote found" >&2
40
- exit 1
41
- fi
42
-
43
- # Extract owner/repo from HTTPS or SSH URL
44
- # HTTPS: https://github.com/owner/repo.git
45
- # SSH: git@github.com:owner/repo.git
46
- OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's#^(https?://github\.com/|git@github\.com:)##; s#\.git$##')
47
-
48
- if [[ -z "$OWNER_REPO" || ! "$OWNER_REPO" =~ / ]]; then
49
- echo "Error: Could not parse owner/repo from remote: $REMOTE_URL" >&2
50
- exit 1
51
- fi
52
-
53
- # Get current branch
54
- BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
55
- if [[ -z "$BRANCH" || "$BRANCH" == "HEAD" ]]; then
56
- echo "Error: Could not determine current branch (detached HEAD?)" >&2
57
- exit 1
58
- fi
59
-
60
36
  # Copy file into .pre-post/ at the repo root
61
37
  REPO_ROOT=$(git rev-parse --show-toplevel)
62
38
  DEST_DIR="$REPO_ROOT/.pre-post"
@@ -71,5 +47,5 @@ git add -f "$DEST"
71
47
 
72
48
  echo "Staged: .pre-post/$FILENAME" >&2
73
49
 
74
- # Return the raw GitHub URL (will resolve after push)
75
- echo "https://raw.githubusercontent.com/$OWNER_REPO/$BRANCH/.pre-post/$FILENAME"
50
+ # Return just the filename URL built by caller after commit
51
+ echo "$FILENAME"
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # Environment:
9
9
  # IMAGE_ADAPTER Storage adapter to use (default: git-native)
10
- # Available: git-native, 0x0st, gist, blob
10
+ # Available: git-native, 0x0st, blob
11
11
  #
12
12
  # Adapter-specific environment variables:
13
13
  # blob: BLOB_UPLOAD_URL - Custom upload endpoint
@@ -51,7 +51,7 @@ if [[ -z "$BEFORE_FILE" || -z "$AFTER_FILE" ]]; then
51
51
  echo ""
52
52
  echo "Environment:"
53
53
  echo " IMAGE_ADAPTER Storage adapter (default: git-native)"
54
- echo " Available: git-native, 0x0st, gist, blob"
54
+ echo " Available: git-native, 0x0st, blob"
55
55
  exit 1
56
56
  fi
57
57
 
@@ -79,6 +79,8 @@ if [[ ! -f "$ADAPTER_SCRIPT" ]]; then
79
79
  fi
80
80
 
81
81
  # Upload function using adapter
82
+ # NOTE: git-native adapter returns a filename (not a URL) — the URL is
83
+ # constructed below after commit+push, using the SHA for blob URLs.
82
84
  upload_file() {
83
85
  local file="$1"
84
86
  local filename=$(basename "$file")
@@ -89,16 +91,33 @@ upload_file() {
89
91
  "$ADAPTER_SCRIPT" "$file"
90
92
  }
91
93
 
92
- # Upload both files
94
+ # Upload both files (adapter returns filename for git-native, URL for others)
93
95
  echo "=== Uploading Screenshots ==="
94
- BEFORE_URL=$(upload_file "$BEFORE_FILE")
95
- AFTER_URL=$(upload_file "$AFTER_FILE")
96
+ BEFORE_RESULT=$(upload_file "$BEFORE_FILE")
97
+ AFTER_RESULT=$(upload_file "$AFTER_FILE")
96
98
 
97
- # For git-native adapter: batch commit + push after both files are staged
99
+ # For git-native: commit, push, then construct blob+SHA URLs.
100
+ # Blob URLs work for both public and private repos (same-origin on GitHub).
98
101
  if [[ "$IMAGE_ADAPTER" == "git-native" ]]; then
99
102
  echo "Committing and pushing screenshots..." >&2
100
103
  git commit -m "chore: add pre/post screenshots"
101
104
  git push origin HEAD
105
+
106
+ SHA=$(git rev-parse HEAD)
107
+ if [[ ! "$SHA" =~ ^[0-9a-f]{40}$ ]]; then
108
+ echo "Error: Could not determine commit SHA after push (got: '$SHA')" >&2
109
+ exit 1
110
+ fi
111
+
112
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null)
113
+ OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's#^(https?://github\.com/|git@github\.com:)##; s#\.git$##')
114
+
115
+ BEFORE_URL="https://github.com/$OWNER_REPO/blob/$SHA/.pre-post/$BEFORE_RESULT?raw=true"
116
+ AFTER_URL="https://github.com/$OWNER_REPO/blob/$SHA/.pre-post/$AFTER_RESULT?raw=true"
117
+ else
118
+ # Other adapters (0x0st, blob) return full URLs directly
119
+ BEFORE_URL="$BEFORE_RESULT"
120
+ AFTER_URL="$AFTER_RESULT"
102
121
  fi
103
122
 
104
123
  echo ""
@@ -1,59 +0,0 @@
1
- #!/bin/bash
2
- # GitHub Gist adapter - Upload images via gh CLI
3
- #
4
- # Usage: ./gist.sh <file>
5
- # Output: Raw URL to uploaded file (stdout)
6
- #
7
- # Requirements:
8
- # - gh CLI installed and authenticated
9
- #
10
- # Notes:
11
- # - Creates a public gist for each upload
12
- # - Files persist indefinitely
13
- # - Requires GitHub authentication
14
-
15
- set -e
16
-
17
- FILE="$1"
18
-
19
- if [[ -z "$FILE" ]]; then
20
- echo "Usage: $0 <file>" >&2
21
- exit 1
22
- fi
23
-
24
- if [[ ! -f "$FILE" ]]; then
25
- echo "Error: File not found: $FILE" >&2
26
- exit 1
27
- fi
28
-
29
- # Check gh is available
30
- if ! command -v gh &> /dev/null; then
31
- echo "Error: gh CLI not found. Install from https://cli.github.com" >&2
32
- exit 1
33
- fi
34
-
35
- # Create gist and capture output
36
- GIST_OUTPUT=$(gh gist create "$FILE" --public 2>&1)
37
-
38
- # Extract the gist URL from output
39
- GIST_URL=$(echo "$GIST_OUTPUT" | grep -o 'https://gist.github.com/[^ ]*' | head -1)
40
-
41
- if [[ -z "$GIST_URL" ]]; then
42
- echo "Error: Failed to create gist. Output: $GIST_OUTPUT" >&2
43
- exit 1
44
- fi
45
-
46
- # Convert to raw URL
47
- # Format: https://gist.github.com/user/id -> https://gist.githubusercontent.com/user/id/raw/filename
48
- GIST_ID=$(echo "$GIST_URL" | sed 's|.*/||')
49
- FILENAME=$(basename "$FILE")
50
-
51
- # Get the raw URL via gh api
52
- RAW_URL=$(gh api "gists/$GIST_ID" --jq ".files[\"$FILENAME\"].raw_url")
53
-
54
- if [[ -z "$RAW_URL" ]]; then
55
- echo "Error: Could not get raw URL for gist" >&2
56
- exit 1
57
- fi
58
-
59
- echo "$RAW_URL"