deploylog 0.2.0 → 0.2.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/README.md +138 -0
- package/dist/api.js +17 -3
- package/dist/config.js +4 -2
- package/dist/index.js +22 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Idzuo32/deploylog-cli/main/.github/assets/logo.png" width="120" alt="DeployLog" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">deploylog</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Push changelog entries from the terminal. Generate release notes from git with one flag. Rewrite them with Claude Haiku with another.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/deploylog"><img src="https://img.shields.io/npm/v/deploylog.svg" alt="npm"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/deploylog"><img src="https://img.shields.io/npm/dm/deploylog.svg" alt="downloads"></a>
|
|
14
|
+
<img src="https://img.shields.io/node/v/deploylog.svg" alt="node">
|
|
15
|
+
<img src="https://img.shields.io/npm/l/deploylog.svg" alt="license">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i -g deploylog
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Node 18+ required.
|
|
27
|
+
|
|
28
|
+
## Authenticate
|
|
29
|
+
|
|
30
|
+
Create an API key in your dashboard at [deploylog.dev/dashboard/api-keys](https://deploylog.dev/dashboard/api-keys), then:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
deploylog login --key dk_xxx
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Credentials are stored with [`conf`](https://github.com/sindresorhus/conf) in your OS's standard config directory.
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# List your projects
|
|
42
|
+
deploylog projects
|
|
43
|
+
|
|
44
|
+
# Publish an entry
|
|
45
|
+
deploylog push \
|
|
46
|
+
--project my-app \
|
|
47
|
+
--title "Dark mode" \
|
|
48
|
+
--body "Auto-detects system preference." \
|
|
49
|
+
--type feature \
|
|
50
|
+
--version 1.4.0 \
|
|
51
|
+
--publish
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Project config
|
|
55
|
+
|
|
56
|
+
Create a `.deploylog.yml` at your repo root so you don't have to pass `--project` every time:
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
project: my-app
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Commands
|
|
63
|
+
|
|
64
|
+
### `deploylog login`
|
|
65
|
+
|
|
66
|
+
Authenticate with an API key.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
--key <key> API key (starts with dk_)
|
|
70
|
+
--api-url <url> API base URL (default: https://deploylog.dev)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `deploylog logout`
|
|
74
|
+
|
|
75
|
+
Remove stored credentials.
|
|
76
|
+
|
|
77
|
+
### `deploylog projects`
|
|
78
|
+
|
|
79
|
+
List projects in your organization.
|
|
80
|
+
|
|
81
|
+
### `deploylog list`
|
|
82
|
+
|
|
83
|
+
List recent entries for a project.
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
-p, --project <slug> Project slug (or set in .deploylog.yml)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `deploylog push`
|
|
90
|
+
|
|
91
|
+
Create a new changelog entry.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
-t, --title <title> Entry title
|
|
95
|
+
-b, --body <markdown> Entry body (Markdown)
|
|
96
|
+
-p, --project <slug> Project slug (or set in .deploylog.yml)
|
|
97
|
+
--type <type> feature | fix | improvement | breaking | announcement
|
|
98
|
+
--version <version> Semver (e.g. 1.2.3)
|
|
99
|
+
--publish Publish immediately
|
|
100
|
+
--draft Save as draft (default)
|
|
101
|
+
--from-git Derive title/body from commits since the last tag
|
|
102
|
+
--ai-summarize Rewrite the entry with Claude Haiku
|
|
103
|
+
-y, --yes Skip interactive confirmation for AI-generated content
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Recipes
|
|
107
|
+
|
|
108
|
+
**Draft from recent commits:**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
deploylog push --from-git
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Collects commits since the last git tag, formats them as a Markdown list, and opens the entry as a draft.
|
|
115
|
+
|
|
116
|
+
**AI-polished release notes:**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
deploylog push --from-git --ai-summarize --version 1.4.0 --publish
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
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.
|
|
123
|
+
|
|
124
|
+
**CI / GitHub Actions:**
|
|
125
|
+
|
|
126
|
+
For CI workflows, prefer the official Action:
|
|
127
|
+
|
|
128
|
+
- [`deploylogdev/action`](https://github.com/marketplace/actions/deploylog) on the GitHub Marketplace
|
|
129
|
+
|
|
130
|
+
## Related
|
|
131
|
+
|
|
132
|
+
- **Dashboard** — [deploylog.dev](https://deploylog.dev)
|
|
133
|
+
- **Widget** — embeddable changelog widget at `cdn.deploylog.dev`
|
|
134
|
+
- **GitHub Action** — [`deploylogdev/action@v1`](https://github.com/marketplace/actions/deploylog)
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT © DeployLog
|
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
|
@@ -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) {
|
|
@@ -175,11 +189,19 @@ program
|
|
|
175
189
|
return;
|
|
176
190
|
}
|
|
177
191
|
}
|
|
192
|
+
else if (!opts.yes) {
|
|
193
|
+
// Non-interactive shell (CI, piped stdin): there's no prompt to show,
|
|
194
|
+
// so make the unreviewed auto-proceed explicit. (BUG-019)
|
|
195
|
+
console.log(chalk.yellow('Non-interactive shell: proceeding with the AI-generated entry without confirmation.'));
|
|
196
|
+
}
|
|
178
197
|
}
|
|
179
198
|
if (!title || !body) {
|
|
180
199
|
console.error(chalk.red('Entry requires --title and --body (or --from-git / --ai-summarize to derive them).'));
|
|
181
200
|
process.exit(1);
|
|
182
201
|
}
|
|
202
|
+
if (opts.publish && opts.draft) {
|
|
203
|
+
console.log(chalk.yellow('Both --publish and --draft passed; saving as a draft.'));
|
|
204
|
+
}
|
|
183
205
|
const entry = await createEntry(slug, {
|
|
184
206
|
title,
|
|
185
207
|
body_markdown: body,
|