httpcat-cli 0.0.17 → 0.0.20

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.
@@ -0,0 +1,27 @@
1
+ version: 2
2
+ updates:
3
+ # Enable version updates for npm
4
+ - package-ecosystem: "npm"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ open-pull-requests-limit: 5
9
+ labels:
10
+ - "dependencies"
11
+ - "automated"
12
+ commit-message:
13
+ prefix: "chore"
14
+ include: "scope"
15
+
16
+ # Enable version updates for GitHub Actions
17
+ - package-ecosystem: "github-actions"
18
+ directory: "/"
19
+ schedule:
20
+ interval: "weekly"
21
+ labels:
22
+ - "github-actions"
23
+ - "automated"
24
+ commit-message:
25
+ prefix: "ci"
26
+ include: "scope"
27
+
@@ -0,0 +1,49 @@
1
+ # GitHub Actions Workflows
2
+
3
+ This directory contains automated workflows for CI/CD and releases.
4
+
5
+ ## Workflows
6
+
7
+ ### `ci.yml`
8
+ Continuous Integration workflow that runs on every push and pull request:
9
+ - Runs tests across multiple Node.js versions (18, 20, 22)
10
+ - Type checking and linting
11
+ - Security audits
12
+ - Code coverage reporting
13
+
14
+ ### `release.yml`
15
+ Automated release workflow that:
16
+ - Triggers on version tags (v*.*.*) or manual dispatch
17
+ - Validates version format
18
+ - Runs tests and builds
19
+ - Publishes to npm
20
+ - Updates Homebrew formula
21
+ - Creates GitHub release with auto-generated release notes
22
+
23
+ ### `homebrew-tap.yml`
24
+ Manual workflow to update the Homebrew formula in the tap repository.
25
+
26
+ ## Secrets Required
27
+
28
+ Configure these in Repository Settings → Secrets and variables → Actions:
29
+
30
+ - `NPM_TOKEN`: npm authentication token with publish permissions
31
+ - Generate at: https://www.npmjs.com/settings/YOUR_USERNAME/tokens
32
+ - Required scopes: `read:packages`, `write:packages`
33
+
34
+ ## Usage
35
+
36
+ ### Creating a Release
37
+
38
+ 1. **Automatic (recommended)**: Push a version tag
39
+ ```bash
40
+ git tag v1.2.3
41
+ git push origin v1.2.3
42
+ ```
43
+
44
+ 2. **Manual**: Use GitHub Actions UI
45
+ - Go to Actions → Release → Run workflow
46
+ - Enter version number
47
+ - Click Run workflow
48
+
49
+ See [RELEASE.md](../RELEASE.md) for detailed release instructions.
@@ -0,0 +1,101 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ pull_request:
7
+ branches: [main, develop]
8
+
9
+ env:
10
+ NODE_VERSION: '20'
11
+
12
+ jobs:
13
+ test:
14
+ name: Test
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ matrix:
18
+ node-version: ['18', '20', '22']
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Setup Node.js ${{ matrix.node-version }}
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: ${{ matrix.node-version }}
27
+ cache: 'yarn'
28
+
29
+ - name: Install dependencies
30
+ run: yarn install --frozen-lockfile
31
+
32
+ - name: Run tests
33
+ run: yarn test
34
+
35
+ - name: Build
36
+ run: yarn build
37
+
38
+ - name: Upload coverage reports
39
+ if: matrix.node-version == '20'
40
+ uses: codecov/codecov-action@v4
41
+ with:
42
+ files: ./coverage/lcov.info
43
+ flags: unittests
44
+ name: codecov-umbrella
45
+ fail_ci_if_error: false
46
+
47
+ lint:
48
+ name: Lint & Type Check
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - name: Checkout code
52
+ uses: actions/checkout@v4
53
+
54
+ - name: Setup Node.js
55
+ uses: actions/setup-node@v4
56
+ with:
57
+ node-version: ${{ env.NODE_VERSION }}
58
+ cache: 'yarn'
59
+
60
+ - name: Install dependencies
61
+ run: yarn install --frozen-lockfile
62
+
63
+ - name: Type check
64
+ run: yarn build --noEmit || npx tsc --noEmit
65
+
66
+ - name: Check formatting (if configured)
67
+ continue-on-error: true
68
+ run: |
69
+ if [ -f ".prettierrc" ] || [ -f ".prettierrc.js" ] || [ -f ".prettierrc.json" ]; then
70
+ npx prettier --check "**/*.{ts,js,json,md}" || true
71
+ else
72
+ echo "No formatter configured, skipping..."
73
+ fi
74
+
75
+ security:
76
+ name: Security Audit
77
+ runs-on: ubuntu-latest
78
+ steps:
79
+ - name: Checkout code
80
+ uses: actions/checkout@v4
81
+
82
+ - name: Setup Node.js
83
+ uses: actions/setup-node@v4
84
+ with:
85
+ node-version: ${{ env.NODE_VERSION }}
86
+ cache: 'yarn'
87
+
88
+ - name: Install dependencies
89
+ run: yarn install --frozen-lockfile
90
+
91
+ - name: Run security audit
92
+ run: yarn audit --level moderate || true
93
+
94
+ - name: Check for known vulnerabilities
95
+ uses: snyk/actions/node@master
96
+ continue-on-error: true
97
+ env:
98
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
99
+ with:
100
+ args: --severity-threshold=high
101
+
@@ -0,0 +1,63 @@
1
+ name: Homebrew Tap Update
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: 'Version to update (e.g., 1.2.3)'
8
+ required: true
9
+ type: string
10
+
11
+ jobs:
12
+ update-formula:
13
+ name: Update Homebrew Formula
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout homebrew tap
17
+ uses: actions/checkout@v4
18
+ with:
19
+ repository: hathbanger/homebrew-httpcat
20
+ token: ${{ secrets.GITHUB_TOKEN }}
21
+ path: homebrew-tap
22
+
23
+ - name: Get npm package SHA256
24
+ id: npm-sha
25
+ run: |
26
+ VERSION="${{ github.event.inputs.version }}"
27
+ TARBALL_URL="https://registry.npmjs.org/httpcat-cli/-/httpcat-cli-${VERSION}.tgz"
28
+
29
+ echo "Downloading tarball to calculate SHA256..."
30
+ curl -L -o package.tgz "$TARBALL_URL"
31
+ SHA256=$(shasum -a 256 package.tgz | cut -d' ' -f1)
32
+ echo "sha256=$SHA256" >> $GITHUB_OUTPUT
33
+ echo "✅ SHA256: $SHA256"
34
+
35
+ - name: Update Homebrew formula
36
+ run: |
37
+ VERSION="${{ github.event.inputs.version }}"
38
+ SHA256="${{ steps.npm-sha.outputs.sha256 }}"
39
+ FORMULA_FILE="homebrew-tap/Formula/httpcat.rb"
40
+
41
+ # Update version
42
+ sed -i.bak "s|url \".*httpcat-cli-.*\.tgz\"|url \"https://registry.npmjs.org/httpcat-cli/-/httpcat-cli-${VERSION}.tgz\"|" "$FORMULA_FILE"
43
+
44
+ # Update SHA256
45
+ sed -i.bak "s|sha256 \".*\"|sha256 \"${SHA256}\"|" "$FORMULA_FILE"
46
+
47
+ # Update test version
48
+ sed -i.bak "s|assert_match \".*\"|assert_match \"${VERSION}\"|" "$FORMULA_FILE"
49
+
50
+ rm -f "${FORMULA_FILE}.bak"
51
+
52
+ echo "✅ Updated Homebrew formula:"
53
+ cat "$FORMULA_FILE"
54
+
55
+ - name: Commit and push
56
+ run: |
57
+ cd homebrew-tap
58
+ git config user.name "github-actions[bot]"
59
+ git config user.email "github-actions[bot]@users.noreply.github.com"
60
+ git add Formula/httpcat.rb
61
+ git commit -m "Update httpcat to ${{ github.event.inputs.version }}" || exit 0
62
+ git push
63
+
@@ -0,0 +1,361 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*.*.*' # Triggers on semantic version tags (e.g., v1.2.3)
7
+ workflow_dispatch:
8
+ inputs:
9
+ version:
10
+ description: 'Version to release (e.g., 1.2.3)'
11
+ required: true
12
+ type: string
13
+
14
+ env:
15
+ NODE_VERSION: '20'
16
+ REGISTRY_URL: 'https://registry.npmjs.org'
17
+
18
+ jobs:
19
+ # Job 1: Validate and prepare release
20
+ prepare:
21
+ name: Prepare Release
22
+ runs-on: ubuntu-latest
23
+ outputs:
24
+ version: ${{ steps.version.outputs.version }}
25
+ tag: ${{ steps.version.outputs.tag }}
26
+ npm-version: ${{ steps.version.outputs.npm-version }}
27
+ release-notes: ${{ steps.notes.outputs.notes }}
28
+ steps:
29
+ - name: Checkout code
30
+ uses: actions/checkout@v4
31
+ with:
32
+ fetch-depth: 0 # Full history for changelog generation
33
+
34
+ - name: Setup Node.js
35
+ uses: actions/setup-node@v4
36
+ with:
37
+ node-version: ${{ env.NODE_VERSION }}
38
+ registry-url: ${{ env.REGISTRY_URL }}
39
+
40
+ - name: Extract version from tag
41
+ id: version
42
+ run: |
43
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
44
+ VERSION="${{ github.event.inputs.version }}"
45
+ # Remove 'v' prefix if present
46
+ VERSION=${VERSION#v}
47
+ else
48
+ # Extract from tag (e.g., v1.2.3 -> 1.2.3)
49
+ VERSION=${GITHUB_REF#refs/tags/v}
50
+ fi
51
+
52
+ # Validate semantic version format
53
+ if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9-]+(\.[0-9]+)?)?$'; then
54
+ echo "❌ Invalid version format: $VERSION"
55
+ echo "Expected format: X.Y.Z or X.Y.Z-prerelease"
56
+ exit 1
57
+ fi
58
+
59
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
60
+ echo "tag=v$VERSION" >> $GITHUB_OUTPUT
61
+ echo "npm-version=$VERSION" >> $GITHUB_OUTPUT
62
+ echo "✅ Version: $VERSION"
63
+
64
+ - name: Verify version in package.json
65
+ run: |
66
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
67
+ RELEASE_VERSION="${{ steps.version.outputs.version }}"
68
+
69
+ if [ "$CURRENT_VERSION" != "$RELEASE_VERSION" ]; then
70
+ echo "⚠️ Warning: package.json version ($CURRENT_VERSION) doesn't match release version ($RELEASE_VERSION)"
71
+ echo "Updating package.json..."
72
+ npm version "$RELEASE_VERSION" --no-git-tag-version --allow-same-version
73
+ fi
74
+
75
+ - name: Generate release notes
76
+ id: notes
77
+ uses: actions/github-script@v7
78
+ with:
79
+ script: |
80
+ const { data: releases } = await github.rest.repos.listReleases({
81
+ owner: context.repo.owner,
82
+ repo: context.repo.repo,
83
+ per_page: 1
84
+ });
85
+
86
+ const lastTag = releases.length > 0 ? releases[0].tag_name : null;
87
+ const currentTag = 'v${{ steps.version.outputs.version }}';
88
+
89
+ // Get commits since last release
90
+ let baseSha;
91
+ if (lastTag) {
92
+ try {
93
+ const { data: tagData } = await github.rest.git.getRef({
94
+ owner: context.repo.owner,
95
+ repo: context.repo.repo,
96
+ ref: `tags/${lastTag}`
97
+ });
98
+ baseSha = tagData.object.sha;
99
+ } catch (e) {
100
+ // If tag ref doesn't exist, try to get commit from tag
101
+ const { data: tagData } = await github.rest.repos.getCommit({
102
+ owner: context.repo.owner,
103
+ repo: context.repo.repo,
104
+ ref: lastTag
105
+ });
106
+ baseSha = tagData.sha;
107
+ }
108
+ } else {
109
+ // Get the first commit or main branch
110
+ const { data: branchData } = await github.rest.repos.getBranch({
111
+ owner: context.repo.owner,
112
+ repo: context.repo.repo,
113
+ branch: 'main'
114
+ });
115
+ baseSha = branchData.commit.sha;
116
+ }
117
+
118
+ const { data: commits } = await github.rest.repos.compareCommits({
119
+ owner: context.repo.owner,
120
+ repo: context.repo.repo,
121
+ base: baseSha,
122
+ head: context.sha
123
+ });
124
+
125
+ // Categorize commits
126
+ const features = [];
127
+ const fixes = [];
128
+ const docs = [];
129
+ const chore = [];
130
+ const breaking = [];
131
+
132
+ for (const commit of commits.commits) {
133
+ const message = commit.commit.message;
134
+ const firstLine = message.split('\n')[0];
135
+
136
+ if (firstLine.match(/^BREAKING/)) {
137
+ breaking.push(`- ${firstLine.replace(/^BREAKING[:\s]+/i, '')}`);
138
+ } else if (firstLine.match(/^feat(ure)?[(:]/i)) {
139
+ features.push(`- ${firstLine.replace(/^feat(ure)?[(:]\s*/i, '')}`);
140
+ } else if (firstLine.match(/^fix[(]/i)) {
141
+ fixes.push(`- ${firstLine.replace(/^fix[(]\s*/i, '')}`);
142
+ } else if (firstLine.match(/^doc(s)?[(]/i)) {
143
+ docs.push(`- ${firstLine.replace(/^doc(s)?[(]\s*/i, '')}`);
144
+ } else if (!firstLine.match(/^(chore|ci|test|build)[(:]/i)) {
145
+ chore.push(`- ${firstLine}`);
146
+ }
147
+ }
148
+
149
+ let notes = `## 🎉 Release ${{ steps.version.outputs.version }}\n\n`;
150
+
151
+ if (breaking.length > 0) {
152
+ notes += `### ⚠️ Breaking Changes\n${breaking.join('\n')}\n\n`;
153
+ }
154
+
155
+ if (features.length > 0) {
156
+ notes += `### ✨ Features\n${features.join('\n')}\n\n`;
157
+ }
158
+
159
+ if (fixes.length > 0) {
160
+ notes += `### 🐛 Bug Fixes\n${fixes.join('\n')}\n\n`;
161
+ }
162
+
163
+ if (docs.length > 0) {
164
+ notes += `### 📚 Documentation\n${docs.join('\n')}\n\n`;
165
+ }
166
+
167
+ if (chore.length > 0 && chore.length < 10) {
168
+ notes += `### 🔧 Other Changes\n${chore.join('\n')}\n\n`;
169
+ }
170
+
171
+ notes += `### 📦 Installation\n\n`;
172
+ notes += `\`\`\`bash\n`;
173
+ notes += `# npm\n`;
174
+ notes += `npm install -g httpcat-cli@${{ steps.version.outputs.version }}\n\n`;
175
+ notes += `# Homebrew\n`;
176
+ notes += `brew upgrade httpcat\n`;
177
+ notes += `\`\`\`\n\n`;
178
+ notes += `---\n\n`;
179
+ notes += `**Full Changelog**: https://github.com/${{ github.repository }}/compare/${lastTag || 'main'}...${currentTag}`;
180
+
181
+ core.setOutput('notes', notes);
182
+ console.log('Generated release notes');
183
+
184
+ # Job 2: Build and test
185
+ test:
186
+ name: Build & Test
187
+ runs-on: ubuntu-latest
188
+ needs: prepare
189
+ steps:
190
+ - name: Checkout code
191
+ uses: actions/checkout@v4
192
+
193
+ - name: Setup Node.js
194
+ uses: actions/setup-node@v4
195
+ with:
196
+ node-version: ${{ env.NODE_VERSION }}
197
+ cache: 'yarn'
198
+
199
+ - name: Install dependencies
200
+ run: yarn install --frozen-lockfile
201
+
202
+ - name: Run linter (if configured)
203
+ continue-on-error: true
204
+ run: |
205
+ if [ -f ".eslintrc" ] || [ -f ".eslintrc.js" ] || [ -f ".eslintrc.json" ]; then
206
+ yarn lint
207
+ else
208
+ echo "No linter configured, skipping..."
209
+ fi
210
+
211
+ - name: Run tests
212
+ run: yarn test
213
+
214
+ - name: Build
215
+ run: yarn build
216
+
217
+ - name: Verify build output
218
+ run: |
219
+ if [ ! -f "dist/index.js" ]; then
220
+ echo "❌ Build failed: dist/index.js not found"
221
+ exit 1
222
+ fi
223
+ echo "✅ Build successful"
224
+
225
+ # Job 3: Publish to npm
226
+ publish-npm:
227
+ name: Publish to npm
228
+ runs-on: ubuntu-latest
229
+ needs: [prepare, test]
230
+ environment:
231
+ name: npm-publish
232
+ url: https://www.npmjs.com/package/httpcat-cli
233
+ permissions:
234
+ contents: read
235
+ id-token: write # For npm provenance
236
+ steps:
237
+ - name: Checkout code
238
+ uses: actions/checkout@v4
239
+
240
+ - name: Setup Node.js
241
+ uses: actions/setup-node@v4
242
+ with:
243
+ node-version: ${{ env.NODE_VERSION }}
244
+ registry-url: ${{ env.REGISTRY_URL }}
245
+
246
+ - name: Update package.json version
247
+ run: |
248
+ npm version "${{ needs.prepare.outputs.version }}" --no-git-tag-version --allow-same-version
249
+
250
+ - name: Install dependencies
251
+ run: yarn install --frozen-lockfile
252
+
253
+ - name: Build
254
+ run: yarn build
255
+
256
+ - name: Publish to npm
257
+ run: npm publish --provenance --access public
258
+ env:
259
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
260
+
261
+ - name: Verify npm publication
262
+ run: |
263
+ sleep 5 # Wait for npm CDN propagation
264
+ VERSION="${{ needs.prepare.outputs.version }}"
265
+ if npm view httpcat-cli@$VERSION version > /dev/null 2>&1; then
266
+ echo "✅ Successfully published httpcat-cli@$VERSION to npm"
267
+ else
268
+ echo "❌ Failed to verify npm publication"
269
+ exit 1
270
+ fi
271
+
272
+ # Job 4: Update Homebrew formula
273
+ update-homebrew:
274
+ name: Update Homebrew Formula
275
+ runs-on: ubuntu-latest
276
+ needs: [prepare, publish-npm]
277
+ steps:
278
+ - name: Checkout code
279
+ uses: actions/checkout@v4
280
+ with:
281
+ token: ${{ secrets.GITHUB_TOKEN }}
282
+
283
+ - name: Wait for npm CDN propagation
284
+ run: |
285
+ VERSION="${{ needs.prepare.outputs.version }}"
286
+ echo "Waiting for npm package to be available..."
287
+ for i in {1..30}; do
288
+ if npm view httpcat-cli@$VERSION version > /dev/null 2>&1; then
289
+ echo "✅ Package is available on npm"
290
+ break
291
+ fi
292
+ echo "Attempt $i/30: Package not yet available, waiting 10s..."
293
+ sleep 10
294
+ done
295
+
296
+ - name: Get npm package SHA256
297
+ id: npm-sha
298
+ run: |
299
+ VERSION="${{ needs.prepare.outputs.version }}"
300
+ TARBALL_URL="https://registry.npmjs.org/httpcat-cli/-/httpcat-cli-${VERSION}.tgz"
301
+
302
+ echo "Downloading tarball to calculate SHA256..."
303
+ curl -L -o package.tgz "$TARBALL_URL"
304
+ SHA256=$(shasum -a 256 package.tgz | cut -d' ' -f1)
305
+ echo "sha256=$SHA256" >> $GITHUB_OUTPUT
306
+ echo "✅ SHA256: $SHA256"
307
+
308
+ - name: Update Homebrew formula
309
+ run: |
310
+ VERSION="${{ needs.prepare.outputs.version }}"
311
+ SHA256="${{ steps.npm-sha.outputs.sha256 }}"
312
+ FORMULA_FILE="homebrew-httpcat/Formula/httpcat.rb"
313
+
314
+ # Update version
315
+ sed -i.bak "s|url \".*httpcat-cli-.*\.tgz\"|url \"https://registry.npmjs.org/httpcat-cli/-/httpcat-cli-${VERSION}.tgz\"|" "$FORMULA_FILE"
316
+
317
+ # Update SHA256
318
+ sed -i.bak "s|sha256 \".*\"|sha256 \"${SHA256}\"|" "$FORMULA_FILE"
319
+
320
+ # Update test version
321
+ sed -i.bak "s|assert_match \".*\"|assert_match \"${VERSION}\"|" "$FORMULA_FILE"
322
+
323
+ rm -f "${FORMULA_FILE}.bak"
324
+
325
+ echo "✅ Updated Homebrew formula:"
326
+ cat "$FORMULA_FILE"
327
+
328
+ - name: Commit and push Homebrew formula update
329
+ run: |
330
+ git config user.name "github-actions[bot]"
331
+ git config user.email "github-actions[bot]@users.noreply.github.com"
332
+ git add homebrew-httpcat/Formula/httpcat.rb
333
+ git commit -m "chore: update Homebrew formula to v${{ needs.prepare.outputs.version }}" || exit 0
334
+ git push
335
+
336
+ # Job 5: Create GitHub Release
337
+ create-release:
338
+ name: Create GitHub Release
339
+ runs-on: ubuntu-latest
340
+ needs: [prepare, publish-npm, update-homebrew]
341
+ permissions:
342
+ contents: write
343
+ steps:
344
+ - name: Create GitHub Release
345
+ uses: softprops/action-gh-release@v1
346
+ with:
347
+ tag_name: ${{ needs.prepare.outputs.tag }}
348
+ name: Release ${{ needs.prepare.outputs.version }}
349
+ body: ${{ needs.prepare.outputs.release-notes }}
350
+ draft: false
351
+ prerelease: ${{ contains(needs.prepare.outputs.version, '-') }}
352
+ env:
353
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
354
+
355
+ - name: Release summary
356
+ run: |
357
+ echo "✅ Release created successfully!"
358
+ echo "Tag: ${{ needs.prepare.outputs.tag }}"
359
+ echo "Version: ${{ needs.prepare.outputs.version }}"
360
+ echo "npm: https://www.npmjs.com/package/httpcat-cli/v/${{ needs.prepare.outputs.version }}"
361
+ echo "GitHub: https://github.com/${{ github.repository }}/releases/tag/${{ needs.prepare.outputs.tag }}"