-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
16a4192
commit a230b82
Showing
8 changed files
with
276 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import { describe, beforeEach, afterEach, vi, expect, it, Mock } from "vitest"; | ||
import { DandoriTask } from "@dandori/core"; | ||
import { generateDandoriTrelloCards } from "../index"; | ||
import { runPromisesSequentially } from "@dandori/libs"; | ||
import { TrelloClient } from "../trello/client"; | ||
|
||
vi.mock("../trello/client", () => { | ||
const TrelloClient = vi.fn(); | ||
TrelloClient.prototype = { | ||
getLists: vi.fn(() => [ | ||
{ | ||
id: "1", | ||
name: "TODO", | ||
}, | ||
{ | ||
id: "2", | ||
name: "DOING", | ||
}, | ||
{ | ||
id: "3", | ||
name: "done", | ||
}, | ||
]), | ||
createCard: vi.fn(), | ||
}; | ||
return { TrelloClient }; | ||
}); | ||
|
||
vi.mock("@dandori/libs", () => { | ||
return { | ||
runPromisesSequentially: vi.fn((runPromises, _runningLogPrefix) => | ||
Promise.all(runPromises.map((runPromise: () => any) => runPromise())), | ||
), | ||
checkApiKey: vi.fn(), | ||
}; | ||
}); | ||
|
||
const mockRunPromisesSequentially = runPromisesSequentially as Mock; | ||
|
||
describe("generateDandoriTrelloCards", () => { | ||
let client: TrelloClient; | ||
|
||
const todoWithStatus = "TODO"; | ||
const noStatus = "DOING"; | ||
const doneWithStatusButInvalidTrelloListName = "DONE"; | ||
|
||
const tasks: DandoriTask[] = [ | ||
{ | ||
id: "1", | ||
name: todoWithStatus, | ||
status: "todo", | ||
fromTaskIdList: [], | ||
}, | ||
{ | ||
id: "2", | ||
name: noStatus, | ||
fromTaskIdList: ["1"], | ||
}, | ||
{ | ||
id: "3", | ||
name: doneWithStatusButInvalidTrelloListName, | ||
status: "done", | ||
fromTaskIdList: ["2"], | ||
}, | ||
]; | ||
const boardId = "boardId"; | ||
|
||
const findPagePropertiesMockParam = (taskName: string) => { | ||
const params = (client.createCard as Mock).mock.calls.flat(); | ||
return params.find(({ name }) => name === taskName); | ||
}; | ||
|
||
beforeEach(() => { | ||
client = new TrelloClient("key", "token"); | ||
}); | ||
|
||
afterEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
describe("with status.todo mapping", () => { | ||
beforeEach(async () => { | ||
await generateDandoriTrelloCards(tasks, { | ||
boardId, | ||
trelloListPropertiesMap: { | ||
"status.todo": todoWithStatus, | ||
}, | ||
}); | ||
}); | ||
|
||
it("runPromisesSequentially called with creating pages log", () => { | ||
expect(mockRunPromisesSequentially.mock.calls[0][1]).toBe( | ||
"Creating Trello Cards", | ||
); | ||
}); | ||
|
||
it("called valid arguments", () => { | ||
expect(findPagePropertiesMockParam(todoWithStatus)).toMatchObject({ | ||
name: todoWithStatus, | ||
listId: "1", | ||
}); | ||
}); | ||
}); | ||
|
||
describe("with status.doing mapping", () => { | ||
beforeEach(async () => { | ||
await generateDandoriTrelloCards(tasks, { | ||
boardId, | ||
trelloListPropertiesMap: { | ||
"status.doing": noStatus, | ||
}, | ||
}); | ||
}); | ||
|
||
it("no called valid arguments", () => { | ||
expect(findPagePropertiesMockParam(noStatus)).toBeUndefined(); | ||
}); | ||
}); | ||
|
||
describe("with status.done mapping", () => { | ||
beforeEach(async () => { | ||
await generateDandoriTrelloCards(tasks, { | ||
boardId, | ||
trelloListPropertiesMap: { | ||
"status.done": doneWithStatusButInvalidTrelloListName, | ||
}, | ||
}); | ||
}); | ||
|
||
it("no called valid arguments", () => { | ||
expect( | ||
findPagePropertiesMockParam(doneWithStatusButInvalidTrelloListName), | ||
).toBeUndefined(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from "./miro"; | ||
export * from "./notion"; | ||
export * from "./trello"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
type ListResponse = { | ||
id: string; | ||
name: string; | ||
closed: boolean; | ||
pos: number; | ||
softLimit: string; | ||
idBoard: string; | ||
subscribed: boolean; | ||
limits: { | ||
attachments: { | ||
perBoard: any; | ||
}; | ||
}; | ||
}; | ||
|
||
export class TrelloClient { | ||
private readonly apiKey: string; | ||
private readonly apiToken: string; | ||
|
||
constructor(apiKey: string, apiToken: string) { | ||
this.apiKey = apiKey; | ||
this.apiToken = apiToken; | ||
} | ||
|
||
getLists(boardId: string): Promise<ListResponse[]> { | ||
return fetch( | ||
`https://api.trello.com/1/boards/${boardId}/lists?key=${this.apiKey}&token=${this.apiToken}`, | ||
).then((res) => res.json()); | ||
} | ||
|
||
createCard(param: { listId: string; name: string }): Promise<void> { | ||
return fetch( | ||
`https://api.trello.com/1/cards?key=${this.apiKey}&token=${this.apiToken}&idList=${param.listId}&name=${param.name}`, | ||
{ | ||
method: "POST", | ||
}, | ||
).then((res) => res.json()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./trello"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { DandoriTask, DandoriTaskStatus } from "@dandori/core"; | ||
import { checkApiKey, runPromisesSequentially } from "@dandori/libs"; | ||
import { TrelloClient } from "./client"; | ||
|
||
type TrelloListPropertiesMap = | ||
| { | ||
"status.todo": string; | ||
"status.doing"?: string; | ||
"status.done"?: string; | ||
} | ||
| { | ||
"status.todo"?: string; | ||
"status.doing": string; | ||
"status.done"?: string; | ||
} | ||
| { | ||
"status.todo"?: string; | ||
"status.doing"?: string; | ||
"status.done": string; | ||
}; | ||
|
||
export type GenerateDandoriTrelloCardsOptions = { | ||
boardId: string; | ||
apiKey?: string; | ||
apiToken?: string; | ||
trelloListPropertiesMap: TrelloListPropertiesMap; | ||
}; | ||
|
||
const targetName = "trello"; | ||
|
||
export async function generateDandoriTrelloCards( | ||
tasks: DandoriTask[], | ||
options: GenerateDandoriTrelloCardsOptions, | ||
): Promise<void> { | ||
const key = checkApiKey( | ||
`${targetName} api key`, | ||
process.env.TRELLO_API_KEY, | ||
options.apiKey, | ||
); | ||
const token = checkApiKey( | ||
`${targetName} api token`, | ||
process.env.TRELLO_API_TOKEN, | ||
options.apiToken, | ||
); | ||
const trello = new TrelloClient(key, token); | ||
const lists = await trello.getLists(options.boardId); | ||
const { trelloListPropertiesMap } = options; | ||
const statusNames = [ | ||
trelloListPropertiesMap["status.todo"], | ||
trelloListPropertiesMap["status.doing"], | ||
trelloListPropertiesMap["status.done"], | ||
]; | ||
const listIds = statusNames.map((statusName) => { | ||
const list = lists.find((list) => list.name === statusName); | ||
if (list) { | ||
return list.id; | ||
} | ||
}); | ||
const dandoriTaskListIdMap: Record<DandoriTaskStatus, string | undefined> = { | ||
todo: listIds[0], | ||
doing: listIds[1], | ||
done: listIds[2], | ||
}; | ||
const createCards: (() => Promise<void>)[] = []; | ||
tasks.forEach((task) => { | ||
const taskStatus = task.status; | ||
if (!taskStatus) { | ||
return; | ||
} | ||
const listId = dandoriTaskListIdMap[taskStatus]; | ||
if (!listId) { | ||
return; | ||
} | ||
createCards.push(() => trello.createCard({ listId, name: task.name })); | ||
}); | ||
await runPromisesSequentially(createCards, "Creating Trello Cards"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { loadEnvFile } from "@dandori/libs"; | ||
import { tasks } from "./mock"; | ||
import { generateDandoriTrelloCards } from "../src/trello/trello"; | ||
|
||
// set environment variables like access token | ||
loadEnvFile(); | ||
|
||
// set trello settings | ||
const boardId = ""; | ||
const trelloListPropertiesMap = { | ||
"status.todo": "", | ||
"status.doing": "", | ||
"status.done": "", | ||
}; | ||
|
||
await generateDandoriTrelloCards(tasks, { | ||
boardId, | ||
trelloListPropertiesMap, | ||
}); |