backlog-exporter 0.7.3 → 1.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/README.md +109 -1
- package/bin/dev.js +6 -2
- package/dist/commands/all/index.d.ts +3 -0
- package/dist/commands/all/index.js +69 -127
- package/dist/commands/document/index.d.ts +1 -0
- package/dist/commands/document/index.js +26 -12
- package/dist/commands/issue/index.d.ts +1 -0
- package/dist/commands/issue/index.js +29 -12
- package/dist/commands/prune/index.d.ts +16 -0
- package/dist/commands/prune/index.js +86 -0
- package/dist/commands/update/index.d.ts +4 -7
- package/dist/commands/update/index.js +33 -260
- package/dist/commands/wiki/index.d.ts +1 -0
- package/dist/commands/wiki/index.js +25 -10
- package/dist/composition/backlog-repositories.d.ts +16 -0
- package/dist/composition/backlog-repositories.js +15 -0
- package/dist/modules/all/domain/content-selection.d.ts +4 -0
- package/dist/modules/all/domain/content-selection.js +16 -0
- package/dist/modules/all/use-case/export-all.d.ts +25 -0
- package/dist/modules/all/use-case/export-all.js +84 -0
- package/dist/modules/document/domain/document-markdown.d.ts +2 -0
- package/dist/modules/document/domain/document-markdown.js +40 -0
- package/dist/modules/document/domain/document-path.d.ts +23 -0
- package/dist/modules/document/domain/document-path.js +57 -0
- package/dist/modules/document/domain/document-repository.d.ts +7 -0
- package/dist/modules/document/domain/document-repository.js +1 -0
- package/dist/modules/document/domain/document-save-plan.d.ts +9 -0
- package/dist/modules/document/domain/document-save-plan.js +15 -0
- package/dist/modules/document/domain/document.d.ts +50 -0
- package/dist/modules/document/domain/document.js +1 -0
- package/dist/modules/document/repository/backlog-document-repository.d.ts +3 -0
- package/dist/modules/document/repository/backlog-document-repository.js +35 -0
- package/dist/modules/document/use-case/export-documents.d.ts +17 -0
- package/dist/modules/document/use-case/export-documents.js +107 -0
- package/dist/modules/issue/domain/issue-filter.d.ts +2 -0
- package/dist/modules/issue/domain/issue-filter.js +7 -0
- package/dist/modules/issue/domain/issue-markdown.d.ts +5 -0
- package/dist/modules/issue/domain/issue-markdown.js +127 -0
- package/dist/modules/issue/domain/issue-path.d.ts +34 -0
- package/dist/modules/issue/domain/issue-path.js +42 -0
- package/dist/modules/issue/domain/issue-repository.d.ts +12 -0
- package/dist/modules/issue/domain/issue-repository.js +1 -0
- package/dist/modules/issue/domain/issue.d.ts +53 -0
- package/dist/modules/issue/domain/issue.js +1 -0
- package/dist/modules/issue/repository/backlog-issue-repository.d.ts +3 -0
- package/dist/modules/issue/repository/backlog-issue-repository.js +41 -0
- package/dist/modules/issue/use-case/export-issues.d.ts +19 -0
- package/dist/modules/issue/use-case/export-issues.js +113 -0
- package/dist/modules/project/domain/project-repository.d.ts +3 -0
- package/dist/modules/project/domain/project-repository.js +1 -0
- package/dist/modules/project/repository/backlog-project-repository.d.ts +3 -0
- package/dist/modules/project/repository/backlog-project-repository.js +17 -0
- package/dist/modules/prune/domain/expected-paths.d.ts +4 -0
- package/dist/modules/prune/domain/expected-paths.js +1 -0
- package/dist/modules/prune/domain/prune-target.d.ts +3 -0
- package/dist/modules/prune/domain/prune-target.js +21 -0
- package/dist/modules/prune/repository/prune-walker.d.ts +7 -0
- package/dist/modules/prune/repository/prune-walker.js +44 -0
- package/dist/modules/prune/use-case/prune-directories.d.ts +28 -0
- package/dist/modules/prune/use-case/prune-directories.js +74 -0
- package/dist/modules/prune/use-case/prune-exports.d.ts +27 -0
- package/dist/modules/prune/use-case/prune-exports.js +74 -0
- package/dist/modules/settings/domain/settings.d.ts +16 -0
- package/dist/modules/settings/domain/settings.js +6 -0
- package/dist/modules/settings/repository/settings-store.d.ts +6 -0
- package/dist/modules/settings/repository/settings-store.js +56 -0
- package/dist/modules/update/domain/update-plan.d.ts +38 -0
- package/dist/modules/update/domain/update-plan.js +70 -0
- package/dist/modules/update/use-case/update-exports.d.ts +21 -0
- package/dist/modules/update/use-case/update-exports.js +139 -0
- package/dist/modules/wiki/domain/wiki-filter.d.ts +9 -0
- package/dist/modules/wiki/domain/wiki-filter.js +11 -0
- package/dist/modules/wiki/domain/wiki-markdown.d.ts +6 -0
- package/dist/modules/wiki/domain/wiki-markdown.js +19 -0
- package/dist/modules/wiki/domain/wiki-path.d.ts +7 -0
- package/dist/modules/wiki/domain/wiki-path.js +37 -0
- package/dist/modules/wiki/domain/wiki-repository.d.ts +6 -0
- package/dist/modules/wiki/domain/wiki-repository.js +1 -0
- package/dist/modules/wiki/domain/wiki.d.ts +16 -0
- package/dist/modules/wiki/domain/wiki.js +1 -0
- package/dist/modules/wiki/repository/backlog-wiki-repository.d.ts +3 -0
- package/dist/modules/wiki/repository/backlog-wiki-repository.js +13 -0
- package/dist/modules/wiki/use-case/export-wikis.d.ts +15 -0
- package/dist/modules/wiki/use-case/export-wikis.js +71 -0
- package/dist/shared/attachment.d.ts +8 -0
- package/dist/shared/attachment.js +37 -0
- package/dist/shared/backlog/http-client.d.ts +20 -0
- package/dist/shared/backlog/http-client.js +93 -0
- package/dist/shared/backlog/sleep.d.ts +1 -0
- package/dist/shared/backlog/sleep.js +3 -0
- package/dist/shared/backlog-url.d.ts +1 -0
- package/dist/shared/backlog-url.js +5 -0
- package/dist/shared/config/env.d.ts +3 -0
- package/dist/shared/config/env.js +21 -0
- package/dist/shared/console/progress.d.ts +1 -0
- package/dist/shared/console/progress.js +11 -0
- package/dist/shared/console/prompt.d.ts +3 -0
- package/dist/shared/console/prompt.js +19 -0
- package/dist/shared/file-name.d.ts +3 -0
- package/dist/shared/file-name.js +26 -0
- package/dist/shared/markdown/body-marker.d.ts +3 -0
- package/dist/shared/markdown/body-marker.js +5 -0
- package/dist/shared/ports.d.ts +4 -0
- package/dist/shared/ports.js +1 -0
- package/dist/shared/storage/markdown-store.d.ts +7 -0
- package/dist/shared/storage/markdown-store.js +32 -0
- package/dist/shared/storage/update-log.d.ts +1 -0
- package/dist/{utils/log.js → shared/storage/update-log.js} +1 -5
- package/oclif.manifest.json +160 -27
- package/package.json +15 -19
- package/dist/utils/backlog-api.d.ts +0 -74
- package/dist/utils/backlog-api.js +0 -453
- package/dist/utils/backlog.d.ts +0 -16
- package/dist/utils/backlog.js +0 -34
- package/dist/utils/common.d.ts +0 -25
- package/dist/utils/common.js +0 -54
- package/dist/utils/log.d.ts +0 -6
- package/dist/utils/settings.d.ts +0 -45
- package/dist/utils/settings.js +0 -63
- package/dist/utils/sleep.d.ts +0 -28
- package/dist/utils/sleep.js +0 -42
package/README.md
CHANGED
|
@@ -16,6 +16,12 @@ Backlog のデータをエクスポートするためのコマンドラインツ
|
|
|
16
16
|
* [ドキュメント のエクスポート](#ドキュメント-のエクスポート)
|
|
17
17
|
* [課題・Wiki・ドキュメント の一括エクスポート](#課題wikiドキュメント-の一括エクスポート)
|
|
18
18
|
* [データの更新](#データの更新)
|
|
19
|
+
* [特定の課題だけを再取得(課題キーまたは課題ID)](#特定の課題だけを再取得課題キーまたは課題id)
|
|
20
|
+
* [特定のWikiだけを再取得(Wiki ID)](#特定のwikiだけを再取得wiki-id)
|
|
21
|
+
* [特定のドキュメントだけを再取得(ドキュメントID)](#特定のドキュメントだけを再取得ドキュメントid)
|
|
22
|
+
* [カレントディレクトリ配下の設定ファイルを探索して実行](#カレントディレクトリ配下の設定ファイルを探索して実行)
|
|
23
|
+
* [対象ディレクトリを指定](#対象ディレクトリを指定)
|
|
24
|
+
* [確認プロンプトをスキップ](#確認プロンプトをスキップ)
|
|
19
25
|
* [コマンド](#コマンド)
|
|
20
26
|
* [出力形式](#出力形式)
|
|
21
27
|
* [課題のタイトル](#課題のタイトル)
|
|
@@ -43,7 +49,7 @@ $ npm install -g backlog-exporter
|
|
|
43
49
|
$ backlog-exporter COMMAND
|
|
44
50
|
running command...
|
|
45
51
|
$ backlog-exporter (--version)
|
|
46
|
-
backlog-exporter/
|
|
52
|
+
backlog-exporter/1.1.0 linux-x64 node-v26.5.0
|
|
47
53
|
$ backlog-exporter --help [COMMAND]
|
|
48
54
|
USAGE
|
|
49
55
|
$ backlog-exporter COMMAND
|
|
@@ -153,8 +159,30 @@ $ backlog-exporter issue --domain example.backlog.jp --projectIdOrKey PROJECT_KE
|
|
|
153
159
|
$ backlog-exporter issue --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --issueKeyFileName --issueKeyFolder
|
|
154
160
|
```
|
|
155
161
|
|
|
162
|
+
**課題の添付ファイルもダウンロードする**
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
$ backlog-exporter issue --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --downloadAttachments
|
|
166
|
+
```
|
|
167
|
+
|
|
156
168
|
エクスポートされた課題は、指定したディレクトリ内に Markdown ファイルとして保存されます。ファイル名は課題のキーに基づいて自動的に生成されます。
|
|
157
169
|
|
|
170
|
+
## 添付ファイルのダウンロード
|
|
171
|
+
|
|
172
|
+
`--downloadAttachments`(短縮形: `-d`)フラグを指定すると、課題・Wiki・ドキュメントの添付ファイルもダウンロードされます(`all` / `issue` / `wiki` / `document` / `update` コマンドで使用可能)。
|
|
173
|
+
|
|
174
|
+
- 保存先:
|
|
175
|
+
- 課題: デフォルトは `{年}/attachments/{課題キー}/`、`--issueKeyFolder` 指定時は課題フォルダ直下の `attachments/`
|
|
176
|
+
- Wiki: Markdownと同じディレクトリの `attachments/{Wiki名}/`(階層Wikiは末尾のページ名)
|
|
177
|
+
- ドキュメント: Markdownと同じディレクトリの `attachments/{ドキュメント名}/`
|
|
178
|
+
- ファイル名は同名の衝突を避けるため `{添付ID}_{ファイル名}` になります
|
|
179
|
+
- Markdown の `## 添付ファイル` セクションにローカルファイルへの相対リンクが記載されます(フラグ未指定時はファイル名とサイズのみ記載)
|
|
180
|
+
- 課題の本文・コメント内の添付画像のインライン記法(`![image][ファイル名]` / `#image(ファイル名)`)は、ダウンロード済みファイルへの画像リンクに変換され、Markdownビューアでそのまま表示できます
|
|
181
|
+
- Wiki・ドキュメントの本文はBacklogの原文のまま維持されます(添付参照記法の書き換えは行いません)。添付ファイルへは `## 添付ファイル` セクションのリンクからアクセスできます
|
|
182
|
+
- ダウンロード済みのファイルは再ダウンロードされないため、`update` コマンドでの差分更新でも効率的に動作します
|
|
183
|
+
- 設定は `backlog-settings.json` に保存され、以降の `update` コマンドで自動的に引き継がれます(`update` コマンド自体でフラグを指定した場合はその実行のみ有効です)
|
|
184
|
+
- Backlog側で削除された添付ファイルは、誤削除防止のため `prune` コマンドでも削除されず残ります
|
|
185
|
+
|
|
158
186
|
## カスタム属性の対応
|
|
159
187
|
|
|
160
188
|
課題のエクスポートでは、Backlogのカスタム属性も含めて出力されます:
|
|
@@ -227,12 +255,14 @@ $ backlog-exporter document --domain example.backlog.jp --projectIdOrKey PROJECT
|
|
|
227
255
|
|
|
228
256
|
- Backlogのドキュメントツリーの階層構造がそのままローカルディレクトリ構造として再現されます
|
|
229
257
|
- フォルダはディレクトリとして作成され、ドキュメントはMarkdownファイルとして保存されます
|
|
258
|
+
- 子を持つ親ドキュメント自身が本文を持つ場合は、フォルダ内の `00_index.md` として保存されます(本文が空の親はファイルを作成しません)
|
|
230
259
|
|
|
231
260
|
### 出力例
|
|
232
261
|
|
|
233
262
|
```
|
|
234
263
|
documents/
|
|
235
264
|
├── プロジェクト概要/
|
|
265
|
+
│ ├── 00_index.md ← 親ドキュメント「プロジェクト概要」自身の本文
|
|
236
266
|
│ ├── 要件定義書.md
|
|
237
267
|
│ └── 仕様書.md
|
|
238
268
|
├── 設計書/
|
|
@@ -248,6 +278,7 @@ documents/
|
|
|
248
278
|
### 特徴
|
|
249
279
|
|
|
250
280
|
- **階層構造の完全再現**: Backlogのフォルダ階層がそのまま保持されます
|
|
281
|
+
- **親ドキュメント本文の保存**: 子を持つ親ドキュメントの本文もフォルダ内の `00_index.md` として保存されます
|
|
251
282
|
- **重複処理の防止**: 同じドキュメントが複数回処理されることを防ぎます
|
|
252
283
|
- **ファイル名の自動サニタイズ**: 不正な文字を自動的に除去して安全なファイル名を生成します
|
|
253
284
|
- **メタデータの保持**: 作成者、更新者、タグ、添付ファイル情報なども含めて保存されます
|
|
@@ -286,6 +317,15 @@ $ backlog-exporter all --domain example.backlog.jp --projectIdOrKey PROJECT_KEY
|
|
|
286
317
|
|
|
287
318
|
## エクスポート対象の制御
|
|
288
319
|
|
|
320
|
+
`--only` / `--exclude` を指定せずに対話端末で実行した場合は、Wiki・ドキュメントのどちらを取得するかを選択できます(BacklogはWikiからドキュメントへの移行を予定しています):
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
BacklogのWikiとドキュメントのどちらを取得しますか?(BacklogはWikiからドキュメントへの移行を予定しています)
|
|
324
|
+
[1] 両方(デフォルト) [2] Wikiのみ [3] ドキュメントのみ
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
非対話環境(CI・パイプ実行)では従来どおり両方を取得します。
|
|
328
|
+
|
|
289
329
|
`all`コマンドでは、以下のフラグを使用してエクスポート対象を制御できます:
|
|
290
330
|
|
|
291
331
|
### --only フラグ
|
|
@@ -368,8 +408,51 @@ $ backlog-exporter update --documentsOnly
|
|
|
368
408
|
$ backlog-exporter update --apiKey YOUR_API_KEY
|
|
369
409
|
```
|
|
370
410
|
|
|
411
|
+
**指定した項目(課題・Wiki・ドキュメント)のみを再取得する**
|
|
412
|
+
|
|
413
|
+
```sh
|
|
414
|
+
# 特定の課題だけを再取得(課題キーまたは課題ID)
|
|
415
|
+
$ backlog-exporter update --issueIdOrKey PROJECT-1,PROJECT-2
|
|
416
|
+
|
|
417
|
+
# 特定のWikiだけを再取得(Wiki ID)
|
|
418
|
+
$ backlog-exporter update --wikiId 12345,12346
|
|
419
|
+
|
|
420
|
+
# 特定のドキュメントだけを再取得(ドキュメントID)
|
|
421
|
+
$ backlog-exporter update --documentId abc123,def456
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
`update` は通常、設定ファイルの最終更新日時(`lastUpdated`)以降に更新された項目を差分取得します。一方で「特定の項目だけを取り直したい」場合は、上記のID指定フラグを使います。
|
|
425
|
+
|
|
426
|
+
- `--issueIdOrKey`: 課題キー(`PROJECT-1`)または課題ID(数値)。Wiki・ドキュメントは数値IDのみのため `--wikiId` / `--documentId` を使います
|
|
427
|
+
- いずれもカンマ区切りで複数指定できます
|
|
428
|
+
- 指定したフラグに対応する項目のみを再取得し、それ以外の種別の更新は行いません(例: `--wikiId` のみ指定時は課題・ドキュメントを更新しません)
|
|
429
|
+
- 指定した項目以外のローカルファイルには影響しません
|
|
430
|
+
|
|
431
|
+
> **Note**: これらのID指定フラグは全件差分更新ではないため、設定ファイルの最終更新日時(`lastUpdated`)は更新されません。そのため、次回の通常の差分更新に影響を与えません。
|
|
432
|
+
|
|
371
433
|
更新コマンドは、各ディレクトリの設定ファイルに基づいて、課題・Wiki・ドキュメントを自動的に更新します。設定ファイルが見つかったディレクトリでは、そのディレクトリ内のファイルが直接更新されます(サブフォルダは作成されません)。
|
|
372
434
|
|
|
435
|
+
**Backlog上で削除・移動された課題・ドキュメント・Wikiのローカルファイルを削除する(prune)**
|
|
436
|
+
|
|
437
|
+
```sh
|
|
438
|
+
# カレントディレクトリ配下の設定ファイルを探索して実行
|
|
439
|
+
$ backlog-exporter prune
|
|
440
|
+
|
|
441
|
+
# 対象ディレクトリを指定
|
|
442
|
+
$ backlog-exporter prune ./backlog-documents
|
|
443
|
+
|
|
444
|
+
# 確認プロンプトをスキップ
|
|
445
|
+
$ backlog-exporter prune --force
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
`update`(および各取得コマンド)は増分更新(追加・上書き)のため、Backlog上で削除された課題・ドキュメント・Wikiや別の場所へ移動されたものは、ローカルにファイルが残り続けます。`prune` コマンドは、Backlogに存在しないローカルの `.md` ファイルと、空になったディレクトリを削除してBacklogと同じ状態に揃えます。
|
|
449
|
+
|
|
450
|
+
- 対象は**課題・ドキュメント・Wikiフォルダ**です(設定ファイルの `folderType` で判定します)
|
|
451
|
+
- ファイルを削除する破壊的な操作のため、`update` とは独立したコマンドとして分離しています(実行時に確認プロンプトを表示。`--force` でスキップ可能)
|
|
452
|
+
- 削除対象は `.md` ファイルのみ。`backlog-settings.json`・`backlog-update.log`・`.md` 以外のファイルには触れません。ただし、対象フォルダ内にユーザーが独自に置いた `.md` ファイルや空のディレクトリは、Backlog上に存在しないものとして削除されるため注意してください
|
|
453
|
+
- ファイル名は保存時と同じロジックで比較します(ドキュメントは一覧APIの `title` 基準、課題は設定ファイルの `issueKeyFileName`/`issueKeyFolder` を反映)。サニタイズ差異やツリー名との差異による誤削除は起きません。ドキュメント情報の取得に失敗した場合は、誤削除を防ぐため何も削除せずに中止します
|
|
454
|
+
- 削除したファイルは `backlog-update.log` に記録されます
|
|
455
|
+
|
|
373
456
|
# コマンド
|
|
374
457
|
|
|
375
458
|
## `backlog-exporter help [COMMAND]`
|
|
@@ -686,6 +769,25 @@ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/
|
|
|
686
769
|
|
|
687
770
|
# 出力形式
|
|
688
771
|
|
|
772
|
+
## 本文マーカー
|
|
773
|
+
|
|
774
|
+
課題の詳細・Wikiの本文・ドキュメントの内容といった「本文」部分は、種別を問わず以下のHTMLコメントマーカーで囲まれて出力されます。
|
|
775
|
+
|
|
776
|
+
```markdown
|
|
777
|
+
<!-- backlog-exporter:body:start -->
|
|
778
|
+
ここが本文(## 見出しなどを含んでもよい)
|
|
779
|
+
<!-- backlog-exporter:body:end -->
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
- マーカーはMarkdownのレンダリング時には表示されません(HTMLコメント)
|
|
783
|
+
- 本文自体が `##` 見出しなどを含んでいても、開始・終了マーカー間を本文として機械的に抽出・差し替えできます
|
|
784
|
+
- 本文をBacklogへ書き戻す(API反映する)ツールなどが、どこからどこまでが本文かを一意に判定するために使えます
|
|
785
|
+
- 子を持つ親ドキュメントの本文(`00_index.md`)にも同じマーカーが付きます
|
|
786
|
+
|
|
787
|
+
**抽出時の規約**: 本文自体がマーカーと同じ文字列を含む可能性があるため(例: このツールの使い方をBacklog上にメモした場合)、抽出ツールは「ファイル内で**最初に現れる開始マーカー**から**最後に現れる終了マーカー**まで」を本文とみなしてください。
|
|
788
|
+
|
|
789
|
+
以降の出力例では、この本文マーカーを含めた形を示します。
|
|
790
|
+
|
|
689
791
|
## 課題の出力形式
|
|
690
792
|
|
|
691
793
|
課題は以下の形式で Markdown ファイルとして保存されます:
|
|
@@ -714,7 +816,9 @@ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/
|
|
|
714
816
|
|
|
715
817
|
## 詳細
|
|
716
818
|
|
|
819
|
+
<!-- backlog-exporter:body:start -->
|
|
717
820
|
ここに課題の詳細説明が入ります。
|
|
821
|
+
<!-- backlog-exporter:body:end -->
|
|
718
822
|
|
|
719
823
|
## コメント
|
|
720
824
|
|
|
@@ -744,8 +848,10 @@ Wiki は以下の形式で Markdown ファイルとして保存されます:
|
|
|
744
848
|
|
|
745
849
|
[Backlog Wiki Link](https://example.backlog.jp/alias/wiki/12345)
|
|
746
850
|
|
|
851
|
+
<!-- backlog-exporter:body:start -->
|
|
747
852
|
ここに Wiki の本文内容が入ります。
|
|
748
853
|
Backlog の書式がそのまま保持されます。
|
|
854
|
+
<!-- backlog-exporter:body:end -->
|
|
749
855
|
```
|
|
750
856
|
|
|
751
857
|
## ドキュメント の出力形式
|
|
@@ -765,8 +871,10 @@ Backlog の書式がそのまま保持されます。
|
|
|
765
871
|
|
|
766
872
|
## 内容
|
|
767
873
|
|
|
874
|
+
<!-- backlog-exporter:body:start -->
|
|
768
875
|
ここにドキュメントの本文内容が入ります。
|
|
769
876
|
Backlog の書式がそのまま保持されます。
|
|
877
|
+
<!-- backlog-exporter:body:end -->
|
|
770
878
|
|
|
771
879
|
## 添付ファイル
|
|
772
880
|
|
package/bin/dev.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env -S node --
|
|
1
|
+
#!/usr/bin/env -S node --import tsx --disable-warning=ExperimentalWarning
|
|
2
2
|
|
|
3
3
|
import {execute} from '@oclif/core'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// execute({development: true}) はエラー時のスタックトレース表示も有効化してしまうため、
|
|
6
|
+
// srcのTS解決に必要な NODE_ENV のみを設定する
|
|
7
|
+
process.env.NODE_ENV = 'development'
|
|
8
|
+
|
|
9
|
+
await execute({dir: import.meta.url})
|
|
@@ -5,6 +5,7 @@ export default class All extends Command {
|
|
|
5
5
|
static flags: {
|
|
6
6
|
apiKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
domain: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
downloadAttachments: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
9
|
exclude: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
10
|
issueKeyFileName: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
issueKeyFolder: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -14,4 +15,6 @@ export default class All extends Command {
|
|
|
14
15
|
projectIdOrKey: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
16
|
};
|
|
16
17
|
run(): Promise<void>;
|
|
18
|
+
private determineTargets;
|
|
19
|
+
private promptContentSelection;
|
|
17
20
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { FolderType, updateSettings } from '../../utils/settings.js';
|
|
2
|
+
import { createBacklogRepositories } from '../../composition/backlog-repositories.js';
|
|
3
|
+
import { applyContentSelection, parseContentSelection } from '../../modules/all/domain/content-selection.js';
|
|
4
|
+
import { exportAll } from '../../modules/all/use-case/export-all.js';
|
|
5
|
+
import { API_KEY_NOT_FOUND_MESSAGE, loadDotenv, resolveApiKey } from '../../shared/config/env.js';
|
|
6
|
+
import { isInteractiveStdin, readLine } from '../../shared/console/prompt.js';
|
|
8
7
|
// .envファイルを読み込む
|
|
9
|
-
|
|
8
|
+
loadDotenv();
|
|
9
|
+
const VALID_TARGETS = ['issues', 'wiki', 'documents'];
|
|
10
10
|
export default class All extends Command {
|
|
11
11
|
static description = 'Backlogから課題・Wiki・ドキュメントを取得してMarkdownファイルとして保存する';
|
|
12
12
|
static examples = [
|
|
@@ -44,6 +44,11 @@ export default class All extends Command {
|
|
|
44
44
|
description: 'Backlog domain (e.g. example.backlog.jp)',
|
|
45
45
|
required: true,
|
|
46
46
|
}),
|
|
47
|
+
downloadAttachments: Flags.boolean({
|
|
48
|
+
char: 'd',
|
|
49
|
+
description: '課題の添付ファイルもダウンロードする',
|
|
50
|
+
required: false,
|
|
51
|
+
}),
|
|
47
52
|
exclude: Flags.string({
|
|
48
53
|
description: "Exclude the specified types, separated by commas (e.g., 'documents,wiki')",
|
|
49
54
|
required: false,
|
|
@@ -79,132 +84,69 @@ export default class All extends Command {
|
|
|
79
84
|
async run() {
|
|
80
85
|
const { flags } = await this.parse(All);
|
|
81
86
|
try {
|
|
82
|
-
const { domain, exclude, issueKeyFileName, issueKeyFolder, maxCount, only, projectIdOrKey } = flags;
|
|
83
|
-
const apiKey = flags.apiKey
|
|
87
|
+
const { domain, downloadAttachments, exclude, issueKeyFileName, issueKeyFolder, maxCount, only, projectIdOrKey } = flags;
|
|
88
|
+
const apiKey = resolveApiKey(flags.apiKey, () => this.log('環境変数 BACKLOG_API_KEY からAPIキーを使用します')) ??
|
|
89
|
+
this.error(API_KEY_NOT_FOUND_MESSAGE);
|
|
84
90
|
const outputRoot = flags.output || './backlog-data';
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Determine targets based on flags
|
|
90
|
-
let targets;
|
|
91
|
-
if (only) {
|
|
92
|
-
targets = only.split(',');
|
|
93
|
-
}
|
|
94
|
-
else if (exclude) {
|
|
95
|
-
const excludeTargets = exclude.split(',');
|
|
96
|
-
const allTargets = ['issues', 'wiki', 'documents'];
|
|
97
|
-
targets = allTargets.filter((target) => !excludeTargets.includes(target));
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
targets = ['issues', 'wiki', 'documents'];
|
|
101
|
-
}
|
|
102
|
-
// Validate targets
|
|
103
|
-
const validTargets = ['issues', 'wiki', 'documents'];
|
|
104
|
-
const inputTargets = only ? only.split(',') : exclude ? exclude.split(',') : [];
|
|
105
|
-
for (const target of inputTargets) {
|
|
106
|
-
if (!validTargets.includes(target)) {
|
|
107
|
-
this.error(`Invalid target '${target}'. Available targets are: ${validTargets.join(', ')}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// Check if any targets remain after exclusion
|
|
111
|
-
if (targets.length === 0) {
|
|
112
|
-
this.error('No targets remaining after exclusion. Please specify valid targets to export.');
|
|
113
|
-
}
|
|
114
|
-
// 出力ディレクトリの作成
|
|
115
|
-
await createOutputDirectory(outputRoot);
|
|
116
|
-
// プロジェクトキーからプロジェクトIDを取得
|
|
117
|
-
const projectId = await validateAndGetProjectId(domain, projectIdOrKey, apiKey);
|
|
118
|
-
this.log(`プロジェクトID: ${projectId} を使用します`);
|
|
119
|
-
if (targets.includes('issues')) {
|
|
120
|
-
// 課題の出力ディレクトリ
|
|
121
|
-
const issueOutput = path.join(outputRoot, 'issues');
|
|
122
|
-
await createOutputDirectory(issueOutput);
|
|
123
|
-
// 課題フォルダに設定ファイルを保存
|
|
124
|
-
await updateSettings(issueOutput, {
|
|
125
|
-
apiKey,
|
|
126
|
-
domain,
|
|
127
|
-
folderType: FolderType.ISSUE,
|
|
128
|
-
issueKeyFileName,
|
|
129
|
-
issueKeyFolder,
|
|
130
|
-
outputDir: issueOutput,
|
|
131
|
-
projectIdOrKey,
|
|
132
|
-
});
|
|
133
|
-
// 課題の取得と保存
|
|
134
|
-
this.log('課題の取得を開始します...');
|
|
135
|
-
await downloadIssues(this, {
|
|
136
|
-
apiKey,
|
|
137
|
-
count: maxCount,
|
|
138
|
-
domain,
|
|
139
|
-
issueKeyFileName,
|
|
140
|
-
issueKeyFolder,
|
|
141
|
-
outputDir: issueOutput,
|
|
142
|
-
projectId,
|
|
143
|
-
});
|
|
144
|
-
// 課題フォルダの最終更新日時を更新
|
|
145
|
-
await updateSettings(issueOutput, {
|
|
146
|
-
lastUpdated: new Date().toISOString(),
|
|
147
|
-
});
|
|
148
|
-
this.log('課題の取得が完了しました');
|
|
149
|
-
}
|
|
150
|
-
if (targets.includes('wiki')) {
|
|
151
|
-
// Wikiの出力ディレクトリ
|
|
152
|
-
const wikiOutput = path.join(outputRoot, 'wiki');
|
|
153
|
-
await createOutputDirectory(wikiOutput);
|
|
154
|
-
// Wikiフォルダに設定ファイルを保存
|
|
155
|
-
await updateSettings(wikiOutput, {
|
|
156
|
-
apiKey,
|
|
157
|
-
domain,
|
|
158
|
-
folderType: FolderType.WIKI,
|
|
159
|
-
outputDir: wikiOutput,
|
|
160
|
-
projectIdOrKey,
|
|
161
|
-
});
|
|
162
|
-
// Wikiの取得と保存
|
|
163
|
-
this.log('Wikiの取得を開始します...');
|
|
164
|
-
await downloadWikis(this, {
|
|
165
|
-
apiKey,
|
|
166
|
-
domain,
|
|
167
|
-
outputDir: wikiOutput,
|
|
168
|
-
projectIdOrKey,
|
|
169
|
-
});
|
|
170
|
-
// Wikiフォルダの最終更新日時を更新
|
|
171
|
-
await updateSettings(wikiOutput, {
|
|
172
|
-
lastUpdated: new Date().toISOString(),
|
|
173
|
-
});
|
|
174
|
-
this.log('Wikiの取得が完了しました');
|
|
175
|
-
}
|
|
176
|
-
if (targets.includes('documents')) {
|
|
177
|
-
// ドキュメントの出力ディレクトリ
|
|
178
|
-
const documentOutput = path.join(outputRoot, 'documents');
|
|
179
|
-
await createOutputDirectory(documentOutput);
|
|
180
|
-
// ドキュメントフォルダに設定ファイルを保存
|
|
181
|
-
await updateSettings(documentOutput, {
|
|
182
|
-
apiKey,
|
|
183
|
-
domain,
|
|
184
|
-
folderType: FolderType.DOCUMENT,
|
|
185
|
-
outputDir: documentOutput,
|
|
186
|
-
projectIdOrKey,
|
|
187
|
-
});
|
|
188
|
-
// ドキュメントの取得と保存
|
|
189
|
-
this.log('ドキュメントの取得を開始します...');
|
|
190
|
-
await downloadDocuments(this, {
|
|
191
|
-
apiKey,
|
|
192
|
-
domain,
|
|
193
|
-
outputDir: documentOutput,
|
|
194
|
-
projectId,
|
|
195
|
-
projectIdOrKey,
|
|
196
|
-
});
|
|
197
|
-
// ドキュメントフォルダの最終更新日時を更新
|
|
198
|
-
await updateSettings(documentOutput, {
|
|
199
|
-
lastUpdated: new Date().toISOString(),
|
|
200
|
-
});
|
|
201
|
-
this.log('ドキュメントの取得が完了しました');
|
|
91
|
+
let targets = this.determineTargets(only, exclude);
|
|
92
|
+
// --only / --exclude 未指定の対話実行では、Wiki・ドキュメントのどちらを取得するか選択できるようにする
|
|
93
|
+
if (!only && !exclude && isInteractiveStdin()) {
|
|
94
|
+
targets = applyContentSelection(targets, await this.promptContentSelection());
|
|
202
95
|
}
|
|
203
|
-
this.log('
|
|
96
|
+
this.log(`取得対象: ${targets.join(', ')}`);
|
|
97
|
+
const logger = { log: (message) => this.log(message), warn: (message) => this.warn(message) };
|
|
98
|
+
const repositories = createBacklogRepositories({
|
|
99
|
+
apiKey,
|
|
100
|
+
domain,
|
|
101
|
+
onRateLimitExceeded: (waitSeconds) => this.log(`レート制限の上限に達しました。${waitSeconds}秒待機します...`),
|
|
102
|
+
});
|
|
103
|
+
await exportAll({ ...repositories, logger }, {
|
|
104
|
+
apiKey,
|
|
105
|
+
domain,
|
|
106
|
+
downloadAttachments,
|
|
107
|
+
issueKeyFileName,
|
|
108
|
+
issueKeyFolder,
|
|
109
|
+
maxCount,
|
|
110
|
+
outputRoot,
|
|
111
|
+
projectIdOrKey,
|
|
112
|
+
targets,
|
|
113
|
+
});
|
|
204
114
|
}
|
|
205
115
|
catch (error) {
|
|
206
116
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
207
117
|
this.error(`データの取得に失敗しました: ${errorMessage}`);
|
|
208
118
|
}
|
|
209
119
|
}
|
|
120
|
+
determineTargets(only, exclude) {
|
|
121
|
+
if (only && exclude) {
|
|
122
|
+
this.error('Cannot use both --only and --exclude flags together. Please use only one.');
|
|
123
|
+
}
|
|
124
|
+
// 指定された値の検証
|
|
125
|
+
const inputTargets = only ? only.split(',') : exclude ? exclude.split(',') : [];
|
|
126
|
+
for (const target of inputTargets) {
|
|
127
|
+
if (!VALID_TARGETS.includes(target)) {
|
|
128
|
+
this.error(`Invalid target '${target}'. Available targets are: ${VALID_TARGETS.join(', ')}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
let targets;
|
|
132
|
+
if (only) {
|
|
133
|
+
targets = only.split(',');
|
|
134
|
+
}
|
|
135
|
+
else if (exclude) {
|
|
136
|
+
const excludeTargets = exclude.split(',');
|
|
137
|
+
targets = VALID_TARGETS.filter((target) => !excludeTargets.includes(target));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
targets = [...VALID_TARGETS];
|
|
141
|
+
}
|
|
142
|
+
if (targets.length === 0) {
|
|
143
|
+
this.error('No targets remaining after exclusion. Please specify valid targets to export.');
|
|
144
|
+
}
|
|
145
|
+
return targets;
|
|
146
|
+
}
|
|
147
|
+
async promptContentSelection() {
|
|
148
|
+
this.log('BacklogのWikiとドキュメントのどちらを取得しますか?(BacklogはWikiからドキュメントへの移行を予定しています)');
|
|
149
|
+
this.log(' [1] 両方(デフォルト) [2] Wikiのみ [3] ドキュメントのみ');
|
|
150
|
+
return parseContentSelection(await readLine());
|
|
151
|
+
}
|
|
210
152
|
}
|
|
@@ -5,6 +5,7 @@ export default class Document extends Command {
|
|
|
5
5
|
static flags: {
|
|
6
6
|
apiKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
domain: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
downloadAttachments: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
9
|
keyword: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
10
|
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
projectIdOrKey: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { createBacklogRepositories } from '../../composition/backlog-repositories.js';
|
|
3
|
+
import { exportDocuments } from '../../modules/document/use-case/export-documents.js';
|
|
4
|
+
import { FolderType } from '../../modules/settings/domain/settings.js';
|
|
5
|
+
import { updateSettings } from '../../modules/settings/repository/settings-store.js';
|
|
6
|
+
import { API_KEY_NOT_FOUND_MESSAGE, loadDotenv, resolveApiKey } from '../../shared/config/env.js';
|
|
7
|
+
import { ensureDirectory } from '../../shared/storage/markdown-store.js';
|
|
7
8
|
// .envファイルを読み込む
|
|
8
|
-
|
|
9
|
+
loadDotenv();
|
|
9
10
|
export default class Document extends Command {
|
|
10
11
|
static description = 'Backlogからドキュメントを取得してMarkdownファイルとして保存する';
|
|
11
12
|
static examples = [
|
|
@@ -28,6 +29,11 @@ export default class Document extends Command {
|
|
|
28
29
|
description: 'Backlog domain (e.g. example.backlog.jp)',
|
|
29
30
|
required: true,
|
|
30
31
|
}),
|
|
32
|
+
downloadAttachments: Flags.boolean({
|
|
33
|
+
char: 'd',
|
|
34
|
+
description: '添付ファイルもダウンロードする',
|
|
35
|
+
required: false,
|
|
36
|
+
}),
|
|
31
37
|
keyword: Flags.string({
|
|
32
38
|
description: '検索キーワード',
|
|
33
39
|
required: false,
|
|
@@ -45,26 +51,34 @@ export default class Document extends Command {
|
|
|
45
51
|
async run() {
|
|
46
52
|
const { flags } = await this.parse(Document);
|
|
47
53
|
try {
|
|
48
|
-
const { domain, keyword, projectIdOrKey } = flags;
|
|
49
|
-
const apiKey = flags.apiKey
|
|
54
|
+
const { domain, downloadAttachments, keyword, projectIdOrKey } = flags;
|
|
55
|
+
const apiKey = resolveApiKey(flags.apiKey, () => this.log('環境変数 BACKLOG_API_KEY からAPIキーを使用します')) ??
|
|
56
|
+
this.error(API_KEY_NOT_FOUND_MESSAGE);
|
|
50
57
|
const outputDir = flags.output || './backlog-documents';
|
|
58
|
+
const logger = { log: (message) => this.log(message), warn: (message) => this.warn(message) };
|
|
59
|
+
const { documentRepository, projectRepository } = createBacklogRepositories({
|
|
60
|
+
apiKey,
|
|
61
|
+
domain,
|
|
62
|
+
onRateLimitExceeded: (waitSeconds) => this.log(`レート制限の上限に達しました。${waitSeconds}秒待機します...`),
|
|
63
|
+
});
|
|
51
64
|
// 出力ディレクトリの作成
|
|
52
|
-
await
|
|
65
|
+
await ensureDirectory(outputDir);
|
|
53
66
|
// プロジェクトキーからプロジェクトIDを取得
|
|
54
|
-
const projectId = await
|
|
67
|
+
const projectId = await projectRepository.resolveProjectId(projectIdOrKey);
|
|
55
68
|
this.log(`プロジェクトID: ${projectId} を使用します`);
|
|
56
69
|
// 設定ファイルを保存
|
|
57
70
|
await updateSettings(outputDir, {
|
|
58
71
|
apiKey,
|
|
59
72
|
domain,
|
|
73
|
+
downloadAttachments,
|
|
60
74
|
folderType: FolderType.DOCUMENT,
|
|
61
75
|
outputDir,
|
|
62
76
|
projectIdOrKey,
|
|
63
77
|
});
|
|
64
78
|
// ドキュメントの取得と保存
|
|
65
|
-
await
|
|
66
|
-
apiKey,
|
|
79
|
+
await exportDocuments({ documentRepository, logger }, {
|
|
67
80
|
domain,
|
|
81
|
+
downloadAttachments,
|
|
68
82
|
keyword,
|
|
69
83
|
outputDir,
|
|
70
84
|
projectId,
|
|
@@ -5,6 +5,7 @@ export default class Issue extends Command {
|
|
|
5
5
|
static flags: {
|
|
6
6
|
apiKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
domain: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
downloadAttachments: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
9
|
issueKeyFileName: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
10
|
issueKeyFolder: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
maxCount: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { createBacklogRepositories } from '../../composition/backlog-repositories.js';
|
|
3
|
+
import { exportIssues } from '../../modules/issue/use-case/export-issues.js';
|
|
4
|
+
import { FolderType } from '../../modules/settings/domain/settings.js';
|
|
5
|
+
import { updateSettings } from '../../modules/settings/repository/settings-store.js';
|
|
6
|
+
import { API_KEY_NOT_FOUND_MESSAGE, loadDotenv, resolveApiKey } from '../../shared/config/env.js';
|
|
7
|
+
import { ensureDirectory } from '../../shared/storage/markdown-store.js';
|
|
7
8
|
// .envファイルを読み込む
|
|
8
|
-
|
|
9
|
+
loadDotenv();
|
|
9
10
|
export default class Issue extends Command {
|
|
10
11
|
static description = 'Backlogから課題を取得してMarkdownファイルとして保存する';
|
|
11
12
|
static examples = [
|
|
@@ -29,6 +30,9 @@ export default class Issue extends Command {
|
|
|
29
30
|
`,
|
|
30
31
|
`<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --issueKeyFileName --issueKeyFolder
|
|
31
32
|
課題キーでフォルダを作成し、ファイル名も課題キーにする
|
|
33
|
+
`,
|
|
34
|
+
`<%= config.bin %> <%= command.id %> --domain example.backlog.jp --projectIdOrKey PROJECT_KEY --apiKey YOUR_API_KEY --downloadAttachments
|
|
35
|
+
課題の添付ファイルもダウンロードする
|
|
32
36
|
`,
|
|
33
37
|
];
|
|
34
38
|
static flags = {
|
|
@@ -40,6 +44,11 @@ export default class Issue extends Command {
|
|
|
40
44
|
description: 'Backlog domain (e.g. example.backlog.jp)',
|
|
41
45
|
required: true,
|
|
42
46
|
}),
|
|
47
|
+
downloadAttachments: Flags.boolean({
|
|
48
|
+
char: 'd',
|
|
49
|
+
description: '課題の添付ファイルもダウンロードする',
|
|
50
|
+
required: false,
|
|
51
|
+
}),
|
|
43
52
|
issueKeyFileName: Flags.boolean({
|
|
44
53
|
description: 'ファイル名を課題キーにする',
|
|
45
54
|
required: false,
|
|
@@ -71,18 +80,26 @@ export default class Issue extends Command {
|
|
|
71
80
|
async run() {
|
|
72
81
|
const { flags } = await this.parse(Issue);
|
|
73
82
|
try {
|
|
74
|
-
const { domain, issueKeyFileName, issueKeyFolder, maxCount, projectIdOrKey, statusId } = flags;
|
|
75
|
-
const apiKey = flags.apiKey
|
|
83
|
+
const { domain, downloadAttachments, issueKeyFileName, issueKeyFolder, maxCount, projectIdOrKey, statusId } = flags;
|
|
84
|
+
const apiKey = resolveApiKey(flags.apiKey, () => this.log('環境変数 BACKLOG_API_KEY からAPIキーを使用します')) ??
|
|
85
|
+
this.error(API_KEY_NOT_FOUND_MESSAGE);
|
|
76
86
|
const outputDir = flags.output || './backlog-issues';
|
|
87
|
+
const logger = { log: (message) => this.log(message), warn: (message) => this.warn(message) };
|
|
88
|
+
const { issueRepository, projectRepository } = createBacklogRepositories({
|
|
89
|
+
apiKey,
|
|
90
|
+
domain,
|
|
91
|
+
onRateLimitExceeded: (waitSeconds) => this.log(`レート制限の上限に達しました。${waitSeconds}秒待機します...`),
|
|
92
|
+
});
|
|
77
93
|
// 出力ディレクトリの作成
|
|
78
|
-
await
|
|
94
|
+
await ensureDirectory(outputDir);
|
|
79
95
|
// プロジェクトキーからプロジェクトIDを取得
|
|
80
|
-
const projectId = await
|
|
96
|
+
const projectId = await projectRepository.resolveProjectId(projectIdOrKey);
|
|
81
97
|
this.log(`プロジェクトID: ${projectId} を使用します`);
|
|
82
98
|
// 設定ファイルを保存
|
|
83
99
|
await updateSettings(outputDir, {
|
|
84
100
|
apiKey,
|
|
85
101
|
domain,
|
|
102
|
+
downloadAttachments,
|
|
86
103
|
folderType: FolderType.ISSUE,
|
|
87
104
|
issueKeyFileName,
|
|
88
105
|
issueKeyFolder,
|
|
@@ -90,10 +107,10 @@ export default class Issue extends Command {
|
|
|
90
107
|
projectIdOrKey,
|
|
91
108
|
});
|
|
92
109
|
// 課題の取得と保存
|
|
93
|
-
await
|
|
94
|
-
apiKey,
|
|
110
|
+
await exportIssues({ issueRepository, logger }, {
|
|
95
111
|
count: maxCount,
|
|
96
112
|
domain,
|
|
113
|
+
downloadAttachments,
|
|
97
114
|
issueKeyFileName,
|
|
98
115
|
issueKeyFolder,
|
|
99
116
|
outputDir,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Prune 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
|
+
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
projectIdOrKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
private confirmPrune;
|
|
16
|
+
}
|