backlog-exporter 0.1.0 → 0.2.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/README.md +5 -5
- package/dist/commands/all/index.js +13 -2
- package/dist/commands/issue/index.js +7 -1
- package/dist/commands/update/index.js +19 -2
- package/dist/commands/wiki/index.js +6 -1
- package/dist/utils/backlog-api.d.ts +18 -12
- package/dist/utils/backlog-api.js +49 -29
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ $ npm install -g backlog-exporter
|
|
|
59
59
|
$ backlog-exporter COMMAND
|
|
60
60
|
running command...
|
|
61
61
|
$ backlog-exporter (--version)
|
|
62
|
-
backlog-exporter/0.
|
|
62
|
+
backlog-exporter/0.2.0 linux-x64 node-v23.9.0
|
|
63
63
|
$ backlog-exporter --help [COMMAND]
|
|
64
64
|
USAGE
|
|
65
65
|
$ backlog-exporter COMMAND
|
|
@@ -215,7 +215,7 @@ EXAMPLES
|
|
|
215
215
|
指定したディレクトリに課題とWikiを保存する
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
-
_See code: [src/commands/all/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.
|
|
218
|
+
_See code: [src/commands/all/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.2.0/src/commands/all/index.ts)_
|
|
219
219
|
|
|
220
220
|
## `backlog-exporter help [COMMAND]`
|
|
221
221
|
|
|
@@ -262,7 +262,7 @@ EXAMPLES
|
|
|
262
262
|
指定したディレクトリに課題を保存する
|
|
263
263
|
```
|
|
264
264
|
|
|
265
|
-
_See code: [src/commands/issue/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.
|
|
265
|
+
_See code: [src/commands/issue/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.2.0/src/commands/issue/index.ts)_
|
|
266
266
|
|
|
267
267
|
## `backlog-exporter plugins`
|
|
268
268
|
|
|
@@ -591,7 +591,7 @@ EXAMPLES
|
|
|
591
591
|
指定したディレクトリの設定を使用して更新する
|
|
592
592
|
```
|
|
593
593
|
|
|
594
|
-
_See code: [src/commands/update/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.
|
|
594
|
+
_See code: [src/commands/update/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.2.0/src/commands/update/index.ts)_
|
|
595
595
|
|
|
596
596
|
## `backlog-exporter wiki`
|
|
597
597
|
|
|
@@ -618,7 +618,7 @@ EXAMPLES
|
|
|
618
618
|
指定したディレクトリにWikiを保存する
|
|
619
619
|
```
|
|
620
620
|
|
|
621
|
-
_See code: [src/commands/wiki/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.
|
|
621
|
+
_See code: [src/commands/wiki/index.ts](https://github.com/ShuntaToda/backlog-exporter/blob/v0.2.0/src/commands/wiki/index.ts)_
|
|
622
622
|
<!-- commandsstop -->
|
|
623
623
|
|
|
624
624
|
# 出力形式
|
|
@@ -55,7 +55,13 @@ export default class All extends Command {
|
|
|
55
55
|
await createOutputDirectory(wikiOutput);
|
|
56
56
|
// 課題の取得と保存
|
|
57
57
|
this.log('課題の取得を開始します...');
|
|
58
|
-
await downloadIssues(this,
|
|
58
|
+
await downloadIssues(this, {
|
|
59
|
+
apiKey,
|
|
60
|
+
count: 100,
|
|
61
|
+
domain,
|
|
62
|
+
outputDir: issueOutput,
|
|
63
|
+
projectId,
|
|
64
|
+
});
|
|
59
65
|
// 課題フォルダに設定ファイルを保存
|
|
60
66
|
await updateSettings(issueOutput, {
|
|
61
67
|
apiKey,
|
|
@@ -68,7 +74,12 @@ export default class All extends Command {
|
|
|
68
74
|
this.log('課題の取得が完了しました');
|
|
69
75
|
// Wikiの取得と保存
|
|
70
76
|
this.log('Wikiの取得を開始します...');
|
|
71
|
-
await downloadWikis(this,
|
|
77
|
+
await downloadWikis(this, {
|
|
78
|
+
apiKey,
|
|
79
|
+
domain,
|
|
80
|
+
outputDir: wikiOutput,
|
|
81
|
+
projectIdOrKey,
|
|
82
|
+
});
|
|
72
83
|
// Wikiフォルダに設定ファイルを保存
|
|
73
84
|
await updateSettings(wikiOutput, {
|
|
74
85
|
apiKey,
|
|
@@ -47,7 +47,13 @@ export default class Issue extends Command {
|
|
|
47
47
|
const projectId = await validateAndGetProjectId(domain, projectIdOrKey, apiKey);
|
|
48
48
|
this.log(`プロジェクトID: ${projectId} を使用します`);
|
|
49
49
|
// 課題の取得と保存
|
|
50
|
-
await downloadIssues(this,
|
|
50
|
+
await downloadIssues(this, {
|
|
51
|
+
apiKey,
|
|
52
|
+
count: 100,
|
|
53
|
+
domain,
|
|
54
|
+
outputDir,
|
|
55
|
+
projectId,
|
|
56
|
+
});
|
|
51
57
|
// 設定ファイルを保存
|
|
52
58
|
await updateSettings(outputDir, {
|
|
53
59
|
apiKey,
|
|
@@ -207,7 +207,16 @@ export default class Update extends Command {
|
|
|
207
207
|
// 課題の更新
|
|
208
208
|
async updateIssues(options) {
|
|
209
209
|
this.log('課題の更新を開始します...');
|
|
210
|
-
|
|
210
|
+
// 設定ファイルから前回の更新日時を取得
|
|
211
|
+
const { lastUpdated } = await loadSettings(options.targetDir);
|
|
212
|
+
await downloadIssues(this, {
|
|
213
|
+
apiKey: options.apiKey,
|
|
214
|
+
count: 100,
|
|
215
|
+
domain: options.domain,
|
|
216
|
+
lastUpdated,
|
|
217
|
+
outputDir: options.targetDir,
|
|
218
|
+
projectId: options.projectId,
|
|
219
|
+
});
|
|
211
220
|
// 設定ファイルを更新
|
|
212
221
|
await updateSettings(options.targetDir, {
|
|
213
222
|
apiKey: options.apiKey,
|
|
@@ -222,7 +231,15 @@ export default class Update extends Command {
|
|
|
222
231
|
// Wikiの更新
|
|
223
232
|
async updateWikis(options) {
|
|
224
233
|
this.log('Wikiの更新を開始します...');
|
|
225
|
-
|
|
234
|
+
// 設定ファイルから前回の更新日時を取得
|
|
235
|
+
const { lastUpdated } = await loadSettings(options.targetDir);
|
|
236
|
+
await downloadWikis(this, {
|
|
237
|
+
apiKey: options.apiKey,
|
|
238
|
+
domain: options.domain,
|
|
239
|
+
lastUpdated,
|
|
240
|
+
outputDir: options.targetDir,
|
|
241
|
+
projectIdOrKey: options.projectIdOrKey,
|
|
242
|
+
});
|
|
226
243
|
// 設定ファイルを更新
|
|
227
244
|
await updateSettings(options.targetDir, {
|
|
228
245
|
apiKey: options.apiKey,
|
|
@@ -43,7 +43,12 @@ Wikiをダウンロードする
|
|
|
43
43
|
// 出力ディレクトリの作成
|
|
44
44
|
await createOutputDirectory(outputDir);
|
|
45
45
|
// Wikiの取得と保存
|
|
46
|
-
await downloadWikis(this,
|
|
46
|
+
await downloadWikis(this, {
|
|
47
|
+
apiKey,
|
|
48
|
+
domain,
|
|
49
|
+
outputDir,
|
|
50
|
+
projectIdOrKey,
|
|
51
|
+
});
|
|
47
52
|
// 設定ファイルを保存
|
|
48
53
|
await updateSettings(outputDir, {
|
|
49
54
|
apiKey,
|
|
@@ -2,20 +2,26 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
/**
|
|
3
3
|
* Backlogから課題をダウンロードする
|
|
4
4
|
* @param command コマンドインスタンス
|
|
5
|
-
* @param
|
|
6
|
-
* @param projectId プロジェクトID
|
|
7
|
-
* @param apiKey APIキー
|
|
8
|
-
* @param outputDir 出力ディレクトリ
|
|
9
|
-
* @param count 一度に取得する課題数
|
|
10
|
-
* @param statusId ステータスID(オプション)
|
|
5
|
+
* @param options 課題ダウンロードのオプション
|
|
11
6
|
*/
|
|
12
|
-
export declare function downloadIssues(command: Command,
|
|
7
|
+
export declare function downloadIssues(command: Command, options: {
|
|
8
|
+
apiKey: string;
|
|
9
|
+
count: number;
|
|
10
|
+
domain: string;
|
|
11
|
+
lastUpdated?: string;
|
|
12
|
+
outputDir: string;
|
|
13
|
+
projectId: number;
|
|
14
|
+
statusId?: string;
|
|
15
|
+
}): Promise<void>;
|
|
13
16
|
/**
|
|
14
17
|
* BacklogからWikiをダウンロードする
|
|
15
18
|
* @param command コマンドインスタンス
|
|
16
|
-
* @param
|
|
17
|
-
* @param projectIdOrKey プロジェクトIDまたはキー
|
|
18
|
-
* @param apiKey APIキー
|
|
19
|
-
* @param outputDir 出力ディレクトリ
|
|
19
|
+
* @param options Wikiダウンロードのオプション
|
|
20
20
|
*/
|
|
21
|
-
export declare function downloadWikis(command: Command,
|
|
21
|
+
export declare function downloadWikis(command: Command, options: {
|
|
22
|
+
apiKey: string;
|
|
23
|
+
domain: string;
|
|
24
|
+
lastUpdated?: string;
|
|
25
|
+
outputDir: string;
|
|
26
|
+
projectIdOrKey: string;
|
|
27
|
+
}): Promise<void>;
|
|
@@ -5,42 +5,51 @@ import { sanitizeFileName, sanitizeWikiFileName } from './common.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* Backlogから課題をダウンロードする
|
|
7
7
|
* @param command コマンドインスタンス
|
|
8
|
-
* @param
|
|
9
|
-
* @param projectId プロジェクトID
|
|
10
|
-
* @param apiKey APIキー
|
|
11
|
-
* @param outputDir 出力ディレクトリ
|
|
12
|
-
* @param count 一度に取得する課題数
|
|
13
|
-
* @param statusId ステータスID(オプション)
|
|
8
|
+
* @param options 課題ダウンロードのオプション
|
|
14
9
|
*/
|
|
15
|
-
export async function downloadIssues(command,
|
|
16
|
-
const baseUrl = `https://${domain}/api/v2`;
|
|
10
|
+
export async function downloadIssues(command, options) {
|
|
11
|
+
const baseUrl = `https://${options.domain}/api/v2`;
|
|
17
12
|
command.log('課題の取得を開始します...');
|
|
18
13
|
// APIパラメータの構築
|
|
19
14
|
const params = new URLSearchParams({
|
|
20
|
-
apiKey,
|
|
21
|
-
count: count.toString(),
|
|
22
|
-
'projectId[]': projectId.toString(),
|
|
15
|
+
apiKey: options.apiKey,
|
|
16
|
+
count: options.count.toString(),
|
|
17
|
+
'projectId[]': options.projectId.toString(),
|
|
23
18
|
});
|
|
24
19
|
// ステータスIDが指定されている場合は追加
|
|
25
|
-
if (statusId) {
|
|
26
|
-
params.append('statusId[]', statusId);
|
|
20
|
+
if (options.statusId) {
|
|
21
|
+
params.append('statusId[]', options.statusId);
|
|
27
22
|
}
|
|
28
23
|
const issues = await ky.get(`${baseUrl}/issues?${params.toString()}`).json();
|
|
29
24
|
command.log(`${issues.length}件の課題が見つかりました。`);
|
|
25
|
+
// 前回の更新日時より新しい課題のみをフィルタリング
|
|
26
|
+
let filteredIssues = issues;
|
|
27
|
+
if (options.lastUpdated) {
|
|
28
|
+
const lastUpdatedDate = new Date(options.lastUpdated);
|
|
29
|
+
filteredIssues = issues.filter((issue) => {
|
|
30
|
+
const issueUpdatedDate = new Date(issue.updated);
|
|
31
|
+
return issueUpdatedDate > lastUpdatedDate;
|
|
32
|
+
});
|
|
33
|
+
command.log(`前回の更新日時(${options.lastUpdated})以降に更新された${filteredIssues.length}件の課題を処理します。`);
|
|
34
|
+
}
|
|
35
|
+
if (filteredIssues.length === 0) {
|
|
36
|
+
command.log('更新が必要な課題はありません。');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
30
39
|
// 各課題の詳細情報を取得して保存
|
|
31
40
|
command.log('課題を保存しています...');
|
|
32
41
|
// Promise.allを使用して並列処理
|
|
33
|
-
const issuePromises =
|
|
42
|
+
const issuePromises = filteredIssues.map(async (issue) => {
|
|
34
43
|
try {
|
|
35
44
|
// 課題の詳細情報をJSONファイルとして保存
|
|
36
45
|
const issueFileName = `${sanitizeFileName(issue.summary)}.md`;
|
|
37
|
-
const issueFilePath = path.join(outputDir, issueFileName);
|
|
46
|
+
const issueFilePath = path.join(options.outputDir, issueFileName);
|
|
38
47
|
// BacklogのIssueへのリンクを作成
|
|
39
|
-
const backlogIssueUrl = `https://${domain}/view/${issue.issueKey}`;
|
|
48
|
+
const backlogIssueUrl = `https://${options.domain}/view/${issue.issueKey}`;
|
|
40
49
|
// コメント一覧を取得
|
|
41
50
|
command.log(`課題 ${issue.issueKey} のコメントを取得しています...`);
|
|
42
51
|
const commentsParams = new URLSearchParams({
|
|
43
|
-
apiKey,
|
|
52
|
+
apiKey: options.apiKey,
|
|
44
53
|
count: '100', // 最大100件のコメントを取得
|
|
45
54
|
order: 'asc', // 古い順に取得
|
|
46
55
|
});
|
|
@@ -86,29 +95,40 @@ ${issue.description || '詳細情報なし'}${commentsSection}`;
|
|
|
86
95
|
/**
|
|
87
96
|
* BacklogからWikiをダウンロードする
|
|
88
97
|
* @param command コマンドインスタンス
|
|
89
|
-
* @param
|
|
90
|
-
* @param projectIdOrKey プロジェクトIDまたはキー
|
|
91
|
-
* @param apiKey APIキー
|
|
92
|
-
* @param outputDir 出力ディレクトリ
|
|
98
|
+
* @param options Wikiダウンロードのオプション
|
|
93
99
|
*/
|
|
94
|
-
export async function downloadWikis(command,
|
|
95
|
-
const baseUrl = `https://${domain}/api/v2`;
|
|
100
|
+
export async function downloadWikis(command, options) {
|
|
101
|
+
const baseUrl = `https://${options.domain}/api/v2`;
|
|
96
102
|
command.log('Wikiの取得を開始します...');
|
|
97
103
|
// Wiki一覧の取得
|
|
98
104
|
command.log('Wiki一覧を取得しています...');
|
|
99
105
|
const wikis = await ky
|
|
100
|
-
.get(`${baseUrl}/wikis?apiKey=${apiKey}&projectIdOrKey=${projectIdOrKey}`)
|
|
106
|
+
.get(`${baseUrl}/wikis?apiKey=${options.apiKey}&projectIdOrKey=${options.projectIdOrKey}`)
|
|
101
107
|
.json();
|
|
102
108
|
command.log(`${wikis.length}件のWikiが見つかりました。`);
|
|
109
|
+
// 前回の更新日時より新しいWikiのみをフィルタリング
|
|
110
|
+
let filteredWikis = wikis;
|
|
111
|
+
if (options.lastUpdated) {
|
|
112
|
+
const lastUpdatedDate = new Date(options.lastUpdated);
|
|
113
|
+
filteredWikis = wikis.filter((wiki) => {
|
|
114
|
+
const wikiUpdatedDate = new Date(wiki.updated);
|
|
115
|
+
return wikiUpdatedDate > lastUpdatedDate;
|
|
116
|
+
});
|
|
117
|
+
command.log(`前回の更新日時(${options.lastUpdated})以降に更新された${filteredWikis.length}件のWikiを処理します。`);
|
|
118
|
+
}
|
|
119
|
+
if (filteredWikis.length === 0) {
|
|
120
|
+
command.log('更新が必要なWikiはありません。');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
103
123
|
// 各Wikiの詳細情報を取得
|
|
104
124
|
command.log('Wiki詳細を取得しています...');
|
|
105
125
|
// Promise.allを使用して並列処理
|
|
106
|
-
const wikiPromises =
|
|
126
|
+
const wikiPromises = filteredWikis.map(async (wiki) => {
|
|
107
127
|
const wikiId = wiki.id;
|
|
108
128
|
command.log(`Wiki: ${wiki.name} (ID: ${wikiId}) を取得しています`);
|
|
109
129
|
try {
|
|
110
130
|
const wikiDetail = await ky
|
|
111
|
-
.get(`${baseUrl}/wikis/${wikiId}?projectIdOrKey=${projectIdOrKey}&apiKey=${apiKey}`)
|
|
131
|
+
.get(`${baseUrl}/wikis/${wikiId}?projectIdOrKey=${options.projectIdOrKey}&apiKey=${options.apiKey}`)
|
|
112
132
|
.json();
|
|
113
133
|
// Wikiの名前をファイルパスとして使用
|
|
114
134
|
const wikiName = wiki.name;
|
|
@@ -119,14 +139,14 @@ export async function downloadWikis(command, domain, projectIdOrKey, apiKey, out
|
|
|
119
139
|
// ディレクトリ構造を作成(必要な場合)
|
|
120
140
|
const dirPath = path.dirname(wikiFileName);
|
|
121
141
|
if (dirPath !== '.') {
|
|
122
|
-
await fs.mkdir(path.join(outputDir, dirPath), { recursive: true });
|
|
142
|
+
await fs.mkdir(path.join(options.outputDir, dirPath), { recursive: true });
|
|
123
143
|
}
|
|
124
144
|
// Markdownファイルを保存
|
|
125
|
-
const wikiFilePath = path.join(outputDir, wikiFileName);
|
|
145
|
+
const wikiFilePath = path.join(options.outputDir, wikiFileName);
|
|
126
146
|
// JSONからcontentフィールドを取得
|
|
127
147
|
const content = wikiDetail.content || '';
|
|
128
148
|
// BacklogのWikiへのリンクを作成
|
|
129
|
-
const backlogWikiUrl = `https://${domain}/alias/wiki/${wikiId}`;
|
|
149
|
+
const backlogWikiUrl = `https://${options.domain}/alias/wiki/${wikiId}`;
|
|
130
150
|
// Markdownファイルに書き込む(タイトルとBacklogリンクを追加)
|
|
131
151
|
const markdownContent = `# ${wiki.name}\n\n[Backlog Wiki Link](${backlogWikiUrl})\n\n${content}`;
|
|
132
152
|
await fs.writeFile(wikiFilePath, markdownContent);
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backlog-exporter",
|
|
3
3
|
"description": "A new CLI generated with oclif",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"author": "ShuntaToda",
|
|
6
6
|
"bin": {
|
|
7
7
|
"backlog-exporter": "bin/run.js"
|
|
@@ -76,4 +76,4 @@
|
|
|
76
76
|
"version": "oclif readme && git add README.md"
|
|
77
77
|
},
|
|
78
78
|
"types": "dist/index.d.ts"
|
|
79
|
-
}
|
|
79
|
+
}
|