Skip to content

Commit e581c3d

Browse files
blombardgr2m
andauthored
feat: support iteration fields (#95)
Following the issue #94 I created, here is the start of solution. I'm not used to Typescript so sorry if I make rookie mistakes. :) Closes #94 --------- Co-authored-by: Gregor Martynus <[email protected]>
1 parent 221c849 commit e581c3d

File tree

10 files changed

+537
-5
lines changed

10 files changed

+537
-5
lines changed

api/lib/item-fields-nodes-to-fields-map.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ function projectFieldValueNodeToValue(projectField, node) {
4343
return projectField.optionsById[node.optionId];
4444
case "ProjectV2ItemFieldTextValue":
4545
return node.text;
46-
// TODO: implement iteration fields
47-
// case "ProjectV2ItemFieldIterationValue":
48-
// return null;
46+
case "ProjectV2ItemFieldIterationValue":
47+
return node.title;
4948
}
5049
}

api/lib/project-fields-nodes-to-fields-map.js

+22
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,28 @@ export function projectFieldsNodesToFieldsMap(state, project, nodes) {
129129
);
130130
}
131131

132+
// If the field is of type "Iteration", then the `configuration` property will be set.
133+
if (node.configuration) {
134+
acc[userFieldNameAlias].optionsById = node.configuration.iterations.concat(node.configuration.completedIterations).reduce(
135+
(acc, option) => {
136+
return {
137+
...acc,
138+
[option.id]: option.title,
139+
};
140+
},
141+
{}
142+
);
143+
acc[userFieldNameAlias].optionsByValue = node.configuration.iterations.concat(node.configuration.completedIterations).reduce(
144+
(acc, option) => {
145+
return {
146+
...acc,
147+
[option.title]: option.id,
148+
};
149+
},
150+
{}
151+
);
152+
}
153+
132154
return acc;
133155
},
134156
optionalFields

api/lib/queries.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@ const queryProjectNodes = `
5353
... on ProjectV2IterationField {
5454
configuration {
5555
iterations {
56+
id
5657
title
5758
duration
5859
startDate
5960
}
6061
completedIterations {
62+
id
6163
title
6264
duration
6365
startDate
@@ -186,7 +188,7 @@ export const getProjectItemsPaginatedQuery = `
186188
${queryItemFieldNodes}
187189
}
188190
}
189-
}
191+
}
190192
}
191193
}
192194
}

index.d.ts

+18
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,24 @@ export type ProjectFieldNode = {
241241
* `options` is only set on `ProjectV2SingleSelectField`
242242
*/
243243
options?: { id: string; name: string }[];
244+
245+
/**
246+
* `configuration` is only set on `ProjectV2IterationField`
247+
*/
248+
configuration?: {
249+
iterations: {
250+
id: string;
251+
title: string;
252+
duration: number;
253+
startDate: string;
254+
}[];
255+
completedIterations: {
256+
id: string;
257+
title: string;
258+
duration: number;
259+
startDate: string;
260+
}[];
261+
};
244262
};
245263

246264
export type ProjectField =

test/recorded/api.items.update-iteration/fixtures.json

+410
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// @ts-check
2+
3+
/**
4+
* Prepare state in order to record fixtures for test.js. Returns array of arguments that will be passed
5+
* passed as `test(project, ...arguments)`.
6+
*
7+
* @param {import("@octokit/openapi-types").components["schemas"]["repository"]} repository
8+
* @param {import("@octokit/core").Octokit} octokit
9+
* @param {import("../../..").default<{text: string, number: number, date: string, singleSelect: "One" | "Two" | "Three", iteration: "Iteration 1" | "Iteration 2" | "Iteration 3"}>} project
10+
* @returns {Promise<[string]>}
11+
*/
12+
export async function prepare(repository, octokit, project) {
13+
// create a test issue
14+
const { data: issue } = await octokit.request(
15+
"POST /repos/{owner}/{repo}/issues",
16+
{
17+
owner: repository.owner.login,
18+
repo: repository.name,
19+
title: "Issue",
20+
body: "This is a test issue",
21+
}
22+
);
23+
24+
// add issue to project
25+
const item = await project.items.add(issue.node_id, {
26+
text: "text",
27+
number: "1",
28+
date: new Date("2020-02-02").toISOString(),
29+
singleSelect: "One",
30+
iteration: "Iteration 1",
31+
});
32+
33+
return [item.id];
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @ts-check
2+
3+
import GitHubProject from "../../../index.js";
4+
5+
/**
6+
* @param {import("../../../").default} defaultTestProject
7+
* @param {string} [itemId]
8+
*/
9+
export function test(defaultTestProject, itemId = "PVTI_1") {
10+
const project = new GitHubProject({
11+
owner: defaultTestProject.owner,
12+
number: defaultTestProject.number,
13+
octokit: defaultTestProject.octokit,
14+
fields: {
15+
iteration: "Iteration",
16+
},
17+
});
18+
19+
return project.items.update(itemId, { iteration: "Iteration 2" });
20+
}

test/recorded/api.items.update-with-emoji-alias/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ export function test(defaultTestingProject, itemId = "PVTI_1") {
1515
"🎯text": "Text",
1616
},
1717
});
18-
18+
1919
return project.items.update(itemId, { "🎯text": "new text" });
2020
}

test/snapshots/recorded.test.js.md

+27
Original file line numberDiff line numberDiff line change
@@ -7177,6 +7177,33 @@ Generated by [AVA](https://avajs.dev).
71777177
type: 'ISSUE',
71787178
}
71797179

7180+
## api.items.update-iteration
7181+
7182+
> Snapshot 1
7183+
7184+
{
7185+
content: {
7186+
assignees: [],
7187+
closed: false,
7188+
closedAt: undefined,
7189+
createdAt: '2022-02-02T12:00:00Z',
7190+
databaseId: 1001,
7191+
id: 'I_1',
7192+
labels: [],
7193+
milestone: null,
7194+
number: 1,
7195+
repository: 'test-repository',
7196+
title: 'Issue',
7197+
url: 'https://github.com/github-project-fixtures/test-repository/issues/1',
7198+
},
7199+
fields: {
7200+
iteration: 'Iteration 2',
7201+
},
7202+
id: 'PVTI_1',
7203+
isArchived: false,
7204+
type: 'ISSUE',
7205+
}
7206+
71807207
## api.items.update-not-found
71817208

71827209
> Snapshot 1

test/snapshots/recorded.test.js.snap

50 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)