deploylog 0.1.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/dist/api.d.ts +32 -0
- package/dist/api.js +43 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +26 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +169 -0
- package/dist/project-config.d.ts +10 -0
- package/dist/project-config.js +25 -0
- package/package.json +33 -0
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
code: string;
|
|
4
|
+
constructor(status: number, code: string, message: string);
|
|
5
|
+
}
|
|
6
|
+
export interface Project {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
slug: string;
|
|
10
|
+
website_url: string | null;
|
|
11
|
+
created_at: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Entry {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
slug: string;
|
|
17
|
+
entry_type: string | null;
|
|
18
|
+
version: string | null;
|
|
19
|
+
published: boolean;
|
|
20
|
+
published_at: string | null;
|
|
21
|
+
created_at: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function listProjects(): Promise<Project[]>;
|
|
24
|
+
export declare function listEntries(projectSlug: string): Promise<Entry[]>;
|
|
25
|
+
export interface CreateEntryInput {
|
|
26
|
+
title: string;
|
|
27
|
+
body_markdown: string;
|
|
28
|
+
entry_type?: string | null;
|
|
29
|
+
version?: string;
|
|
30
|
+
publish?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare function createEntry(projectSlug: string, input: CreateEntryInput): Promise<Entry>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getApiKey, getApiUrl } from './config.js';
|
|
2
|
+
export class ApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
constructor(status, code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = 'ApiError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function request(path, options = {}) {
|
|
13
|
+
const apiKey = getApiKey();
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
throw new Error('Not authenticated. Run `deploylog login` first.');
|
|
16
|
+
}
|
|
17
|
+
const url = `${getApiUrl()}/api/cli${path}`;
|
|
18
|
+
const res = await fetch(url, {
|
|
19
|
+
...options,
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
Authorization: `Bearer ${apiKey}`,
|
|
23
|
+
...options.headers,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
const json = await res.json();
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
throw new ApiError(res.status, json.error?.code ?? 'UNKNOWN', json.error?.message ?? `Request failed (${res.status})`);
|
|
29
|
+
}
|
|
30
|
+
return json.data;
|
|
31
|
+
}
|
|
32
|
+
export async function listProjects() {
|
|
33
|
+
return request('/projects');
|
|
34
|
+
}
|
|
35
|
+
export async function listEntries(projectSlug) {
|
|
36
|
+
return request(`/projects/${projectSlug}/entries`);
|
|
37
|
+
}
|
|
38
|
+
export async function createEntry(projectSlug, input) {
|
|
39
|
+
return request(`/projects/${projectSlug}/entries`, {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
body: JSON.stringify(input),
|
|
42
|
+
});
|
|
43
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function getApiKey(): string | undefined;
|
|
2
|
+
export declare function setApiKey(key: string): void;
|
|
3
|
+
export declare function getApiUrl(): string;
|
|
4
|
+
export declare function setApiUrl(url: string): void;
|
|
5
|
+
export declare function clearConfig(): void;
|
|
6
|
+
export declare function getConfigPath(): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
const config = new Conf({
|
|
3
|
+
projectName: 'deploylog',
|
|
4
|
+
schema: {
|
|
5
|
+
apiKey: { type: 'string' },
|
|
6
|
+
apiUrl: { type: 'string', default: 'https://deploylog.dev' },
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
export function getApiKey() {
|
|
10
|
+
return config.get('apiKey');
|
|
11
|
+
}
|
|
12
|
+
export function setApiKey(key) {
|
|
13
|
+
config.set('apiKey', key);
|
|
14
|
+
}
|
|
15
|
+
export function getApiUrl() {
|
|
16
|
+
return config.get('apiUrl') ?? 'https://deploylog.dev';
|
|
17
|
+
}
|
|
18
|
+
export function setApiUrl(url) {
|
|
19
|
+
config.set('apiUrl', url);
|
|
20
|
+
}
|
|
21
|
+
export function clearConfig() {
|
|
22
|
+
config.clear();
|
|
23
|
+
}
|
|
24
|
+
export function getConfigPath() {
|
|
25
|
+
return config.path;
|
|
26
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { setApiKey, setApiUrl, getConfigPath, clearConfig } from './config.js';
|
|
5
|
+
import { listProjects, listEntries, createEntry, ApiError } from './api.js';
|
|
6
|
+
import { readProjectConfig } from './project-config.js';
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('deploylog')
|
|
10
|
+
.description('Push changelog entries from the terminal')
|
|
11
|
+
.version('0.1.0');
|
|
12
|
+
// ─── login ──────────────────────────────────────────────────────────────────
|
|
13
|
+
program
|
|
14
|
+
.command('login')
|
|
15
|
+
.description('Authenticate with an API key')
|
|
16
|
+
.option('--key <key>', 'API key (starts with dk_)')
|
|
17
|
+
.option('--api-url <url>', 'API base URL (default: https://deploylog.dev)')
|
|
18
|
+
.action(async (opts) => {
|
|
19
|
+
if (opts.apiUrl) {
|
|
20
|
+
setApiUrl(opts.apiUrl);
|
|
21
|
+
}
|
|
22
|
+
if (opts.key) {
|
|
23
|
+
if (!opts.key.startsWith('dk_')) {
|
|
24
|
+
console.error(chalk.red('Invalid API key. Keys start with dk_'));
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
setApiKey(opts.key);
|
|
28
|
+
console.log(chalk.green('Authenticated successfully.'));
|
|
29
|
+
console.log(chalk.dim(`Config saved to ${getConfigPath()}`));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Interactive: prompt for key
|
|
33
|
+
const { createInterface } = await import('node:readline');
|
|
34
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
35
|
+
const key = await new Promise((resolve) => {
|
|
36
|
+
rl.question('Enter your API key (from Dashboard → API Keys): ', resolve);
|
|
37
|
+
});
|
|
38
|
+
rl.close();
|
|
39
|
+
const trimmed = key.trim();
|
|
40
|
+
if (!trimmed.startsWith('dk_')) {
|
|
41
|
+
console.error(chalk.red('Invalid API key. Keys start with dk_'));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
setApiKey(trimmed);
|
|
45
|
+
console.log(chalk.green('Authenticated successfully.'));
|
|
46
|
+
console.log(chalk.dim(`Config saved to ${getConfigPath()}`));
|
|
47
|
+
});
|
|
48
|
+
// ─── logout ─────────────────────────────────────────────────────────────────
|
|
49
|
+
program
|
|
50
|
+
.command('logout')
|
|
51
|
+
.description('Remove stored credentials')
|
|
52
|
+
.action(() => {
|
|
53
|
+
clearConfig();
|
|
54
|
+
console.log(chalk.green('Logged out. Credentials removed.'));
|
|
55
|
+
});
|
|
56
|
+
// ─── projects ───────────────────────────────────────────────────────────────
|
|
57
|
+
program
|
|
58
|
+
.command('projects')
|
|
59
|
+
.description('List projects in your organization')
|
|
60
|
+
.action(async () => {
|
|
61
|
+
try {
|
|
62
|
+
const projects = await listProjects();
|
|
63
|
+
if (projects.length === 0) {
|
|
64
|
+
console.log(chalk.dim('No projects found.'));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log(chalk.bold('Projects:\n'));
|
|
68
|
+
for (const p of projects) {
|
|
69
|
+
console.log(` ${chalk.cyan(p.name)} ${chalk.dim(p.slug)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
handleError(err);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// ─── list ───────────────────────────────────────────────────────────────────
|
|
77
|
+
program
|
|
78
|
+
.command('list')
|
|
79
|
+
.description('List recent entries for a project')
|
|
80
|
+
.option('-p, --project <slug>', 'Project slug (or set in .deploylog.yml)')
|
|
81
|
+
.action(async (opts) => {
|
|
82
|
+
try {
|
|
83
|
+
const slug = resolveProject(opts.project);
|
|
84
|
+
const entries = await listEntries(slug);
|
|
85
|
+
if (entries.length === 0) {
|
|
86
|
+
console.log(chalk.dim('No entries found.'));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
console.log(chalk.bold(`Entries for ${slug}:\n`));
|
|
90
|
+
for (const e of entries) {
|
|
91
|
+
const status = e.published
|
|
92
|
+
? chalk.green('published')
|
|
93
|
+
: chalk.yellow('draft');
|
|
94
|
+
const type = e.entry_type ? chalk.dim(`[${e.entry_type}]`) : '';
|
|
95
|
+
const version = e.version ? chalk.dim(`v${e.version}`) : '';
|
|
96
|
+
const date = new Date(e.created_at).toLocaleDateString('en-US', {
|
|
97
|
+
month: 'short',
|
|
98
|
+
day: 'numeric',
|
|
99
|
+
});
|
|
100
|
+
console.log(` ${status} ${e.title} ${type} ${version} ${chalk.dim(date)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
handleError(err);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// ─── push ───────────────────────────────────────────────────────────────────
|
|
108
|
+
program
|
|
109
|
+
.command('push')
|
|
110
|
+
.description('Create a new changelog entry')
|
|
111
|
+
.requiredOption('-t, --title <title>', 'Entry title')
|
|
112
|
+
.requiredOption('-b, --body <markdown>', 'Entry body (Markdown)')
|
|
113
|
+
.option('-p, --project <slug>', 'Project slug (or set in .deploylog.yml)')
|
|
114
|
+
.option('--type <type>', 'Entry type: feature, fix, improvement, breaking, announcement')
|
|
115
|
+
.option('--version <version>', 'Semver version (e.g. 1.2.3)')
|
|
116
|
+
.option('--publish', 'Publish immediately (default: draft)')
|
|
117
|
+
.option('--draft', 'Save as draft (default)')
|
|
118
|
+
.action(async (opts) => {
|
|
119
|
+
try {
|
|
120
|
+
const slug = resolveProject(opts.project);
|
|
121
|
+
const projectConfig = readProjectConfig();
|
|
122
|
+
const entry = await createEntry(slug, {
|
|
123
|
+
title: opts.title,
|
|
124
|
+
body_markdown: opts.body,
|
|
125
|
+
entry_type: opts.type ?? projectConfig?.default_type ?? null,
|
|
126
|
+
version: opts.version,
|
|
127
|
+
publish: opts.publish && !opts.draft,
|
|
128
|
+
});
|
|
129
|
+
const status = entry.published
|
|
130
|
+
? chalk.green('Published')
|
|
131
|
+
: chalk.yellow('Draft');
|
|
132
|
+
console.log(`\n${chalk.green('✓')} Entry created: ${chalk.bold(entry.title)}`);
|
|
133
|
+
console.log(` Status: ${status}`);
|
|
134
|
+
console.log(` Slug: ${chalk.dim(entry.slug)}`);
|
|
135
|
+
if (entry.version)
|
|
136
|
+
console.log(` Version: ${chalk.dim(`v${entry.version}`)}`);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
handleError(err);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// ─── helpers ────────────────────────────────────────────────────────────────
|
|
143
|
+
function resolveProject(cliArg) {
|
|
144
|
+
if (cliArg)
|
|
145
|
+
return cliArg;
|
|
146
|
+
const config = readProjectConfig();
|
|
147
|
+
if (config?.project)
|
|
148
|
+
return config.project;
|
|
149
|
+
console.error(chalk.red('No project specified.'));
|
|
150
|
+
console.error('Use --project <slug> or create a .deploylog.yml with:');
|
|
151
|
+
console.error(chalk.dim(' project: my-app'));
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
function handleError(err) {
|
|
155
|
+
if (err instanceof ApiError) {
|
|
156
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
157
|
+
if (err.status === 401) {
|
|
158
|
+
console.error(chalk.dim('Run `deploylog login` to authenticate.'));
|
|
159
|
+
}
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
if (err instanceof Error) {
|
|
163
|
+
console.error(chalk.red(err.message));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
console.error(chalk.red('An unknown error occurred'));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
program.parse();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface ProjectConfig {
|
|
2
|
+
project?: string;
|
|
3
|
+
default_type?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Read .deploylog.yml from the current directory (or parents).
|
|
7
|
+
* Returns null if not found.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readProjectConfig(): ProjectConfig | null;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
/**
|
|
5
|
+
* Read .deploylog.yml from the current directory (or parents).
|
|
6
|
+
* Returns null if not found.
|
|
7
|
+
*/
|
|
8
|
+
export function readProjectConfig() {
|
|
9
|
+
let dir = process.cwd();
|
|
10
|
+
while (true) {
|
|
11
|
+
const filePath = resolve(dir, '.deploylog.yml');
|
|
12
|
+
try {
|
|
13
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
14
|
+
return parse(content);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// File not found, try parent
|
|
18
|
+
}
|
|
19
|
+
const parent = resolve(dir, '..');
|
|
20
|
+
if (parent === dir)
|
|
21
|
+
break;
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "deploylog",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Push changelog entries from the terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"deploylog": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["dist"],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"prepublishOnly": "tsc",
|
|
14
|
+
"start": "node dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": ["changelog", "deploylog", "cli", "release-notes", "devtools"],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/Idzuo32/deploylog-cli.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://deploylog.dev",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"chalk": "^5.4.1",
|
|
25
|
+
"commander": "^13.1.0",
|
|
26
|
+
"conf": "^13.1.0",
|
|
27
|
+
"yaml": "^2.7.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.15.3",
|
|
31
|
+
"typescript": "^5.8.3"
|
|
32
|
+
}
|
|
33
|
+
}
|