backlog-exporter 0.7.0 → 0.7.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.
@@ -0,0 +1,16 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Issue extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ apiKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ domain: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ issueKeyFileName: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ issueKeyFolder: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ maxCount: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
11
+ output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ projectIdOrKey: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ statusId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ };
15
+ run(): Promise<void>;
16
+ }
@@ -0,0 +1,114 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import * as dotenv from 'dotenv';
3
+ import { downloadIssues } from '../../utils/backlog-api.js';
4
+ import { validateAndGetProjectId } from '../../utils/backlog.js';
5
+ import { createOutputDirectory, getApiKey } from '../../utils/common.js';
6
+ import { FolderType, updateSettings } from '../../utils/settings.js';
7
+ // .envファイルを読み込む
8
+ dotenv.config();
9
+ export default class Issue extends Command {
10
+ static description = 'Backlogから課題を取得してMarkdownファイルとして保存する';
11
+ static examples = [
12
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY
13
+ 課題をMarkdownファイルとして保存する
14
+ `,
15
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --output ./my-issues
16
+ 指定したディレクトリに課題を保存する
17
+ `,
18
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --statusId 1,2,3
19
+ 指定したステータスIDの課題のみを取得する
20
+ `,
21
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --maxCount 10000
22
+ 最大10000件の課題を取得する(デフォルトは5000件)
23
+ `,
24
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --issueKeyFileName
25
+ ファイル名を課題キーにする
26
+ `,
27
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --issueKeyFolder
28
+ 課題キーでフォルダを作成する
29
+ `,
30
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --issueKeyFileName --issueKeyFolder
31
+ 課題キーでフォルダを作成し、ファイル名も課題キーにする
32
+ `,
33
+ ];
34
+ static flags = {
35
+ apiKey: Flags.string({
36
+ description: 'Backlog API key (環境変数 BACKLOG_API_KEY からも自動読み取り可能)',
37
+ required: false,
38
+ }),
39
+ domain: Flags.string({
40
+ description: 'Backlog domain (e.g. example.backlog.jp)',
41
+ required: true,
42
+ }),
43
+ issueKeyFileName: Flags.boolean({
44
+ description: 'ファイル名を課題キーにする',
45
+ required: false,
46
+ }),
47
+ issueKeyFolder: Flags.boolean({
48
+ description: '課題キーでフォルダを作成する',
49
+ required: false,
50
+ }),
51
+ maxCount: Flags.integer({
52
+ char: 'm',
53
+ default: 5000,
54
+ description: '一度に取得する課題の最大数(デフォルト: 5000)',
55
+ required: false,
56
+ }),
57
+ output: Flags.string({
58
+ char: 'o',
59
+ description: '出力ディレクトリパス',
60
+ required: false,
61
+ }),
62
+ projectIdOrKey: Flags.string({
63
+ description: 'Backlog project ID or key',
64
+ required: true,
65
+ }),
66
+ statusId: Flags.string({
67
+ description: 'ステータスID(カンマ区切りで複数指定可能)',
68
+ required: false,
69
+ }),
70
+ };
71
+ async run() {
72
+ const { flags } = await this.parse(Issue);
73
+ try {
74
+ const { domain, issueKeyFileName, issueKeyFolder, maxCount, projectIdOrKey, statusId } = flags;
75
+ const apiKey = flags.apiKey || getApiKey(this);
76
+ const outputDir = flags.output || './backlog-issues';
77
+ // 出力ディレクトリの作成
78
+ await createOutputDirectory(outputDir);
79
+ // プロジェクトキーからプロジェクトIDを取得
80
+ const projectId = await validateAndGetProjectId(domain, projectIdOrKey, apiKey);
81
+ this.log(`プロジェクトID: ${projectId} を使用します`);
82
+ // 設定ファイルを保存
83
+ await updateSettings(outputDir, {
84
+ apiKey,
85
+ domain,
86
+ folderType: FolderType.ISSUE,
87
+ issueKeyFileName,
88
+ issueKeyFolder,
89
+ outputDir,
90
+ projectIdOrKey,
91
+ });
92
+ // 課題の取得と保存
93
+ await downloadIssues(this, {
94
+ apiKey,
95
+ count: maxCount,
96
+ domain,
97
+ issueKeyFileName,
98
+ issueKeyFolder,
99
+ outputDir,
100
+ projectId,
101
+ statusId,
102
+ });
103
+ // 最終更新日時を更新
104
+ await updateSettings(outputDir, {
105
+ lastUpdated: new Date().toISOString(),
106
+ });
107
+ this.log('課題の取得が完了しました!');
108
+ }
109
+ catch (error) {
110
+ const errorMessage = error instanceof Error ? error.message : String(error);
111
+ this.error(`課題の取得に失敗しました: ${errorMessage}`);
112
+ }
113
+ }
114
+ }
@@ -0,0 +1,27 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Update extends Command {
3
+ static args: {
4
+ directory: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ apiKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ documentsOnly: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ issueKeyFileName: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ issueKeyFolder: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ issuesOnly: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ projectIdOrKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ wikisOnly: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ private confirmUpdate;
21
+ private determineUpdateTargets;
22
+ private findAndUpdateSettings;
23
+ private updateDirectory;
24
+ private updateDocuments;
25
+ private updateIssues;
26
+ private updateWikis;
27
+ }
@@ -0,0 +1,344 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import * as dotenv from 'dotenv';
3
+ import { access, readdir } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { downloadDocuments, downloadIssues, downloadWikis } from '../../utils/backlog-api.js';
6
+ import { validateAndGetProjectId } from '../../utils/backlog.js';
7
+ import { createOutputDirectory, getApiKey } from '../../utils/common.js';
8
+ import { FolderType, getSettingsFilePath, loadSettings, updateSettings } from '../../utils/settings.js';
9
+ // .envファイルを読み込む
10
+ dotenv.config();
11
+ export default class Update extends Command {
12
+ static args = {
13
+ directory: Args.string({
14
+ description: '更新対象のディレクトリ(設定ファイルが保存されている場所)',
15
+ required: false,
16
+ }),
17
+ };
18
+ static description = 'Backlogから最新データを取得して更新する';
19
+ static examples = [
20
+ `<%= config.bin %> <%= command.id %>
21
+ カレントディレクトリの設定を使用して更新する
22
+ `,
23
+ `<%= config.bin %> <%= command.id %> --force
24
+ 確認プロンプトをスキップする
25
+ `,
26
+ `<%= config.bin %> <%= command.id %> --apiKey YOUR_API_KEY --domain example.backlog.jp --projectIdOrKey PROJECT_KEY
27
+ 指定したパラメータで更新する(設定ファイルが存在する場合は上書きされます)
28
+ `,
29
+ `<%= config.bin %> <%= command.id %> ./my-project
30
+ 指定したディレクトリの設定を使用して更新する
31
+ `,
32
+ `<%= config.bin %> <%= command.id %> --issueKeyFileName
33
+ ファイル名を課題キーにする
34
+ `,
35
+ `<%= config.bin %> <%= command.id %> --issueKeyFolder
36
+ 課題キーでフォルダを作成する
37
+ `,
38
+ `<%= config.bin %> <%= command.id %> --issueKeyFileName --issueKeyFolder
39
+ 課題キーでフォルダを作成し、ファイル名も課題キーにする
40
+ `,
41
+ ];
42
+ static flags = {
43
+ apiKey: Flags.string({
44
+ description: 'Backlog API key (環境変数 BACKLOG_API_KEY からも自動読み取り可能)',
45
+ required: false,
46
+ }),
47
+ documentsOnly: Flags.boolean({
48
+ description: 'ドキュメントのみを更新する',
49
+ required: false,
50
+ }),
51
+ domain: Flags.string({
52
+ description: 'Backlog domain (e.g. example.backlog.jp)',
53
+ required: false,
54
+ }),
55
+ force: Flags.boolean({
56
+ char: 'f',
57
+ description: '確認プロンプトをスキップする',
58
+ required: false,
59
+ }),
60
+ issueKeyFileName: Flags.boolean({
61
+ description: 'ファイル名を課題キーにする',
62
+ required: false,
63
+ }),
64
+ issueKeyFolder: Flags.boolean({
65
+ description: '課題キーでフォルダを作成する',
66
+ required: false,
67
+ }),
68
+ issuesOnly: Flags.boolean({
69
+ description: '課題のみを更新する',
70
+ required: false,
71
+ }),
72
+ projectIdOrKey: Flags.string({
73
+ description: 'Backlog project ID or key',
74
+ required: false,
75
+ }),
76
+ wikisOnly: Flags.boolean({
77
+ description: 'Wikiのみを更新する',
78
+ required: false,
79
+ }),
80
+ };
81
+ async run() {
82
+ const { args, flags } = await this.parse(Update);
83
+ // 更新対象のディレクトリを決定(指定がなければカレントディレクトリ)
84
+ const targetDir = args.directory || process.cwd();
85
+ try {
86
+ // 設定ファイルを探索して更新を実行
87
+ await this.findAndUpdateSettings(targetDir, flags);
88
+ }
89
+ catch (error) {
90
+ const errorMessage = error instanceof Error ? error.message : String(error);
91
+ this.error(`更新に失敗しました: ${errorMessage}`);
92
+ }
93
+ }
94
+ // 確認プロンプトの表示
95
+ async confirmUpdate(options) {
96
+ if (options.force)
97
+ return true;
98
+ this.log(`以下の設定で更新を実行します:`);
99
+ this.log(`- ディレクトリ: ${options.targetDir}`);
100
+ this.log(`- ドメイン: ${options.domain}`);
101
+ this.log(`- プロジェクト: ${options.projectIdOrKey}`);
102
+ if (options.folderType) {
103
+ this.log(`- フォルダタイプ: ${options.folderType}`);
104
+ }
105
+ const updateTargets = [];
106
+ if (options.updateIssues)
107
+ updateTargets.push('課題');
108
+ if (options.updateWikis)
109
+ updateTargets.push('Wiki');
110
+ if (options.updateDocuments)
111
+ updateTargets.push('ドキュメント');
112
+ this.log(`- 更新対象: ${updateTargets.join('・')}`);
113
+ // 確認プロンプトを表示
114
+ this.log('更新を実行しますか? (y/n)');
115
+ process.stdin.resume();
116
+ process.stdin.setEncoding('utf8');
117
+ const response = await new Promise((resolve) => {
118
+ process.stdin.once('data', (data) => {
119
+ const input = data.toString().trim().toLowerCase();
120
+ resolve(input === 'y' || input === 'yes');
121
+ process.stdin.pause();
122
+ });
123
+ });
124
+ if (!response) {
125
+ this.log('更新をキャンセルしました');
126
+ }
127
+ return response;
128
+ }
129
+ // 更新対象の決定
130
+ determineUpdateTargets(folderType, documentsOnly, issuesOnly, wikisOnly) {
131
+ let updateIssues = !wikisOnly && !documentsOnly;
132
+ let updateWikis = !issuesOnly && !documentsOnly;
133
+ let updateDocuments = !issuesOnly && !wikisOnly;
134
+ // フォルダタイプに応じて更新対象を決定
135
+ switch (folderType) {
136
+ case FolderType.DOCUMENT: {
137
+ updateIssues = false;
138
+ updateWikis = false;
139
+ updateDocuments = true;
140
+ break;
141
+ }
142
+ case FolderType.ISSUE: {
143
+ updateIssues = true;
144
+ updateWikis = false;
145
+ updateDocuments = false;
146
+ break;
147
+ }
148
+ case FolderType.WIKI: {
149
+ updateIssues = false;
150
+ updateWikis = true;
151
+ updateDocuments = false;
152
+ break;
153
+ }
154
+ }
155
+ return { updateDocuments, updateIssues, updateWikis };
156
+ }
157
+ // 設定ファイルを探索して更新を実行
158
+ async findAndUpdateSettings(targetDir, flags) {
159
+ // 現在のディレクトリに設定ファイルがあるか確認
160
+ const settingsPath = getSettingsFilePath(targetDir);
161
+ let hasSettings = false;
162
+ try {
163
+ await access(settingsPath);
164
+ hasSettings = true;
165
+ }
166
+ catch {
167
+ // 設定ファイルが存在しない場合は何もしない
168
+ }
169
+ if (hasSettings) {
170
+ // 設定ファイルが存在する場合は更新を実行
171
+ await this.updateDirectory(targetDir, flags);
172
+ }
173
+ // サブディレクトリを探索
174
+ try {
175
+ const entries = await readdir(targetDir, { withFileTypes: true });
176
+ for (const entry of entries) {
177
+ if (entry.isDirectory()) {
178
+ const subDir = join(targetDir, entry.name);
179
+ // eslint-disable-next-line no-await-in-loop
180
+ await this.findAndUpdateSettings(subDir, flags);
181
+ }
182
+ }
183
+ }
184
+ catch {
185
+ this.warn(`ディレクトリの読み取りに失敗しました: ${targetDir}`);
186
+ }
187
+ }
188
+ // 指定されたディレクトリの更新を実行
189
+ async updateDirectory(targetDir, flags) {
190
+ // 設定ファイルを読み込む
191
+ const settings = await loadSettings(targetDir);
192
+ // コマンドライン引数と設定ファイルを組み合わせて使用する値を決定
193
+ const domain = flags.domain || settings.domain;
194
+ const projectIdOrKey = flags.projectIdOrKey || settings.projectIdOrKey;
195
+ const { folderType } = settings;
196
+ const { documentsOnly, force, issuesOnly, wikisOnly } = flags;
197
+ // 設定ファイルからオプションを読み込み、コマンドライン引数で上書き
198
+ const issueKeyFileName = flags.issueKeyFileName ?? settings.issueKeyFileName ?? false;
199
+ const issueKeyFolder = flags.issueKeyFolder ?? settings.issueKeyFolder ?? false;
200
+ // 必須パラメータの検証
201
+ if (!domain) {
202
+ this.warn(`${targetDir}: ドメインが指定されていません。スキップします。`);
203
+ return;
204
+ }
205
+ if (!projectIdOrKey) {
206
+ this.warn(`${targetDir}: プロジェクトIDまたはキーが指定されていません。スキップします。`);
207
+ return;
208
+ }
209
+ // APIキーの検証
210
+ let apiKey;
211
+ try {
212
+ apiKey = flags.apiKey || settings.apiKey || getApiKey(this);
213
+ }
214
+ catch {
215
+ this.warn(`${targetDir}: APIキーが指定されていません。--apiKey フラグまたは BACKLOG_API_KEY 環境変数で設定してください。`);
216
+ return;
217
+ }
218
+ // 更新対象の決定
219
+ const { updateDocuments, updateIssues, updateWikis } = this.determineUpdateTargets(folderType, documentsOnly, issuesOnly, wikisOnly);
220
+ // 更新前の確認
221
+ const confirmed = await this.confirmUpdate({
222
+ domain,
223
+ folderType,
224
+ force: force || false,
225
+ projectIdOrKey,
226
+ targetDir,
227
+ updateDocuments,
228
+ updateIssues,
229
+ updateWikis,
230
+ });
231
+ if (!confirmed)
232
+ return;
233
+ // 出力ディレクトリの作成
234
+ await createOutputDirectory(targetDir);
235
+ // プロジェクトキーからプロジェクトIDを取得
236
+ const projectId = await validateAndGetProjectId(domain, projectIdOrKey, apiKey);
237
+ this.log(`プロジェクトID: ${projectId} を使用します`);
238
+ // 課題の更新
239
+ if (updateIssues) {
240
+ await this.updateIssues({
241
+ apiKey,
242
+ domain,
243
+ issueKeyFileName,
244
+ issueKeyFolder,
245
+ projectId,
246
+ projectIdOrKey,
247
+ targetDir,
248
+ });
249
+ }
250
+ // Wikiの更新
251
+ if (updateWikis) {
252
+ await this.updateWikis({
253
+ apiKey,
254
+ domain,
255
+ projectIdOrKey,
256
+ targetDir,
257
+ });
258
+ }
259
+ // ドキュメントの更新
260
+ if (updateDocuments) {
261
+ await this.updateDocuments({
262
+ apiKey,
263
+ domain,
264
+ projectId,
265
+ projectIdOrKey,
266
+ targetDir,
267
+ });
268
+ }
269
+ this.log(`${targetDir} の更新が完了しました!`);
270
+ }
271
+ // ドキュメントの更新
272
+ async updateDocuments(options) {
273
+ this.log('ドキュメントの更新を開始します...');
274
+ // 設定ファイルから前回の更新日時を取得
275
+ const { lastUpdated } = await loadSettings(options.targetDir);
276
+ await downloadDocuments(this, {
277
+ apiKey: options.apiKey,
278
+ domain: options.domain,
279
+ lastUpdated,
280
+ outputDir: options.targetDir,
281
+ projectId: options.projectId,
282
+ projectIdOrKey: options.projectIdOrKey,
283
+ });
284
+ // 設定ファイルを更新
285
+ await updateSettings(options.targetDir, {
286
+ apiKey: options.apiKey,
287
+ domain: options.domain,
288
+ folderType: FolderType.DOCUMENT,
289
+ lastUpdated: new Date().toISOString(),
290
+ outputDir: options.targetDir,
291
+ projectIdOrKey: options.projectIdOrKey,
292
+ });
293
+ this.log('ドキュメントの更新が完了しました');
294
+ }
295
+ // 課題の更新
296
+ async updateIssues(options) {
297
+ this.log('課題の更新を開始します...');
298
+ // 設定ファイルから前回の更新日時を取得
299
+ const { lastUpdated } = await loadSettings(options.targetDir);
300
+ await downloadIssues(this, {
301
+ apiKey: options.apiKey,
302
+ count: 100,
303
+ domain: options.domain,
304
+ issueKeyFileName: options.issueKeyFileName,
305
+ issueKeyFolder: options.issueKeyFolder,
306
+ lastUpdated,
307
+ outputDir: options.targetDir,
308
+ projectId: options.projectId,
309
+ });
310
+ // 設定ファイルを更新
311
+ await updateSettings(options.targetDir, {
312
+ apiKey: options.apiKey,
313
+ domain: options.domain,
314
+ folderType: FolderType.ISSUE,
315
+ lastUpdated: new Date().toISOString(),
316
+ outputDir: options.targetDir,
317
+ projectIdOrKey: options.projectIdOrKey,
318
+ });
319
+ this.log('課題の更新が完了しました');
320
+ }
321
+ // Wikiの更新
322
+ async updateWikis(options) {
323
+ this.log('Wikiの更新を開始します...');
324
+ // 設定ファイルから前回の更新日時を取得
325
+ const { lastUpdated } = await loadSettings(options.targetDir);
326
+ await downloadWikis(this, {
327
+ apiKey: options.apiKey,
328
+ domain: options.domain,
329
+ lastUpdated,
330
+ outputDir: options.targetDir,
331
+ projectIdOrKey: options.projectIdOrKey,
332
+ });
333
+ // 設定ファイルを更新
334
+ await updateSettings(options.targetDir, {
335
+ apiKey: options.apiKey,
336
+ domain: options.domain,
337
+ folderType: FolderType.WIKI,
338
+ lastUpdated: new Date().toISOString(),
339
+ outputDir: options.targetDir,
340
+ projectIdOrKey: options.projectIdOrKey,
341
+ });
342
+ this.log('Wikiの更新が完了しました');
343
+ }
344
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Wiki extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ apiKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ domain: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ projectIdOrKey: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,71 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import * as dotenv from 'dotenv';
3
+ import { downloadWikis } from '../../utils/backlog-api.js';
4
+ import { createOutputDirectory, getApiKey } from '../../utils/common.js';
5
+ import { FolderType, updateSettings } from '../../utils/settings.js';
6
+ // .envファイルを読み込む
7
+ dotenv.config();
8
+ export default class Wiki extends Command {
9
+ static description = 'Backlogから Wiki を取得してMarkdownファイルとして保存する';
10
+ static examples = [
11
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY
12
+ Wikiをダウンロードする
13
+ `,
14
+ `<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --output ./my-project
15
+ 指定したディレクトリにWikiを保存する
16
+ `,
17
+ ];
18
+ static flags = {
19
+ apiKey: Flags.string({
20
+ description: 'Backlog API key (環境変数 BACKLOG_API_KEY からも自動読み取り可能)',
21
+ required: false,
22
+ }),
23
+ domain: Flags.string({
24
+ description: 'Backlog domain (e.g. example.backlog.jp)',
25
+ required: true,
26
+ }),
27
+ output: Flags.string({
28
+ char: 'o',
29
+ description: '出力ディレクトリパス',
30
+ required: false,
31
+ }),
32
+ projectIdOrKey: Flags.string({
33
+ description: 'Backlog project ID or key',
34
+ required: true,
35
+ }),
36
+ };
37
+ async run() {
38
+ const { flags } = await this.parse(Wiki);
39
+ try {
40
+ const { domain, projectIdOrKey } = flags;
41
+ const apiKey = flags.apiKey || getApiKey(this);
42
+ const outputDir = flags.output || './wiki';
43
+ // 出力ディレクトリの作成
44
+ await createOutputDirectory(outputDir);
45
+ // 設定ファイルを保存
46
+ await updateSettings(outputDir, {
47
+ apiKey,
48
+ domain,
49
+ folderType: FolderType.WIKI,
50
+ outputDir,
51
+ projectIdOrKey,
52
+ });
53
+ // Wikiの取得と保存
54
+ await downloadWikis(this, {
55
+ apiKey,
56
+ domain,
57
+ outputDir,
58
+ projectIdOrKey,
59
+ });
60
+ // 最終更新日時を更新
61
+ await updateSettings(outputDir, {
62
+ lastUpdated: new Date().toISOString(),
63
+ });
64
+ this.log('Wikiの取得が完了しました!');
65
+ }
66
+ catch (error) {
67
+ const errorMessage = error instanceof Error ? error.message : String(error);
68
+ this.error(`Wikiの取得に失敗しました: ${errorMessage}`);
69
+ }
70
+ }
71
+ }
@@ -0,0 +1 @@
1
+ export { run } from '@oclif/core';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { run } from '@oclif/core';
@@ -0,0 +1,74 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * カスタム属性セクションを作成する
4
+ * @param customFields カスタム属性の配列
5
+ * @returns Markdownテーブル形式のカスタム属性セクション
6
+ */
7
+ export declare function createCustomFieldsSection(customFields?: Array<{
8
+ id: number;
9
+ name: string;
10
+ value: unknown;
11
+ }>): string;
12
+ /**
13
+ * Backlogから課題をダウンロードする
14
+ * @param command コマンドインスタンス
15
+ * @param options 課題ダウンロードのオプション
16
+ * @param options.apiKey Backlog API key
17
+ * @param options.count 取得する課題の最大数
18
+ * @param options.domain Backlogのドメイン
19
+ * @param options.lastUpdated 最終更新日時
20
+ * @param options.outputDir 出力ディレクトリ
21
+ * @param options.projectId プロジェクトID
22
+ * @param options.statusId ステータスID
23
+ * @param options.issueKeyFileName ファイル名を課題キーにするかどうか
24
+ * @param options.issueKeyFolder 課題キーでフォルダを作成するかどうか
25
+ */
26
+ export declare function downloadIssues(command: Command, options: {
27
+ apiKey: string;
28
+ count?: number;
29
+ domain: string;
30
+ issueKeyFileName?: boolean;
31
+ issueKeyFolder?: boolean;
32
+ lastUpdated?: string;
33
+ outputDir: string;
34
+ projectId: number;
35
+ statusId?: string;
36
+ }): Promise<void>;
37
+ /**
38
+ * BacklogからWikiをダウンロードする
39
+ * @param command コマンドインスタンス
40
+ * @param options Wikiダウンロードのオプション
41
+ * @param options.apiKey Backlog API key
42
+ * @param options.domain Backlogのドメイン
43
+ * @param options.lastUpdated 最終更新日時
44
+ * @param options.outputDir 出力ディレクトリ
45
+ * @param options.projectIdOrKey プロジェクトIDまたはキー
46
+ */
47
+ export declare function downloadWikis(command: Command, options: {
48
+ apiKey: string;
49
+ domain: string;
50
+ lastUpdated?: string;
51
+ outputDir: string;
52
+ projectIdOrKey: string;
53
+ }): Promise<void>;
54
+ /**
55
+ * Backlogからドキュメントをダウンロードする
56
+ * @param command コマンドインスタンス
57
+ * @param options ドキュメントダウンロードのオプション
58
+ * @param options.apiKey Backlog API key
59
+ * @param options.domain Backlogのドメイン
60
+ * @param options.keyword キーワードフィルター
61
+ * @param options.lastUpdated 最終更新日時
62
+ * @param options.outputDir 出力ディレクトリ
63
+ * @param options.projectId プロジェクトID
64
+ * @param options.projectIdOrKey プロジェクトIDまたはキー
65
+ */
66
+ export declare function downloadDocuments(command: Command, options: {
67
+ apiKey: string;
68
+ domain: string;
69
+ keyword?: string;
70
+ lastUpdated?: string;
71
+ outputDir: string;
72
+ projectId: number;
73
+ projectIdOrKey: string;
74
+ }): Promise<void>;