@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 +11 -13
- package/dist/upload.d.ts +10 -6
- package/dist/upload.d.ts.map +1 -1
- package/dist/upload.js +27 -10
- package/dist/upload.js.map +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +7 -6
- package/skill/scripts/adapters/git-native.sh +7 -31
- package/skill/scripts/upload-and-copy.sh +25 -6
- package/skill/scripts/adapters/gist.sh +0 -59
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
|
-
>
|
|
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
|
|
61
|
-
V
|
|
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**
|
|
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
|
|
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
|
-
|
|
178
|
+
Upload to a custom image storage service:
|
|
181
179
|
|
|
182
180
|
```bash
|
|
183
|
-
pre-post url1 url2 --upload-url https://
|
|
181
|
+
pre-post url1 url2 --markdown --upload-url https://my-s3-bucket.amazonaws.com
|
|
184
182
|
```
|
|
185
183
|
|
|
186
|
-
By default,
|
|
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
|
|
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
|
|
13
|
-
*
|
|
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):
|
|
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():
|
|
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;
|
package/dist/upload.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
|
72
|
-
*
|
|
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
|
|
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
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
package/dist/upload.js.map
CHANGED
|
@@ -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":"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"}
|
package/package.json
CHANGED
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
|
|
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
|
-
#
|
|
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 -
|
|
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:
|
|
5
|
+
# Output: filename (stdout)
|
|
6
6
|
#
|
|
7
7
|
# Requirements:
|
|
8
|
-
# - Inside a git repo
|
|
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
|
|
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
|
|
75
|
-
echo "
|
|
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,
|
|
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,
|
|
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
|
-
|
|
95
|
-
|
|
96
|
+
BEFORE_RESULT=$(upload_file "$BEFORE_FILE")
|
|
97
|
+
AFTER_RESULT=$(upload_file "$AFTER_FILE")
|
|
96
98
|
|
|
97
|
-
# For git-native
|
|
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"
|