deploylog 0.2.1 → 0.3.0
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/LICENSE +21 -0
- package/README.md +11 -9
- package/dist/api.js +17 -3
- package/dist/config.js +4 -2
- package/dist/index.js +36 -9
- package/package.json +4 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Monolithiq LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/
|
|
2
|
+
<img src="https://raw.githubusercontent.com/marko-builds/deploylog-cli/main/.github/assets/logo.png" width="120" alt="DeployLog" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">deploylog</h1>
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
npm i -g deploylog
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Node 18+ required.
|
|
26
|
+
Node 18+ required. Installs two equivalent commands: `deploylog` and the short alias `dpl`.
|
|
27
27
|
|
|
28
28
|
## Authenticate
|
|
29
29
|
|
|
@@ -94,12 +94,12 @@ Create a new changelog entry.
|
|
|
94
94
|
-t, --title <title> Entry title
|
|
95
95
|
-b, --body <markdown> Entry body (Markdown)
|
|
96
96
|
-p, --project <slug> Project slug (or set in .deploylog.yml)
|
|
97
|
-
--type <type>
|
|
97
|
+
-T, --type <type> feature | fix | improvement | breaking | announcement
|
|
98
98
|
--version <version> Semver (e.g. 1.2.3)
|
|
99
|
-
--publish
|
|
100
|
-
--draft
|
|
101
|
-
--from-git
|
|
102
|
-
--ai-summarize
|
|
99
|
+
-P, --publish Publish immediately
|
|
100
|
+
-D, --draft Save as draft (default)
|
|
101
|
+
-g, --from-git Derive title/body from commits since the last tag (alias: --git)
|
|
102
|
+
-a, --ai-summarize Rewrite the entry with Claude Haiku (alias: --ai)
|
|
103
103
|
-y, --yes Skip interactive confirmation for AI-generated content
|
|
104
104
|
```
|
|
105
105
|
|
|
@@ -117,6 +117,8 @@ Collects commits since the last git tag, formats them as a Markdown list, and op
|
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
119
|
deploylog push --from-git --ai-summarize --version 1.4.0 --publish
|
|
120
|
+
# or, with short flags and the dpl alias:
|
|
121
|
+
dpl push -g -a --version 1.4.0 --publish
|
|
120
122
|
```
|
|
121
123
|
|
|
122
124
|
Uses Claude Haiku to rewrite your raw commits into user-friendly release notes. Free plan includes 5 AI summaries per month; paid plans are unlimited.
|
|
@@ -125,13 +127,13 @@ Uses Claude Haiku to rewrite your raw commits into user-friendly release notes.
|
|
|
125
127
|
|
|
126
128
|
For CI workflows, prefer the official Action:
|
|
127
129
|
|
|
128
|
-
- [`deploylogdev/action`](https://github.com/marketplace/actions/deploylog) on the GitHub Marketplace
|
|
130
|
+
- [`deploylogdev/action`](https://github.com/marketplace/actions/publish-to-deploylog) on the GitHub Marketplace
|
|
129
131
|
|
|
130
132
|
## Related
|
|
131
133
|
|
|
132
134
|
- **Dashboard** — [deploylog.dev](https://deploylog.dev)
|
|
133
135
|
- **Widget** — embeddable changelog widget at `cdn.deploylog.dev`
|
|
134
|
-
- **GitHub Action** — [`deploylogdev/action@v1`](https://github.com/marketplace/actions/deploylog)
|
|
136
|
+
- **GitHub Action** — [`deploylogdev/action@v1`](https://github.com/marketplace/actions/publish-to-deploylog)
|
|
135
137
|
|
|
136
138
|
## License
|
|
137
139
|
|
package/dist/api.js
CHANGED
|
@@ -23,11 +23,25 @@ async function request(path, options = {}) {
|
|
|
23
23
|
...options.headers,
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
|
-
const
|
|
26
|
+
const raw = await res.text();
|
|
27
|
+
let body = null;
|
|
28
|
+
if (raw) {
|
|
29
|
+
try {
|
|
30
|
+
body = JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
body = null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
27
36
|
if (!res.ok) {
|
|
28
|
-
throw new ApiError(res.status,
|
|
37
|
+
throw new ApiError(res.status, body?.error?.code ?? 'UNKNOWN', body?.error?.message ?? `Request failed (${res.status})`);
|
|
38
|
+
}
|
|
39
|
+
// Reject non-JSON bodies and well-formed JSON that's missing `data` — both
|
|
40
|
+
// violate the response contract and would otherwise return undefined.
|
|
41
|
+
if (!body || body.data === undefined) {
|
|
42
|
+
throw new ApiError(res.status, 'INVALID_RESPONSE', `Server returned an unexpected response (${res.status})`);
|
|
29
43
|
}
|
|
30
|
-
return
|
|
44
|
+
return body.data;
|
|
31
45
|
}
|
|
32
46
|
export async function listProjects() {
|
|
33
47
|
return request('/projects');
|
package/dist/config.js
CHANGED
|
@@ -13,10 +13,12 @@ export function setApiKey(key) {
|
|
|
13
13
|
config.set('apiKey', key);
|
|
14
14
|
}
|
|
15
15
|
export function getApiUrl() {
|
|
16
|
-
return config.get('apiUrl') ?? 'https://deploylog.dev';
|
|
16
|
+
return (config.get('apiUrl') ?? 'https://deploylog.dev').replace(/\/+$/, '');
|
|
17
17
|
}
|
|
18
18
|
export function setApiUrl(url) {
|
|
19
|
-
|
|
19
|
+
// Normalize so request building (`${apiUrl}/api/cli${path}`) never produces a
|
|
20
|
+
// double slash from a trailing-slash paste. (BUG-012)
|
|
21
|
+
config.set('apiUrl', url.trim().replace(/\/+$/, ''));
|
|
20
22
|
}
|
|
21
23
|
export function clearConfig() {
|
|
22
24
|
config.clear();
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const program = new Command();
|
|
|
9
9
|
program
|
|
10
10
|
.name('deploylog')
|
|
11
11
|
.description('Push changelog entries from the terminal')
|
|
12
|
-
.version('0.
|
|
12
|
+
.version('0.3.0');
|
|
13
13
|
// ─── login ──────────────────────────────────────────────────────────────────
|
|
14
14
|
program
|
|
15
15
|
.command('login')
|
|
@@ -18,6 +18,20 @@ program
|
|
|
18
18
|
.option('--api-url <url>', 'API base URL (default: https://deploylog.dev)')
|
|
19
19
|
.action(async (opts) => {
|
|
20
20
|
if (opts.apiUrl) {
|
|
21
|
+
let parsed;
|
|
22
|
+
try {
|
|
23
|
+
parsed = new URL(opts.apiUrl.trim());
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.error(chalk.red('Invalid API URL. Provide a valid absolute URL.'));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// Require http(s) and a real host — a scheme-only value like "https://"
|
|
30
|
+
// parses but would break request URL construction.
|
|
31
|
+
if (!/^https?:$/.test(parsed.protocol) || !parsed.hostname) {
|
|
32
|
+
console.error(chalk.red('Invalid API URL. Must use http(s) and include a host.'));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
21
35
|
setApiUrl(opts.apiUrl);
|
|
22
36
|
}
|
|
23
37
|
if (opts.key) {
|
|
@@ -112,15 +126,20 @@ program
|
|
|
112
126
|
.option('-t, --title <title>', 'Entry title (required unless --from-git or --ai-summarize)')
|
|
113
127
|
.option('-b, --body <markdown>', 'Entry body (Markdown)')
|
|
114
128
|
.option('-p, --project <slug>', 'Project slug (or set in .deploylog.yml)')
|
|
115
|
-
.option('--type <type>', 'Entry type: feature, fix, improvement, breaking, announcement')
|
|
129
|
+
.option('-T, --type <type>', 'Entry type: feature, fix, improvement, breaking, announcement')
|
|
116
130
|
.option('--version <version>', 'Semver version (e.g. 1.2.3)')
|
|
117
|
-
.option('--publish', 'Publish immediately (default: draft)')
|
|
118
|
-
.option('--draft', 'Save as draft (default)')
|
|
119
|
-
.option('--from-git', 'Derive title/body from commits since the last tag')
|
|
120
|
-
.option('--
|
|
131
|
+
.option('-P, --publish', 'Publish immediately (default: draft)')
|
|
132
|
+
.option('-D, --draft', 'Save as draft (default)')
|
|
133
|
+
.option('-g, --from-git', 'Derive title/body from commits since the last tag')
|
|
134
|
+
.option('--git', 'Alias of --from-git')
|
|
135
|
+
.option('-a, --ai-summarize', 'Rewrite the entry with Claude Haiku (user-friendly release notes)')
|
|
136
|
+
.option('--ai', 'Alias of --ai-summarize')
|
|
121
137
|
.option('-y, --yes', 'Skip interactive confirmation for AI-generated content')
|
|
122
138
|
.action(async (opts) => {
|
|
123
139
|
try {
|
|
140
|
+
// Reconcile each flag with its alias (-g/--git, -a/--ai).
|
|
141
|
+
const fromGit = opts.fromGit || opts.git;
|
|
142
|
+
const aiSummarize = opts.aiSummarize || opts.ai;
|
|
124
143
|
const slug = resolveProject(opts.project);
|
|
125
144
|
const projectConfig = readProjectConfig();
|
|
126
145
|
// Gather source material (commits + version) if --from-git.
|
|
@@ -128,7 +147,7 @@ program
|
|
|
128
147
|
let gitVersion = null;
|
|
129
148
|
let gitTitle = null;
|
|
130
149
|
let gitBody = null;
|
|
131
|
-
if (
|
|
150
|
+
if (fromGit) {
|
|
132
151
|
if (!isGitRepo()) {
|
|
133
152
|
console.error(chalk.red('Not in a git repository. Remove --from-git or cd to a repo.'));
|
|
134
153
|
process.exit(1);
|
|
@@ -138,7 +157,7 @@ program
|
|
|
138
157
|
gitVersion = getHeadVersion();
|
|
139
158
|
gitTitle = defaultTitleFromGit(gitVersion, lastTag);
|
|
140
159
|
gitBody = formatCommitsAsMarkdown(commits);
|
|
141
|
-
if (commits.length === 0 && !opts.body && !
|
|
160
|
+
if (commits.length === 0 && !opts.body && !aiSummarize) {
|
|
142
161
|
console.error(chalk.yellow(lastTag
|
|
143
162
|
? `No commits since tag ${lastTag}. Nothing to summarize.`
|
|
144
163
|
: 'No commits found on HEAD.'));
|
|
@@ -150,7 +169,7 @@ program
|
|
|
150
169
|
let body = opts.body ?? gitBody ?? '';
|
|
151
170
|
let entryType = opts.type ?? projectConfig?.default_type ?? null;
|
|
152
171
|
const version = opts.version ?? gitVersion ?? undefined;
|
|
153
|
-
if (
|
|
172
|
+
if (aiSummarize) {
|
|
154
173
|
const hasSource = commits.length > 0 || (opts.body && opts.body.trim().length > 0);
|
|
155
174
|
if (!hasSource) {
|
|
156
175
|
console.error(chalk.red('--ai-summarize needs source material. Pass --from-git or provide --body as raw notes.'));
|
|
@@ -175,11 +194,19 @@ program
|
|
|
175
194
|
return;
|
|
176
195
|
}
|
|
177
196
|
}
|
|
197
|
+
else if (!opts.yes) {
|
|
198
|
+
// Non-interactive shell (CI, piped stdin): there's no prompt to show,
|
|
199
|
+
// so make the unreviewed auto-proceed explicit. (BUG-019)
|
|
200
|
+
console.log(chalk.yellow('Non-interactive shell: proceeding with the AI-generated entry without confirmation.'));
|
|
201
|
+
}
|
|
178
202
|
}
|
|
179
203
|
if (!title || !body) {
|
|
180
204
|
console.error(chalk.red('Entry requires --title and --body (or --from-git / --ai-summarize to derive them).'));
|
|
181
205
|
process.exit(1);
|
|
182
206
|
}
|
|
207
|
+
if (opts.publish && opts.draft) {
|
|
208
|
+
console.log(chalk.yellow('Both --publish and --draft passed; saving as a draft.'));
|
|
209
|
+
}
|
|
183
210
|
const entry = await createEntry(slug, {
|
|
184
211
|
title,
|
|
185
212
|
body_markdown: body,
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deploylog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Push changelog entries from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"deploylog": "./dist/index.js"
|
|
7
|
+
"deploylog": "./dist/index.js",
|
|
8
|
+
"dpl": "./dist/index.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"dist"
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
"license": "MIT",
|
|
28
29
|
"repository": {
|
|
29
30
|
"type": "git",
|
|
30
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/marko-builds/deploylog-cli.git"
|
|
31
32
|
},
|
|
32
33
|
"homepage": "https://deploylog.dev",
|
|
33
34
|
"dependencies": {
|