@d-zero/backlog-projects 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/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/assign.d.ts +11 -0
- package/dist/assign.js +67 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +74 -0
- package/dist/define.d.ts +3 -0
- package/dist/define.js +9 -0
- package/dist/get-backlog-project-id-from-url.d.ts +18 -0
- package/dist/get-backlog-project-id-from-url.js +40 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +1 -0
- package/package.json +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 D-ZERO Co., Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `@d-zero/packbacklog-projects`
|
|
2
|
+
|
|
3
|
+
## 使い方
|
|
4
|
+
|
|
5
|
+
### プロジェクトアサイン
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx @d-zero/backlog-projects --assign
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
プロンプトに従って入力してください。
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
? BacklogのプロジェクトURLを入力してください ›
|
|
15
|
+
? カテゴリーを入力してください(ガントチャートなどで管理しやすくなります) ›
|
|
16
|
+
? 「窓口」を選択してください …
|
|
17
|
+
? 「ディレクション」を選択してください …
|
|
18
|
+
? 「情報設計」を選択してください …
|
|
19
|
+
? 「ビジュアルデザイン」を選択してください …
|
|
20
|
+
? 「フロントエンド」を選択してください …
|
|
21
|
+
? 「システム」を選択してください …
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
逐次、課題が登録されます。
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
︙
|
|
28
|
+
API_TEST-1190 メールフォーム 情報設計・項目定義 @DZ平尾
|
|
29
|
+
API_TEST-1191 メールフォーム 自動返信メール文章作成 @DZ平尾
|
|
30
|
+
API_TEST-1192 デモサイト+開発環境準備 @DZ平尾
|
|
31
|
+
API_TEST-1193 トップページ デザイン @DZ平尾
|
|
32
|
+
API_TEST-1194 トップページ デザイン クライアント確認 @DZ平尾
|
|
33
|
+
API_TEST-1195 トップページ デザイン 戻し修正 @DZ平尾
|
|
34
|
+
API_TEST-1196 下層ページ デザイン @DZ平尾
|
|
35
|
+
︙
|
|
36
|
+
|
|
37
|
+
🔗 https://xxxxx.backlog.jp/gantt/API_TEST?span=6&scale=days&grouping=3&startDate=2024/01/01
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## `.env`ファイル
|
|
41
|
+
|
|
42
|
+
`.env`ファイルを作成し、以下の内容を記述してください。
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
BACKLOG_HOST=xxxxx.backlog.jp
|
|
46
|
+
BACKLOG_APIKEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
47
|
+
NOTION_TOKEN=secret_xxxxxxxxxxxxxx
|
|
48
|
+
```
|
package/dist/assign.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Role } from './types.js';
|
|
2
|
+
import type { Backlog } from 'backlog-js';
|
|
3
|
+
import type { Project, User } from 'backlog-js/dist/types/entity.js';
|
|
4
|
+
type Params = {
|
|
5
|
+
backlogProject: Project.Project;
|
|
6
|
+
assignedUsers: Record<Role, User.User>;
|
|
7
|
+
backlogCategory?: string;
|
|
8
|
+
log?: (message: string) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare function assign(backlog: Backlog, params: Params): Promise<void>;
|
|
11
|
+
export {};
|
package/dist/assign.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { NotionDB } from '@d-zero/notion';
|
|
2
|
+
import { skipHolydayPeriod } from '@d-zero/shared/skip-holyday-period';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
import { PROJECT_COMMON_TASK_LIST_NOTION_URL } from './define.js';
|
|
5
|
+
export async function assign(backlog, params) {
|
|
6
|
+
if (!process.env.NOTION_TOKEN) {
|
|
7
|
+
throw new Error('NOTION_TOKEN is not defined. Please set it in .env file');
|
|
8
|
+
}
|
|
9
|
+
const project = params.backlogProject;
|
|
10
|
+
const assignedUsers = params.assignedUsers;
|
|
11
|
+
const categoryName = params.backlogCategory?.trim() ?? null;
|
|
12
|
+
const db = new NotionDB(process.env.NOTION_TOKEN, PROJECT_COMMON_TASK_LIST_NOTION_URL);
|
|
13
|
+
const data = await db.getTable({
|
|
14
|
+
sorts: [
|
|
15
|
+
{
|
|
16
|
+
property: '順番',
|
|
17
|
+
direction: 'ascending',
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
if (!data['課題名']) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const categories = await backlog.getCategories(project.id);
|
|
25
|
+
const issueTypes = await backlog.getIssueTypes(project.id);
|
|
26
|
+
const issueTypeTask = issueTypes.find((t) => t.name === 'タスク') ?? issueTypes[0];
|
|
27
|
+
if (!issueTypeTask) {
|
|
28
|
+
throw new Error('issueTypes is not found');
|
|
29
|
+
}
|
|
30
|
+
const category = categoryName
|
|
31
|
+
? categories.find((c) => c.name === categoryName) ??
|
|
32
|
+
(await backlog.postCategories(project.id, { name: categoryName }))
|
|
33
|
+
: null;
|
|
34
|
+
const now = dayjs();
|
|
35
|
+
let i = 0;
|
|
36
|
+
let currentDate = now.clone();
|
|
37
|
+
let interval = 0;
|
|
38
|
+
for (const value of data['課題名']) {
|
|
39
|
+
const days = +(data['工数(人日)']?.[i] || 1) - 1;
|
|
40
|
+
const { startDate, dueDate } = skipHolydayPeriod(currentDate, currentDate.add(days, 'day'));
|
|
41
|
+
const start = startDate.format('YYYY-MM-DD');
|
|
42
|
+
const due = dueDate.format('YYYY-MM-DD');
|
|
43
|
+
const role = data['担当']?.[i];
|
|
44
|
+
if (!role) {
|
|
45
|
+
throw new Error('role not found');
|
|
46
|
+
}
|
|
47
|
+
const assignedUser = assignedUsers[role];
|
|
48
|
+
const result = await backlog.postIssue({
|
|
49
|
+
projectId: project.id,
|
|
50
|
+
summary: value,
|
|
51
|
+
priorityId: 3,
|
|
52
|
+
issueTypeId: issueTypeTask.id,
|
|
53
|
+
startDate: start,
|
|
54
|
+
dueDate: due,
|
|
55
|
+
assigneeId: assignedUser.id,
|
|
56
|
+
categoryId: category ? [category.id] : [],
|
|
57
|
+
});
|
|
58
|
+
const realDays = dueDate.diff(startDate, 'day');
|
|
59
|
+
params.log?.(`${result.issueKey} ${result.summary} @${assignedUser.name}`);
|
|
60
|
+
interval = +(data['前工程との間隔(人日)']?.[i] || 0) + 1;
|
|
61
|
+
currentDate = currentDate.add(realDays + interval, 'day');
|
|
62
|
+
i++;
|
|
63
|
+
}
|
|
64
|
+
// https://xxx.backlog.jp/gantt/API_TEST?span=6&scale=days&grouping=3&startDate=2024/01/01
|
|
65
|
+
const resultUrl = `${backlog.webAppBaseURL}/gantt/${project.projectKey}?span=6&scale=days&grouping=3&startDate=${now.format('YYYY/MM/DD')}`;
|
|
66
|
+
params.log?.(`🔗 ${resultUrl}`);
|
|
67
|
+
}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Backlog } from 'backlog-js';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
import Enquirer from 'enquirer';
|
|
5
|
+
import minimist from 'minimist';
|
|
6
|
+
import { assign } from './assign.js';
|
|
7
|
+
import { roles } from './define.js';
|
|
8
|
+
import { getBacklogProjectIdFromUrl } from './get-backlog-project-id-from-url.js';
|
|
9
|
+
dotenv.config();
|
|
10
|
+
const cli = minimist(process.argv.slice(2), {
|
|
11
|
+
alias: {
|
|
12
|
+
a: 'assign',
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
if (!process.env.BACKLOG_HOST) {
|
|
16
|
+
throw new Error('BACKLOG_HOST is not defined. Please set it in .env file');
|
|
17
|
+
}
|
|
18
|
+
if (!process.env.BACKLOG_APIKEY) {
|
|
19
|
+
throw new Error('BACKLOG_APIKEY is not defined. Please set it in .env file');
|
|
20
|
+
}
|
|
21
|
+
const backlog = new Backlog({
|
|
22
|
+
host: process.env.BACKLOG_HOST,
|
|
23
|
+
apiKey: process.env.BACKLOG_APIKEY,
|
|
24
|
+
});
|
|
25
|
+
if (cli.assign) {
|
|
26
|
+
const users = await backlog.getUsers();
|
|
27
|
+
const dzUsers = users.filter((u) => u.mailAddress.endsWith('@d-zero.co.jp'));
|
|
28
|
+
const { projectId } = await Enquirer.prompt({
|
|
29
|
+
name: 'projectId',
|
|
30
|
+
message: 'BacklogのプロジェクトURLを入力してください',
|
|
31
|
+
type: 'input',
|
|
32
|
+
required: true,
|
|
33
|
+
result(value) {
|
|
34
|
+
return getBacklogProjectIdFromUrl(value);
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
const project = await backlog.getProject(projectId);
|
|
38
|
+
const { category } = await Enquirer.prompt({
|
|
39
|
+
name: 'category',
|
|
40
|
+
message: 'カテゴリーを入力してください(ガントチャートなどで管理しやすくなります)',
|
|
41
|
+
type: 'input',
|
|
42
|
+
required: false,
|
|
43
|
+
});
|
|
44
|
+
const assignedUsers = {};
|
|
45
|
+
for (const role of roles) {
|
|
46
|
+
const { userName } = await Enquirer.prompt({
|
|
47
|
+
name: 'userName',
|
|
48
|
+
message: `「${role}」を選択してください`,
|
|
49
|
+
type: 'autocomplete',
|
|
50
|
+
required: true,
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
limit: 5,
|
|
53
|
+
choices: dzUsers.map((u) => ({
|
|
54
|
+
name: u.name,
|
|
55
|
+
message: u.mailAddress,
|
|
56
|
+
hint: u.name,
|
|
57
|
+
value: u.name,
|
|
58
|
+
})),
|
|
59
|
+
});
|
|
60
|
+
const user = dzUsers.find((u) => u.name === userName);
|
|
61
|
+
if (!user) {
|
|
62
|
+
throw new Error(`User ${userName} is not found`);
|
|
63
|
+
}
|
|
64
|
+
assignedUsers[role] = user;
|
|
65
|
+
}
|
|
66
|
+
await assign(backlog, {
|
|
67
|
+
backlogProject: project,
|
|
68
|
+
backlogCategory: category || undefined,
|
|
69
|
+
assignedUsers: assignedUsers,
|
|
70
|
+
log(message) {
|
|
71
|
+
process.stdout.write(message + '\n');
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
package/dist/define.d.ts
ADDED
package/dist/define.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the project ID from a Backlog URL.
|
|
3
|
+
*
|
|
4
|
+
* Ex:
|
|
5
|
+
* - https://xxx.backlog.jp/projects/API_TEST
|
|
6
|
+
* - https://xxx.backlog.jp/add/API_TEST
|
|
7
|
+
* - https://xxx.backlog.jp/find/API_TEST?projectId=123
|
|
8
|
+
* - https://xxx.backlog.jp/board/API_TEST
|
|
9
|
+
* - https://xxx.backlog.jp/gantt/API_TEST
|
|
10
|
+
* - https://xxx.backlog.jp/wiki/API_TEST/Home
|
|
11
|
+
* - https://xxx.backlog.jp/file/API_TEST
|
|
12
|
+
* - https://xxx.backlog.jp/git/API_TEST
|
|
13
|
+
* - https://xxx.backlog.jp/EditProject.action?project.id=123
|
|
14
|
+
*
|
|
15
|
+
* @param url
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
export declare function getBacklogProjectIdFromUrl(url: string): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the project ID from a Backlog URL.
|
|
3
|
+
*
|
|
4
|
+
* Ex:
|
|
5
|
+
* - https://xxx.backlog.jp/projects/API_TEST
|
|
6
|
+
* - https://xxx.backlog.jp/add/API_TEST
|
|
7
|
+
* - https://xxx.backlog.jp/find/API_TEST?projectId=123
|
|
8
|
+
* - https://xxx.backlog.jp/board/API_TEST
|
|
9
|
+
* - https://xxx.backlog.jp/gantt/API_TEST
|
|
10
|
+
* - https://xxx.backlog.jp/wiki/API_TEST/Home
|
|
11
|
+
* - https://xxx.backlog.jp/file/API_TEST
|
|
12
|
+
* - https://xxx.backlog.jp/git/API_TEST
|
|
13
|
+
* - https://xxx.backlog.jp/EditProject.action?project.id=123
|
|
14
|
+
*
|
|
15
|
+
* @param url
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
export function getBacklogProjectIdFromUrl(url) {
|
|
19
|
+
try {
|
|
20
|
+
const urlObj = new URL(url);
|
|
21
|
+
const pathname = urlObj.pathname;
|
|
22
|
+
const paths = pathname.split('/').filter((p) => p !== '');
|
|
23
|
+
const projectId = paths[1];
|
|
24
|
+
if (!projectId) {
|
|
25
|
+
const searchParams = urlObj.searchParams;
|
|
26
|
+
const projectId = searchParams.get('project.id');
|
|
27
|
+
if (!projectId) {
|
|
28
|
+
throw new Error(`Project ID not found in URL: ${url}`);
|
|
29
|
+
}
|
|
30
|
+
return projectId;
|
|
31
|
+
}
|
|
32
|
+
return projectId;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof TypeError) {
|
|
36
|
+
return url;
|
|
37
|
+
}
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Role = '窓口' | 'ディレクション' | '情報設計' | 'ビジュアルデザイン' | 'フロントエンド' | 'システム';
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@d-zero/backlog-projects",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A manipulating Backlog projects library",
|
|
5
|
+
"author": "D-ZERO",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"private": false,
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=22.1.0"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"bin": {
|
|
16
|
+
"backlog-projects": "./dist/cli.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"clean": "tsc --build --clean"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@d-zero/notion": "1.0.0",
|
|
27
|
+
"@d-zero/shared": "0.2.0",
|
|
28
|
+
"backlog-js": "0.13.1",
|
|
29
|
+
"dayjs": "1.11.11",
|
|
30
|
+
"dotenv": "16.4.5",
|
|
31
|
+
"enquirer": "2.4.1",
|
|
32
|
+
"minimist": "1.2.8"
|
|
33
|
+
},
|
|
34
|
+
"gitHead": "db479312eb17afb95785928ae632814897943ba1"
|
|
35
|
+
}
|