Skip to content

Commit a84956b

Browse files
committed
refactor(compose): extract core plugin logic to enable addition of compose capabilities
for #2
1 parent 0adbb1d commit a84956b

File tree

3 files changed

+118
-108
lines changed

3 files changed

+118
-108
lines changed

src/compose-unique-issue.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Octokit } from "@octokit/core";
2+
import {
3+
CreateOrUpdateUniqueIssueOptionsT,
4+
CreateOrUpdateUniqueIssueResponseT,
5+
} from "./types";
6+
7+
const OCTOKIT_UNIQUE_ISSUE_ID_PREFIX = "octokit-unique-issue id=";
8+
9+
export async function composeUniqueIssue(
10+
octokit: Octokit,
11+
options: CreateOrUpdateUniqueIssueOptionsT,
12+
): Promise<CreateOrUpdateUniqueIssueResponseT> {
13+
const {
14+
owner,
15+
repo,
16+
identifier,
17+
close_previous = false,
18+
body,
19+
...rest
20+
} = options;
21+
22+
if (!identifier) {
23+
throw Object.assign(new Error("identifier is required."), {
24+
name: "MissingIdentifierError",
25+
});
26+
}
27+
28+
const term = `${OCTOKIT_UNIQUE_ISSUE_ID_PREFIX}"${identifier}"`;
29+
30+
// MDAST compatible comment marker; see https://github.com/syntax-tree/mdast-comment-marker
31+
const commentMarker = `<!-- ${term} -->`;
32+
33+
const {
34+
data: { items, total_count },
35+
} = await octokit.request("GET /search/issues", {
36+
q: `"${term}" is:issue is:open repo:${owner}/${repo}`,
37+
});
38+
39+
if (total_count === 1 && !close_previous) {
40+
const response = await octokit.request(
41+
"PATCH /repos/{owner}/{repo}/issues/{issue_number}",
42+
{
43+
owner,
44+
repo,
45+
issue_number: items[0].number,
46+
...(body !== undefined ? { body: body + `\n\n${commentMarker}` } : {}),
47+
...rest,
48+
},
49+
);
50+
51+
return {
52+
...response,
53+
updated: true,
54+
closed_issues: [],
55+
};
56+
}
57+
58+
if (total_count > 1 && !close_previous) {
59+
throw Object.assign(
60+
new Error("More than 1 issue was found with identifier."),
61+
{
62+
identifier,
63+
issue_numbers: items.map((item) => item.number).join(),
64+
name: "DuplicateIssueError",
65+
},
66+
);
67+
}
68+
69+
for (const item of items) {
70+
await octokit.request("PATCH /repos/{owner}/{repo}/issues/{issue_number}", {
71+
owner,
72+
repo,
73+
issue_number: item.number,
74+
state: "closed",
75+
});
76+
}
77+
78+
const response = await octokit.request("POST /repos/{owner}/{repo}/issues", {
79+
owner,
80+
repo,
81+
body: body !== undefined ? body + `\n\n${commentMarker}` : commentMarker,
82+
...rest,
83+
});
84+
85+
return {
86+
...response,
87+
updated: false,
88+
closed_issues: items.map((item) => item),
89+
};
90+
}

src/index.ts

Lines changed: 6 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,18 @@
11
import { Octokit } from "@octokit/core";
2+
import {
3+
CreateOrUpdateUniqueIssueOptionsT,
4+
CreateOrUpdateUniqueIssueResponseT,
5+
} from "./types";
26
import { VERSION } from "./version";
3-
import { Endpoints } from "@octokit/types";
7+
import { composeUniqueIssue } from "./compose-unique-issue";
48

5-
const OCTOKIT_UNIQUE_ISSUE_ID_PREFIX = "octokit-unique-issue id=";
6-
7-
type CreateOrUpdateUniqueIssueOptionsT =
8-
Endpoints["POST /repos/{owner}/{repo}/issues"]["parameters"] & {
9-
identifier: string;
10-
close_previous?: boolean;
11-
};
12-
13-
type CreatedIssueResponseT =
14-
Endpoints["POST /repos/{owner}/{repo}/issues"]["response"] & {
15-
updated: false;
16-
closed_issues: Endpoints["GET /search/issues"]["response"]["data"]["items"];
17-
};
18-
type UpdatedIssueResponseT =
19-
Endpoints["PATCH /repos/{owner}/{repo}/issues/{issue_number}"]["response"] & {
20-
updated: true;
21-
closed_issues: [...[]];
22-
};
23-
type CreateOrUpdateUniqueIssueResponseT =
24-
| CreatedIssueResponseT
25-
| UpdatedIssueResponseT;
269

2710
export function uniqueIssue(octokit: Octokit) {
2811
return {
2912
async createOrUpdateUniqueIssue(
3013
options: CreateOrUpdateUniqueIssueOptionsT,
3114
): Promise<CreateOrUpdateUniqueIssueResponseT> {
32-
const {
33-
owner,
34-
repo,
35-
identifier,
36-
close_previous = false,
37-
body,
38-
...rest
39-
} = options;
40-
41-
if (!identifier) {
42-
throw Object.assign(new Error("identifier is required."), {
43-
name: "MissingIdentifierError",
44-
});
45-
}
46-
47-
const term = `${OCTOKIT_UNIQUE_ISSUE_ID_PREFIX}"${identifier}"`;
48-
49-
// MDAST compatible comment marker; see https://github.com/syntax-tree/mdast-comment-marker
50-
const commentMarker = `<!-- ${term} -->`;
51-
52-
const {
53-
data: { items, total_count },
54-
} = await octokit.request("GET /search/issues", {
55-
q: `"${term}" is:issue is:open repo:${owner}/${repo}`,
56-
});
57-
58-
if (total_count === 1 && !close_previous) {
59-
const response = await octokit.request(
60-
"PATCH /repos/{owner}/{repo}/issues/{issue_number}",
61-
{
62-
owner,
63-
repo,
64-
issue_number: items[0].number,
65-
...(body !== undefined
66-
? { body: body + `\n\n${commentMarker}` }
67-
: {}),
68-
...rest,
69-
},
70-
);
71-
72-
return {
73-
...response,
74-
updated: true,
75-
closed_issues: [],
76-
};
77-
}
78-
79-
if (total_count > 1 && !close_previous) {
80-
throw Object.assign(
81-
new Error("More than 1 issue was found with identifier."),
82-
{
83-
identifier,
84-
issue_numbers: items.map((item) => item.number).join(),
85-
name: "DuplicateIssueError",
86-
},
87-
);
88-
}
89-
90-
for (const item of items) {
91-
await octokit.request(
92-
"PATCH /repos/{owner}/{repo}/issues/{issue_number}",
93-
{
94-
owner,
95-
repo,
96-
issue_number: item.number,
97-
state: "closed",
98-
},
99-
);
100-
}
101-
102-
const response = await octokit.request(
103-
"POST /repos/{owner}/{repo}/issues",
104-
{
105-
owner,
106-
repo,
107-
body:
108-
body !== undefined ? body + `\n\n${commentMarker}` : commentMarker,
109-
...rest,
110-
},
111-
);
112-
113-
return {
114-
...response,
115-
updated: false,
116-
closed_issues: items.map((item) => item),
117-
};
15+
return composeUniqueIssue(octokit, options);
11816
},
11917
};
12018
}

src/types.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Endpoints } from "@octokit/types";
2+
3+
type CreatedIssueResponseT =
4+
Endpoints["POST /repos/{owner}/{repo}/issues"]["response"] & {
5+
updated: false;
6+
closed_issues: Endpoints["GET /search/issues"]["response"]["data"]["items"];
7+
};
8+
type UpdatedIssueResponseT =
9+
Endpoints["PATCH /repos/{owner}/{repo}/issues/{issue_number}"]["response"] & {
10+
updated: true;
11+
closed_issues: [...[]];
12+
};
13+
14+
export type CreateOrUpdateUniqueIssueOptionsT =
15+
Endpoints["POST /repos/{owner}/{repo}/issues"]["parameters"] & {
16+
identifier: string;
17+
close_previous?: boolean;
18+
};
19+
20+
export type CreateOrUpdateUniqueIssueResponseT =
21+
| CreatedIssueResponseT
22+
| UpdatedIssueResponseT;

0 commit comments

Comments
 (0)