@makispps/releasejet 1.0.0 → 1.0.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/.releasejet.example.yml +28 -28
- package/README.md +197 -145
- package/ci/release-notes-github.yml +19 -19
- package/ci/release-notes-gitlab.yml +22 -22
- package/dist/cli.js +199 -45
- package/package.json +60 -59
package/.releasejet.example.yml
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
# ReleaseJet Configuration
|
|
2
|
-
# Copy to .releasejet.yml and customize for your project.
|
|
3
|
-
# Or run: releasejet init
|
|
4
|
-
|
|
5
|
-
# GitLab instance URL
|
|
6
|
-
gitlab:
|
|
7
|
-
url: https://gitlab.example.com
|
|
8
|
-
|
|
9
|
-
# Client definitions (omit for single-client repos)
|
|
10
|
-
# clients:
|
|
11
|
-
# - prefix: mobile
|
|
12
|
-
# label: MOBILE
|
|
13
|
-
# - prefix: web
|
|
14
|
-
# label: WEB
|
|
15
|
-
|
|
16
|
-
# Category label mappings
|
|
17
|
-
# Key: the label name in GitLab
|
|
18
|
-
# Value: the section heading in release notes
|
|
19
|
-
categories:
|
|
20
|
-
feature: "New Features"
|
|
21
|
-
bug: "Bug Fixes"
|
|
22
|
-
improvement: "Improvements"
|
|
23
|
-
breaking-change: "Breaking Changes"
|
|
24
|
-
|
|
25
|
-
# How to handle uncategorized issues
|
|
26
|
-
# "lenient" — include under "Other" with a warning (default)
|
|
27
|
-
# "strict" — fail release generation
|
|
28
|
-
uncategorized: lenient
|
|
1
|
+
# ReleaseJet Configuration
|
|
2
|
+
# Copy to .releasejet.yml and customize for your project.
|
|
3
|
+
# Or run: releasejet init
|
|
4
|
+
|
|
5
|
+
# GitLab instance URL
|
|
6
|
+
gitlab:
|
|
7
|
+
url: https://gitlab.example.com
|
|
8
|
+
|
|
9
|
+
# Client definitions (omit for single-client repos)
|
|
10
|
+
# clients:
|
|
11
|
+
# - prefix: mobile
|
|
12
|
+
# label: MOBILE
|
|
13
|
+
# - prefix: web
|
|
14
|
+
# label: WEB
|
|
15
|
+
|
|
16
|
+
# Category label mappings
|
|
17
|
+
# Key: the label name in GitLab
|
|
18
|
+
# Value: the section heading in release notes
|
|
19
|
+
categories:
|
|
20
|
+
feature: "New Features"
|
|
21
|
+
bug: "Bug Fixes"
|
|
22
|
+
improvement: "Improvements"
|
|
23
|
+
breaking-change: "Breaking Changes"
|
|
24
|
+
|
|
25
|
+
# How to handle uncategorized issues
|
|
26
|
+
# "lenient" — include under "Other" with a warning (default)
|
|
27
|
+
# "strict" — fail release generation
|
|
28
|
+
uncategorized: lenient
|
package/README.md
CHANGED
|
@@ -1,145 +1,197 @@
|
|
|
1
|
-
<img width="480" height="120" alt="lockup-light-1x" src="https://github.com/user-attachments/assets/1fd84e91-86f3-4f62-bad7-8bf4b72b517f" />
|
|
2
|
-
|
|
3
|
-
Automated release notes generator for GitLab and GitHub. Collects closed issues (or merged pull requests) between Git tags, categorizes them by label, and publishes formatted release notes.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **GitLab and GitHub support** — works with both providers out of the box
|
|
8
|
-
- **Issues or Pull Requests** — generate notes from closed issues (default) or merged PRs (GitHub)
|
|
9
|
-
- **Multi-client repos** — filter by client label (e.g., `mobile-v1.0.0`, `web-v2.0.0`)
|
|
10
|
-
- **Single-client repos** — just use `v<semver>` tags
|
|
11
|
-
- **Configurable categories** — map labels to sections (features, bugs, improvements, etc.)
|
|
12
|
-
- **CI/CD integration** — runs automatically on tag push via GitLab CI or GitHub Actions
|
|
13
|
-
- **Strict/lenient modes** — enforce labeling or allow uncategorized issues under "Other"
|
|
14
|
-
- **Milestone detection** — automatically links the most common milestone in release notes
|
|
15
|
-
|
|
16
|
-
## Quick Start
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install -g releasejet
|
|
20
|
-
|
|
21
|
-
# Interactive setup (detects provider from git remote)
|
|
22
|
-
releasejet init
|
|
23
|
-
|
|
24
|
-
# Preview release notes
|
|
25
|
-
releasejet generate --tag v1.0.0
|
|
26
|
-
|
|
27
|
-
# Generate and publish
|
|
28
|
-
releasejet generate --tag v1.0.0 --publish
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Configuration
|
|
32
|
-
|
|
33
|
-
Create `.releasejet.yml` in your project root (or run `releasejet init`):
|
|
34
|
-
|
|
35
|
-
```yaml
|
|
36
|
-
provider:
|
|
37
|
-
type: github # 'gitlab' or 'github'
|
|
38
|
-
url: https://github.com
|
|
39
|
-
|
|
40
|
-
# GitHub-only: generate notes from issues or pull requests
|
|
41
|
-
source: issues # 'issues' (default) or 'pull_requests'
|
|
42
|
-
|
|
43
|
-
# For multi-client repos (omit for single-client)
|
|
44
|
-
clients:
|
|
45
|
-
- prefix: mobile
|
|
46
|
-
label: MOBILE
|
|
47
|
-
- prefix: web
|
|
48
|
-
label: WEB
|
|
49
|
-
|
|
50
|
-
categories:
|
|
51
|
-
feature: "New Features"
|
|
52
|
-
bug: "Bug Fixes"
|
|
53
|
-
improvement: "Improvements"
|
|
54
|
-
breaking-change: "Breaking Changes"
|
|
55
|
-
|
|
56
|
-
uncategorized: lenient # or "strict" to enforce labeling
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## CI/CD Integration
|
|
60
|
-
|
|
61
|
-
### GitHub Actions
|
|
62
|
-
|
|
63
|
-
Run `releasejet init` and select CI setup, or add `.github/workflows/release-notes.yml`:
|
|
64
|
-
|
|
65
|
-
```yaml
|
|
66
|
-
name: Release Notes
|
|
67
|
-
on:
|
|
68
|
-
push:
|
|
69
|
-
tags:
|
|
70
|
-
- '**'
|
|
71
|
-
jobs:
|
|
72
|
-
release-notes:
|
|
73
|
-
runs-on: ubuntu-latest
|
|
74
|
-
permissions:
|
|
75
|
-
contents: write
|
|
76
|
-
steps:
|
|
77
|
-
- uses: actions/checkout@v4
|
|
78
|
-
- uses: actions/setup-node@v4
|
|
79
|
-
with:
|
|
80
|
-
node-version: '20'
|
|
81
|
-
- run: npm install -g releasejet
|
|
82
|
-
- run: releasejet generate --tag "${{ github.ref_name }}" --publish
|
|
83
|
-
env:
|
|
84
|
-
RELEASEJET_TOKEN: ${{ secrets.RELEASEJET_TOKEN }}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Set `RELEASEJET_TOKEN` as a repository secret (Settings > Secrets > Actions).
|
|
88
|
-
|
|
89
|
-
### GitLab CI
|
|
90
|
-
|
|
91
|
-
Add to your `.gitlab-ci.yml` (or run `releasejet ci enable`):
|
|
92
|
-
|
|
93
|
-
```yaml
|
|
94
|
-
release-notes:
|
|
95
|
-
stage: deploy
|
|
96
|
-
image: node:20-alpine
|
|
97
|
-
rules:
|
|
98
|
-
- if: $CI_COMMIT_TAG
|
|
99
|
-
before_script:
|
|
100
|
-
- npm install -g releasejet
|
|
101
|
-
script:
|
|
102
|
-
- releasejet generate --tag "$CI_COMMIT_TAG" --publish
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Set `GITLAB_API_TOKEN` (or `RELEASEJET_TOKEN`) as a CI/CD variable with `api` scope.
|
|
106
|
-
|
|
107
|
-
## Authentication
|
|
108
|
-
|
|
109
|
-
Token resolution order:
|
|
110
|
-
|
|
111
|
-
1. `RELEASEJET_TOKEN` env var (works for both providers)
|
|
112
|
-
2. Provider-specific env var: `GITLAB_API_TOKEN` or `GITHUB_TOKEN`
|
|
113
|
-
3. Stored credentials from `~/.releasejet/credentials.yml`
|
|
114
|
-
|
|
115
|
-
## Tag Format
|
|
116
|
-
|
|
117
|
-
| Repo type | Format | Example |
|
|
118
|
-
|-----------|--------|---------|
|
|
119
|
-
| Multi-client | `<prefix>-v<semver>` | `mobile-v1.2.0` |
|
|
120
|
-
| Single-client | `v<semver>` | `v1.2.0` |
|
|
121
|
-
|
|
122
|
-
## Commands
|
|
123
|
-
|
|
124
|
-
| Command | Description |
|
|
125
|
-
|---------|-------------|
|
|
126
|
-
| `releasejet init` | Interactive setup wizard |
|
|
127
|
-
| `releasejet generate --tag <tag>` | Generate release notes |
|
|
128
|
-
| `releasejet generate --tag <tag> --publish` | Generate and publish release |
|
|
129
|
-
| `releasejet validate` | Check issues for proper labeling |
|
|
130
|
-
| `releasejet ci enable` | Add CI configuration to `.gitlab-ci.yml` |
|
|
131
|
-
| `releasejet ci disable` | Remove CI configuration |
|
|
132
|
-
|
|
133
|
-
### Generate Flags
|
|
134
|
-
|
|
135
|
-
| Flag | Description |
|
|
136
|
-
|------|-------------|
|
|
137
|
-
| `--publish` | Publish as a release on the provider |
|
|
138
|
-
| `--dry-run` | Preview without publishing |
|
|
139
|
-
| `--format <format>` | Output format: `markdown` (default) or `json` |
|
|
140
|
-
| `--config <path>` | Custom config file path |
|
|
141
|
-
| `--debug` | Show debug information |
|
|
142
|
-
|
|
143
|
-
##
|
|
144
|
-
|
|
145
|
-
|
|
1
|
+
<img width="480" height="120" alt="lockup-light-1x" src="https://github.com/user-attachments/assets/1fd84e91-86f3-4f62-bad7-8bf4b72b517f" />
|
|
2
|
+
|
|
3
|
+
Automated release notes generator for GitLab and GitHub. Collects closed issues (or merged pull requests) between Git tags, categorizes them by label, and publishes formatted release notes.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **GitLab and GitHub support** — works with both providers out of the box
|
|
8
|
+
- **Issues or Pull Requests** — generate notes from closed issues (default) or merged PRs (GitHub)
|
|
9
|
+
- **Multi-client repos** — filter by client label (e.g., `mobile-v1.0.0`, `web-v2.0.0`)
|
|
10
|
+
- **Single-client repos** — just use `v<semver>` tags
|
|
11
|
+
- **Configurable categories** — map labels to sections (features, bugs, improvements, etc.)
|
|
12
|
+
- **CI/CD integration** — runs automatically on tag push via GitLab CI or GitHub Actions
|
|
13
|
+
- **Strict/lenient modes** — enforce labeling or allow uncategorized issues under "Other"
|
|
14
|
+
- **Milestone detection** — automatically links the most common milestone in release notes
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g releasejet
|
|
20
|
+
|
|
21
|
+
# Interactive setup (detects provider from git remote)
|
|
22
|
+
releasejet init
|
|
23
|
+
|
|
24
|
+
# Preview release notes
|
|
25
|
+
releasejet generate --tag v1.0.0
|
|
26
|
+
|
|
27
|
+
# Generate and publish
|
|
28
|
+
releasejet generate --tag v1.0.0 --publish
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
Create `.releasejet.yml` in your project root (or run `releasejet init`):
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
provider:
|
|
37
|
+
type: github # 'gitlab' or 'github'
|
|
38
|
+
url: https://github.com
|
|
39
|
+
|
|
40
|
+
# GitHub-only: generate notes from issues or pull requests
|
|
41
|
+
source: issues # 'issues' (default) or 'pull_requests'
|
|
42
|
+
|
|
43
|
+
# For multi-client repos (omit for single-client)
|
|
44
|
+
clients:
|
|
45
|
+
- prefix: mobile
|
|
46
|
+
label: MOBILE
|
|
47
|
+
- prefix: web
|
|
48
|
+
label: WEB
|
|
49
|
+
|
|
50
|
+
categories:
|
|
51
|
+
feature: "New Features"
|
|
52
|
+
bug: "Bug Fixes"
|
|
53
|
+
improvement: "Improvements"
|
|
54
|
+
breaking-change: "Breaking Changes"
|
|
55
|
+
|
|
56
|
+
uncategorized: lenient # or "strict" to enforce labeling
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## CI/CD Integration
|
|
60
|
+
|
|
61
|
+
### GitHub Actions
|
|
62
|
+
|
|
63
|
+
Run `releasejet init` and select CI setup, or add `.github/workflows/release-notes.yml`:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
name: Release Notes
|
|
67
|
+
on:
|
|
68
|
+
push:
|
|
69
|
+
tags:
|
|
70
|
+
- '**'
|
|
71
|
+
jobs:
|
|
72
|
+
release-notes:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
permissions:
|
|
75
|
+
contents: write
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
- uses: actions/setup-node@v4
|
|
79
|
+
with:
|
|
80
|
+
node-version: '20'
|
|
81
|
+
- run: npm install -g releasejet
|
|
82
|
+
- run: releasejet generate --tag "${{ github.ref_name }}" --publish
|
|
83
|
+
env:
|
|
84
|
+
RELEASEJET_TOKEN: ${{ secrets.RELEASEJET_TOKEN }}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Set `RELEASEJET_TOKEN` as a repository secret (Settings > Secrets > Actions).
|
|
88
|
+
|
|
89
|
+
### GitLab CI
|
|
90
|
+
|
|
91
|
+
Add to your `.gitlab-ci.yml` (or run `releasejet ci enable`):
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
release-notes:
|
|
95
|
+
stage: deploy
|
|
96
|
+
image: node:20-alpine
|
|
97
|
+
rules:
|
|
98
|
+
- if: $CI_COMMIT_TAG
|
|
99
|
+
before_script:
|
|
100
|
+
- npm install -g releasejet
|
|
101
|
+
script:
|
|
102
|
+
- releasejet generate --tag "$CI_COMMIT_TAG" --publish
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Set `GITLAB_API_TOKEN` (or `RELEASEJET_TOKEN`) as a CI/CD variable with `api` scope.
|
|
106
|
+
|
|
107
|
+
## Authentication
|
|
108
|
+
|
|
109
|
+
Token resolution order:
|
|
110
|
+
|
|
111
|
+
1. `RELEASEJET_TOKEN` env var (works for both providers)
|
|
112
|
+
2. Provider-specific env var: `GITLAB_API_TOKEN` or `GITHUB_TOKEN`
|
|
113
|
+
3. Stored credentials from `~/.releasejet/credentials.yml`
|
|
114
|
+
|
|
115
|
+
## Tag Format
|
|
116
|
+
|
|
117
|
+
| Repo type | Format | Example |
|
|
118
|
+
|-----------|--------|---------|
|
|
119
|
+
| Multi-client | `<prefix>-v<semver>` | `mobile-v1.2.0` |
|
|
120
|
+
| Single-client | `v<semver>` | `v1.2.0` |
|
|
121
|
+
|
|
122
|
+
## Commands
|
|
123
|
+
|
|
124
|
+
| Command | Description |
|
|
125
|
+
|---------|-------------|
|
|
126
|
+
| `releasejet init` | Interactive setup wizard |
|
|
127
|
+
| `releasejet generate --tag <tag>` | Generate release notes |
|
|
128
|
+
| `releasejet generate --tag <tag> --publish` | Generate and publish release |
|
|
129
|
+
| `releasejet validate` | Check issues for proper labeling |
|
|
130
|
+
| `releasejet ci enable` | Add CI configuration to `.gitlab-ci.yml` |
|
|
131
|
+
| `releasejet ci disable` | Remove CI configuration |
|
|
132
|
+
|
|
133
|
+
### Generate Flags
|
|
134
|
+
|
|
135
|
+
| Flag | Description |
|
|
136
|
+
|------|-------------|
|
|
137
|
+
| `--publish` | Publish as a release on the provider |
|
|
138
|
+
| `--dry-run` | Preview without publishing |
|
|
139
|
+
| `--format <format>` | Output format: `markdown` (default) or `json` |
|
|
140
|
+
| `--config <path>` | Custom config file path |
|
|
141
|
+
| `--debug` | Show debug information |
|
|
142
|
+
|
|
143
|
+
## Troubleshooting
|
|
144
|
+
|
|
145
|
+
### "API token not found"
|
|
146
|
+
|
|
147
|
+
ReleaseJet checks three sources in order: `RELEASEJET_TOKEN` env var, provider-specific env var (`GITLAB_API_TOKEN` or `GITHUB_TOKEN`), and `~/.releasejet/credentials.yml`. Verify your token is set:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
echo $RELEASEJET_TOKEN
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To reconfigure, run `releasejet init`.
|
|
154
|
+
|
|
155
|
+
### "Tag not found in remote repository"
|
|
156
|
+
|
|
157
|
+
The tag exists locally but hasn't been pushed. Push it first:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
git push origin <tag>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### "Invalid tag format"
|
|
164
|
+
|
|
165
|
+
Tags must match `v<semver>` (e.g., `v1.2.0`) or `<prefix>-v<semver>` (e.g., `mobile-v1.2.0`). Suffixes like `v1.2.0-beta` are supported but the core version must be valid semver.
|
|
166
|
+
|
|
167
|
+
### Issues missing from release notes
|
|
168
|
+
|
|
169
|
+
ReleaseJet includes issues closed *between* the previous tag and the current tag (by `closedAt` timestamp, not `updatedAt`). Check that:
|
|
170
|
+
|
|
171
|
+
- The issue is **closed** (not just merged)
|
|
172
|
+
- The close date falls within the tag window
|
|
173
|
+
- The issue has the correct **client label** (multi-client repos)
|
|
174
|
+
|
|
175
|
+
Use `--debug` to see the date range and which issues were filtered.
|
|
176
|
+
|
|
177
|
+
### "Request failed with status 401" or "403"
|
|
178
|
+
|
|
179
|
+
The API token doesn't have the required permissions. GitLab tokens need `api` scope. GitHub tokens need `repo` scope. Regenerate the token with the correct scope and update it via `releasejet init` or the `RELEASEJET_TOKEN` env var.
|
|
180
|
+
|
|
181
|
+
### `source: pull_requests` not working
|
|
182
|
+
|
|
183
|
+
Pull request source is only supported for GitHub. GitLab projects must use `source: issues` (the default).
|
|
184
|
+
|
|
185
|
+
### Config changes not taking effect
|
|
186
|
+
|
|
187
|
+
Run with `--debug` to see the loaded config:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
releasejet generate --tag <tag> --debug
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Invalid values (e.g., `uncategorized: "strictt"`) now produce clear error messages instead of being silently ignored.
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
MIT
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
name: Release Notes
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
tags:
|
|
5
|
-
- '**'
|
|
6
|
-
jobs:
|
|
7
|
-
release-notes:
|
|
8
|
-
runs-on: ubuntu-latest
|
|
9
|
-
permissions:
|
|
10
|
-
contents: write
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
- uses: actions/setup-node@v4
|
|
14
|
-
with:
|
|
15
|
-
node-version: '20'
|
|
16
|
-
- run: npm install -g releasejet
|
|
17
|
-
- run: releasejet generate --tag "${{ github.ref_name }}" --publish
|
|
18
|
-
env:
|
|
19
|
-
RELEASEJET_TOKEN: ${{ secrets.RELEASEJET_TOKEN }}
|
|
1
|
+
name: Release Notes
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- '**'
|
|
6
|
+
jobs:
|
|
7
|
+
release-notes:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-node@v4
|
|
14
|
+
with:
|
|
15
|
+
node-version: '20'
|
|
16
|
+
- run: npm install -g releasejet
|
|
17
|
+
- run: releasejet generate --tag "${{ github.ref_name }}" --publish
|
|
18
|
+
env:
|
|
19
|
+
RELEASEJET_TOKEN: ${{ secrets.RELEASEJET_TOKEN }}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
# ReleaseJet — Shared GitLab CI Template
|
|
2
|
-
#
|
|
3
|
-
# Include in your project's .gitlab-ci.yml:
|
|
4
|
-
#
|
|
5
|
-
# include:
|
|
6
|
-
# - project: 'tools/releasejet'
|
|
7
|
-
# file: '/ci/release-notes.yml'
|
|
8
|
-
#
|
|
9
|
-
# variables:
|
|
10
|
-
# RELEASEJET_TOKEN: $GITLAB_API_TOKEN
|
|
11
|
-
|
|
12
|
-
release-notes:
|
|
13
|
-
stage: deploy
|
|
14
|
-
image: node:20-alpine
|
|
15
|
-
rules:
|
|
16
|
-
- if: $CI_COMMIT_TAG
|
|
17
|
-
variables:
|
|
18
|
-
RELEASEJET_TOKEN: ${RELEASEJET_TOKEN}
|
|
19
|
-
before_script:
|
|
20
|
-
- npm install -g releasejet
|
|
21
|
-
script:
|
|
22
|
-
- releasejet generate --tag "$CI_COMMIT_TAG" --publish
|
|
1
|
+
# ReleaseJet — Shared GitLab CI Template
|
|
2
|
+
#
|
|
3
|
+
# Include in your project's .gitlab-ci.yml:
|
|
4
|
+
#
|
|
5
|
+
# include:
|
|
6
|
+
# - project: 'tools/releasejet'
|
|
7
|
+
# file: '/ci/release-notes.yml'
|
|
8
|
+
#
|
|
9
|
+
# variables:
|
|
10
|
+
# RELEASEJET_TOKEN: $GITLAB_API_TOKEN
|
|
11
|
+
|
|
12
|
+
release-notes:
|
|
13
|
+
stage: deploy
|
|
14
|
+
image: node:20-alpine
|
|
15
|
+
rules:
|
|
16
|
+
- if: $CI_COMMIT_TAG
|
|
17
|
+
variables:
|
|
18
|
+
RELEASEJET_TOKEN: ${RELEASEJET_TOKEN}
|
|
19
|
+
before_script:
|
|
20
|
+
- npm install -g releasejet
|
|
21
|
+
script:
|
|
22
|
+
- releasejet generate --tag "$CI_COMMIT_TAG" --publish
|
package/dist/cli.js
CHANGED
|
@@ -37,17 +37,33 @@ async function loadConfig(configPath = ".releasejet.yml") {
|
|
|
37
37
|
return mergeWithDefaults(raw);
|
|
38
38
|
}
|
|
39
39
|
function mergeWithDefaults(raw) {
|
|
40
|
-
const clients = raw.clients;
|
|
41
|
-
const categories = raw.categories;
|
|
42
|
-
const uncategorized = raw.uncategorized;
|
|
43
|
-
const source = raw.source;
|
|
44
40
|
const providerRaw = raw.provider;
|
|
45
41
|
const gitlabRaw = raw.gitlab;
|
|
42
|
+
const source = raw.source;
|
|
43
|
+
const uncategorized = raw.uncategorized;
|
|
44
|
+
const clientsRaw = raw.clients;
|
|
45
|
+
const categoriesRaw = raw.categories;
|
|
46
46
|
let provider;
|
|
47
47
|
if (providerRaw) {
|
|
48
|
+
const pType = providerRaw.type;
|
|
49
|
+
if (pType !== void 0 && pType !== "gitlab" && pType !== "github") {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Invalid config in .releasejet.yml
|
|
52
|
+
|
|
53
|
+
provider.type: "${pType}" is not valid. Expected "gitlab" or "github".`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const pUrl = providerRaw.url ?? "";
|
|
57
|
+
if (pUrl && !pUrl.startsWith("http://") && !pUrl.startsWith("https://")) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Invalid config in .releasejet.yml
|
|
60
|
+
|
|
61
|
+
provider.url: "${pUrl}" is not valid. Must start with http:// or https://.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
48
64
|
provider = {
|
|
49
|
-
type:
|
|
50
|
-
url:
|
|
65
|
+
type: pType ?? "gitlab",
|
|
66
|
+
url: pUrl
|
|
51
67
|
};
|
|
52
68
|
} else if (gitlabRaw) {
|
|
53
69
|
provider = {
|
|
@@ -57,12 +73,51 @@ function mergeWithDefaults(raw) {
|
|
|
57
73
|
} else {
|
|
58
74
|
provider = { type: "gitlab", url: "" };
|
|
59
75
|
}
|
|
76
|
+
if (source !== void 0 && source !== "issues" && source !== "pull_requests") {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Invalid config in .releasejet.yml
|
|
79
|
+
|
|
80
|
+
source: "${source}" is not valid. Expected "issues" or "pull_requests".`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (uncategorized !== void 0 && uncategorized !== "lenient" && uncategorized !== "strict") {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Invalid config in .releasejet.yml
|
|
86
|
+
|
|
87
|
+
uncategorized: "${uncategorized}" is not valid. Expected "lenient" or "strict".`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
const clients = [];
|
|
91
|
+
if (Array.isArray(clientsRaw)) {
|
|
92
|
+
for (let i = 0; i < clientsRaw.length; i++) {
|
|
93
|
+
const entry = clientsRaw[i];
|
|
94
|
+
if (!entry?.prefix || !entry?.label) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Invalid config in .releasejet.yml
|
|
97
|
+
|
|
98
|
+
clients[${i}]: "prefix" and "label" are required.`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
clients.push({ prefix: entry.prefix, label: entry.label });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
let categories;
|
|
105
|
+
if (categoriesRaw !== void 0) {
|
|
106
|
+
if (typeof categoriesRaw !== "object" || categoriesRaw === null || Array.isArray(categoriesRaw)) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
"Invalid config in .releasejet.yml\n\n categories: expected an object mapping labels to headings."
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
categories = categoriesRaw;
|
|
112
|
+
} else {
|
|
113
|
+
categories = { ...DEFAULT_CATEGORIES };
|
|
114
|
+
}
|
|
60
115
|
return {
|
|
61
116
|
provider,
|
|
62
|
-
source: source
|
|
63
|
-
clients
|
|
64
|
-
categories
|
|
65
|
-
uncategorized: uncategorized
|
|
117
|
+
source: source ?? "issues",
|
|
118
|
+
clients,
|
|
119
|
+
categories,
|
|
120
|
+
uncategorized: uncategorized ?? "lenient"
|
|
66
121
|
};
|
|
67
122
|
}
|
|
68
123
|
|
|
@@ -465,15 +520,55 @@ async function promptForUncategorized(issues, config) {
|
|
|
465
520
|
}
|
|
466
521
|
}
|
|
467
522
|
|
|
523
|
+
// src/cli/error-handler.ts
|
|
524
|
+
function withErrorHandler(fn) {
|
|
525
|
+
return async (...args) => {
|
|
526
|
+
try {
|
|
527
|
+
await fn(...args);
|
|
528
|
+
} catch (err) {
|
|
529
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
530
|
+
const isDebug = process.argv.includes("--debug");
|
|
531
|
+
console.error(`
|
|
532
|
+
Error: ${message}`);
|
|
533
|
+
if (isDebug && err instanceof Error && err.stack) {
|
|
534
|
+
console.error(`
|
|
535
|
+
${err.stack}`);
|
|
536
|
+
} else if (!isDebug) {
|
|
537
|
+
console.error("\n Re-run with --debug for more details.");
|
|
538
|
+
}
|
|
539
|
+
process.exitCode = 1;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/cli/logger.ts
|
|
545
|
+
function createLogger(enabled) {
|
|
546
|
+
return {
|
|
547
|
+
debug: enabled ? (...args) => console.error("[DEBUG]", ...args) : (() => {
|
|
548
|
+
})
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
468
552
|
// src/cli/commands/generate.ts
|
|
553
|
+
import ora from "ora";
|
|
469
554
|
function registerGenerateCommand(program2) {
|
|
470
|
-
program2.command("generate").description("Generate release notes for a tag").requiredOption("--tag <tag>", "Git tag
|
|
555
|
+
program2.command("generate").description("Generate release notes for a tag").requiredOption("--tag <tag>", "Git tag (e.g., v1.0.0 or mobile-v1.2.0)").option("--publish", "Publish release to provider", false).option("--dry-run", "Preview without publishing", false).option("--format <format>", "Output format (markdown|json)", "markdown").option("--config <path>", "Config file path", ".releasejet.yml").option("--debug", "Show debug information", false).addHelpText("after", `
|
|
556
|
+
Examples:
|
|
557
|
+
$ releasejet generate --tag v1.0.0 Preview release notes
|
|
558
|
+
$ releasejet generate --tag mobile-v2.1.0 Multi-client tag
|
|
559
|
+
$ releasejet generate --tag v1.0.0 --publish Publish to provider
|
|
560
|
+
$ releasejet generate --tag v1.0.0 --format json JSON output
|
|
561
|
+
|
|
562
|
+
Tag format:
|
|
563
|
+
Multi-client: <prefix>-v<semver> (e.g., mobile-v1.2.0)
|
|
564
|
+
Single-client: v<semver> (e.g., v1.2.0)
|
|
565
|
+
`).action(withErrorHandler(async (options) => {
|
|
471
566
|
await runGenerate(options);
|
|
472
|
-
});
|
|
567
|
+
}));
|
|
473
568
|
}
|
|
474
569
|
async function runGenerate(options) {
|
|
475
|
-
const debug = options.debug
|
|
476
|
-
};
|
|
570
|
+
const { debug } = createLogger(options.debug ?? false);
|
|
571
|
+
const spinner = options.debug ? null : ora({ stream: process.stderr });
|
|
477
572
|
const config = await loadConfig(options.config);
|
|
478
573
|
debug("Config loaded:", JSON.stringify(config, null, 2));
|
|
479
574
|
const remoteUrl = process.env.CI_SERVER_URL || process.env.GITHUB_SERVER_URL ? "" : getRemoteUrl();
|
|
@@ -485,7 +580,15 @@ async function runGenerate(options) {
|
|
|
485
580
|
const client = createClient(config, token);
|
|
486
581
|
const currentParsed = parseTag(options.tag);
|
|
487
582
|
debug("Parsed tag:", JSON.stringify(currentParsed));
|
|
488
|
-
|
|
583
|
+
let apiTags;
|
|
584
|
+
try {
|
|
585
|
+
spinner?.start("Fetching tags...");
|
|
586
|
+
apiTags = await client.listTags(projectPath);
|
|
587
|
+
spinner?.succeed(`Fetched ${apiTags.length} tags`);
|
|
588
|
+
} catch (err) {
|
|
589
|
+
spinner?.fail("Failed to fetch tags");
|
|
590
|
+
throw err;
|
|
591
|
+
}
|
|
489
592
|
debug("All remote tags:", apiTags.map((t) => `${t.name} (${t.createdAt})`).join(", "));
|
|
490
593
|
const allTags = apiTags.map((t) => {
|
|
491
594
|
try {
|
|
@@ -505,14 +608,24 @@ async function runGenerate(options) {
|
|
|
505
608
|
const previousTag = findPreviousTag(allTags, currentTag);
|
|
506
609
|
debug("Previous tag:", previousTag ? JSON.stringify(previousTag) : "none (first release)");
|
|
507
610
|
debug("Date range:", previousTag?.createdAt ?? "beginning", "->", currentTag.createdAt);
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
611
|
+
const sourceLabel = config.source === "pull_requests" ? "pull requests" : "issues";
|
|
612
|
+
let issues;
|
|
613
|
+
try {
|
|
614
|
+
spinner?.start(`Collecting ${sourceLabel}...`);
|
|
615
|
+
issues = await collectIssues(
|
|
616
|
+
client,
|
|
617
|
+
projectPath,
|
|
618
|
+
currentTag,
|
|
619
|
+
previousTag,
|
|
620
|
+
config,
|
|
621
|
+
debug
|
|
622
|
+
);
|
|
623
|
+
const issueCount = Object.values(issues.categorized).reduce((sum, arr) => sum + arr.length, 0) + issues.uncategorized.length;
|
|
624
|
+
spinner?.succeed(`Collected ${issueCount} ${sourceLabel}`);
|
|
625
|
+
} catch (err) {
|
|
626
|
+
spinner?.fail(`Failed to collect ${sourceLabel}`);
|
|
627
|
+
throw err;
|
|
628
|
+
}
|
|
516
629
|
if (issues.uncategorized.length > 0) {
|
|
517
630
|
if (process.stdin.isTTY) {
|
|
518
631
|
await promptForUncategorized(issues, config);
|
|
@@ -548,37 +661,63 @@ async function runGenerate(options) {
|
|
|
548
661
|
console.log(markdown);
|
|
549
662
|
if (options.publish && !options.dryRun) {
|
|
550
663
|
const releaseName = currentParsed.prefix ? `${currentParsed.prefix.toUpperCase()} v${currentParsed.version}` : `v${currentParsed.version}`;
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
664
|
+
try {
|
|
665
|
+
spinner?.start("Publishing release...");
|
|
666
|
+
await client.createRelease(projectPath, {
|
|
667
|
+
tagName: options.tag,
|
|
668
|
+
name: releaseName,
|
|
669
|
+
description: markdown,
|
|
670
|
+
milestones: milestone ? [milestone] : void 0
|
|
671
|
+
});
|
|
672
|
+
spinner?.succeed(`Release published for ${options.tag}`);
|
|
673
|
+
} catch (err) {
|
|
674
|
+
spinner?.fail("Failed to publish release");
|
|
675
|
+
throw err;
|
|
676
|
+
}
|
|
559
677
|
}
|
|
560
678
|
}
|
|
561
679
|
}
|
|
562
680
|
|
|
563
681
|
// src/cli/commands/validate.ts
|
|
682
|
+
import ora2 from "ora";
|
|
564
683
|
function registerValidateCommand(program2) {
|
|
565
|
-
program2.command("validate").description("Check open issues for proper labeling").option("--config <path>", "Config file path", ".releasejet.yml").
|
|
684
|
+
program2.command("validate").description("Check open issues for proper labeling").option("--config <path>", "Config file path", ".releasejet.yml").option("--debug", "Show debug information", false).addHelpText("after", `
|
|
685
|
+
Examples:
|
|
686
|
+
$ releasejet validate Check with default config
|
|
687
|
+
$ releasejet validate --config my.yml Check with custom config
|
|
688
|
+
`).action(withErrorHandler(async (options) => {
|
|
566
689
|
await runValidate(options);
|
|
567
|
-
});
|
|
690
|
+
}));
|
|
568
691
|
}
|
|
569
692
|
async function runValidate(options) {
|
|
693
|
+
const { debug } = createLogger(options.debug ?? false);
|
|
694
|
+
const spinner = options.debug ? null : ora2({ stream: process.stderr });
|
|
570
695
|
const config = await loadConfig(options.config);
|
|
696
|
+
debug("Config loaded:", JSON.stringify(config, null, 2));
|
|
571
697
|
const remoteUrl = getRemoteUrl();
|
|
572
698
|
const hostUrl = config.provider.url || resolveHostUrl(remoteUrl);
|
|
573
699
|
const projectPath = resolveProjectPath(remoteUrl);
|
|
700
|
+
debug("Host URL:", hostUrl);
|
|
701
|
+
debug("Project path:", projectPath);
|
|
574
702
|
const token = await resolveToken(config.provider.type);
|
|
575
703
|
const client = createClient(config, token);
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
704
|
+
let issues;
|
|
705
|
+
try {
|
|
706
|
+
spinner?.start("Fetching open issues...");
|
|
707
|
+
issues = await client.listIssues(projectPath, {
|
|
708
|
+
state: "opened"
|
|
709
|
+
});
|
|
710
|
+
spinner?.succeed(`Fetched ${issues.length} open issues`);
|
|
711
|
+
} catch (err) {
|
|
712
|
+
spinner?.fail("Failed to fetch issues");
|
|
713
|
+
throw err;
|
|
714
|
+
}
|
|
715
|
+
debug("Fetched", issues.length, "open issues");
|
|
579
716
|
const categoryLabels = Object.keys(config.categories);
|
|
580
717
|
const clientLabels = config.clients.map((c) => c.label);
|
|
581
718
|
const isMultiClient = clientLabels.length > 0;
|
|
719
|
+
debug("Category labels:", categoryLabels);
|
|
720
|
+
debug("Client labels:", clientLabels.length > 0 ? clientLabels : "none (single-client)");
|
|
582
721
|
const problems = [];
|
|
583
722
|
for (const issue of issues) {
|
|
584
723
|
const missing = [];
|
|
@@ -589,6 +728,7 @@ async function runValidate(options) {
|
|
|
589
728
|
missing.push("category label");
|
|
590
729
|
}
|
|
591
730
|
if (missing.length > 0) {
|
|
731
|
+
debug(` #${issue.number} "${issue.title}" labels=[${issue.labels.join(", ")}] missing=[${missing.join(", ")}]`);
|
|
592
732
|
problems.push({ number: issue.number, title: issue.title, missing });
|
|
593
733
|
}
|
|
594
734
|
}
|
|
@@ -677,9 +817,12 @@ jobs:
|
|
|
677
817
|
RELEASEJET_TOKEN: \${{ secrets.RELEASEJET_TOKEN }}
|
|
678
818
|
`;
|
|
679
819
|
function registerInitCommand(program2) {
|
|
680
|
-
program2.command("init").description("Interactive setup for ReleaseJet").
|
|
820
|
+
program2.command("init").description("Interactive setup for ReleaseJet").addHelpText("after", `
|
|
821
|
+
Examples:
|
|
822
|
+
$ releasejet init Run the interactive setup wizard
|
|
823
|
+
`).action(withErrorHandler(async () => {
|
|
681
824
|
await runInit();
|
|
682
|
-
});
|
|
825
|
+
}));
|
|
683
826
|
}
|
|
684
827
|
async function runInit() {
|
|
685
828
|
console.log("\u{1F680} ReleaseJet Setup\n");
|
|
@@ -901,22 +1044,32 @@ import { readFile as readFile4, writeFile as writeFile2, unlink } from "fs/promi
|
|
|
901
1044
|
import { input as input2 } from "@inquirer/prompts";
|
|
902
1045
|
var CI_FILE = ".gitlab-ci.yml";
|
|
903
1046
|
function registerCiCommand(program2) {
|
|
904
|
-
const ci = program2.command("ci").description("Manage GitLab CI/CD integration")
|
|
905
|
-
|
|
1047
|
+
const ci = program2.command("ci").description("Manage GitLab CI/CD integration").addHelpText("after", `
|
|
1048
|
+
Examples:
|
|
1049
|
+
$ releasejet ci enable Interactive setup
|
|
1050
|
+
$ releasejet ci enable --tags ci,docker Non-interactive with tags
|
|
1051
|
+
$ releasejet ci disable Remove CI configuration
|
|
1052
|
+
`);
|
|
1053
|
+
ci.command("enable").description("Add ReleaseJet CI configuration to .gitlab-ci.yml").option("--tags <tags>", "Runner tags (comma-separated)").option("--debug", "Show debug information", false).action(withErrorHandler(async (options) => {
|
|
906
1054
|
await runCiEnable(options);
|
|
907
|
-
});
|
|
908
|
-
ci.command("disable").description("Remove ReleaseJet CI configuration from .gitlab-ci.yml").action(async () => {
|
|
1055
|
+
}));
|
|
1056
|
+
ci.command("disable").description("Remove ReleaseJet CI configuration from .gitlab-ci.yml").action(withErrorHandler(async () => {
|
|
909
1057
|
await runCiDisable();
|
|
910
|
-
});
|
|
1058
|
+
}));
|
|
911
1059
|
}
|
|
912
1060
|
async function runCiEnable(options) {
|
|
1061
|
+
const { debug } = createLogger(options.debug ?? false);
|
|
913
1062
|
let existing = "";
|
|
914
1063
|
try {
|
|
915
1064
|
existing = await readFile4(CI_FILE, "utf-8");
|
|
1065
|
+
debug("Existing .gitlab-ci.yml found, length:", existing.length);
|
|
916
1066
|
} catch (err) {
|
|
917
1067
|
if (err.code !== "ENOENT") throw err;
|
|
1068
|
+
debug(".gitlab-ci.yml not found, will create new file");
|
|
918
1069
|
}
|
|
919
|
-
|
|
1070
|
+
const hasMarkers = hasCiBlock(existing);
|
|
1071
|
+
debug("ReleaseJet markers found:", hasMarkers);
|
|
1072
|
+
if (hasMarkers) {
|
|
920
1073
|
console.log("ReleaseJet CI is already enabled.");
|
|
921
1074
|
return;
|
|
922
1075
|
}
|
|
@@ -930,6 +1083,7 @@ async function runCiEnable(options) {
|
|
|
930
1083
|
tags = tagsInput.trim() ? tagsInput.split(",").map((t) => t.trim()).filter(Boolean) : DEFAULT_TAGS;
|
|
931
1084
|
}
|
|
932
1085
|
const block = generateCiBlock(tags);
|
|
1086
|
+
debug("Generated CI block:\n" + block);
|
|
933
1087
|
const content = appendCiBlock(existing, block);
|
|
934
1088
|
await writeFile2(CI_FILE, content);
|
|
935
1089
|
console.log("\u2713 ReleaseJet CI configuration added to .gitlab-ci.yml");
|
|
@@ -959,7 +1113,7 @@ async function runCiDisable() {
|
|
|
959
1113
|
|
|
960
1114
|
// src/cli/index.ts
|
|
961
1115
|
var program = new Command();
|
|
962
|
-
program.name("releasejet").description("Automated
|
|
1116
|
+
program.name("releasejet").description("Automated release notes generator for GitLab and GitHub").version("1.0.2");
|
|
963
1117
|
registerGenerateCommand(program);
|
|
964
1118
|
registerValidateCommand(program);
|
|
965
1119
|
registerInitCommand(program);
|
package/package.json
CHANGED
|
@@ -1,59 +1,60 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@makispps/releasejet",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Automated release notes generator for GitLab and GitHub",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Mavroudis Papas",
|
|
7
|
-
"homepage": "https://www.releasejet.dev/",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/makisp/releasejet.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/makisp/releasejet/issues"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"release-notes",
|
|
17
|
-
"changelog",
|
|
18
|
-
"gitlab",
|
|
19
|
-
"github",
|
|
20
|
-
"cli",
|
|
21
|
-
"automation",
|
|
22
|
-
"ci-cd"
|
|
23
|
-
],
|
|
24
|
-
"type": "module",
|
|
25
|
-
"bin": {
|
|
26
|
-
"releasejet": "./dist/cli.js"
|
|
27
|
-
},
|
|
28
|
-
"files": [
|
|
29
|
-
"dist",
|
|
30
|
-
"ci",
|
|
31
|
-
".releasejet.example.yml"
|
|
32
|
-
],
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "tsup",
|
|
35
|
-
"test": "vitest run",
|
|
36
|
-
"test:watch": "vitest",
|
|
37
|
-
"dev": "tsx src/cli/index.ts",
|
|
38
|
-
"prepublishOnly": "npm run test && npm run build"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"@gitbeaker/rest": "^41.3.0",
|
|
42
|
-
"@inquirer/prompts": "^7.2.0",
|
|
43
|
-
"@octokit/rest": "^22.0.1",
|
|
44
|
-
"commander": "^13.1.0",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"@types/
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@makispps/releasejet",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Automated release notes generator for GitLab and GitHub",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Mavroudis Papas",
|
|
7
|
+
"homepage": "https://www.releasejet.dev/",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/makisp/releasejet.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/makisp/releasejet/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"release-notes",
|
|
17
|
+
"changelog",
|
|
18
|
+
"gitlab",
|
|
19
|
+
"github",
|
|
20
|
+
"cli",
|
|
21
|
+
"automation",
|
|
22
|
+
"ci-cd"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"bin": {
|
|
26
|
+
"releasejet": "./dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"ci",
|
|
31
|
+
".releasejet.example.yml"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest",
|
|
37
|
+
"dev": "tsx src/cli/index.ts",
|
|
38
|
+
"prepublishOnly": "npm run test && npm run build"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@gitbeaker/rest": "^41.3.0",
|
|
42
|
+
"@inquirer/prompts": "^7.2.0",
|
|
43
|
+
"@octokit/rest": "^22.0.1",
|
|
44
|
+
"commander": "^13.1.0",
|
|
45
|
+
"ora": "^9.3.0",
|
|
46
|
+
"semver": "^7.7.1",
|
|
47
|
+
"yaml": "^2.7.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^25.5.2",
|
|
51
|
+
"@types/semver": "^7.5.8",
|
|
52
|
+
"tsup": "^8.4.0",
|
|
53
|
+
"tsx": "^4.19.0",
|
|
54
|
+
"typescript": "^5.7.0",
|
|
55
|
+
"vitest": "^3.1.0"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20"
|
|
59
|
+
}
|
|
60
|
+
}
|