@devory/github 0.3.1 → 0.4.6
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/dist/index.js +140 -0
- package/package.json +4 -4
- package/src/index.ts +14 -7
package/dist/index.js
CHANGED
|
@@ -40,9 +40,13 @@ __export(src_exports, {
|
|
|
40
40
|
canCreatePr: () => canCreatePr,
|
|
41
41
|
commitType: () => commitType,
|
|
42
42
|
createPr: () => createPr,
|
|
43
|
+
extractAcceptanceCriteria: () => extractAcceptanceCriteria,
|
|
44
|
+
fetchGitHubIssue: () => fetchGitHubIssue,
|
|
45
|
+
filterPlanningComments: () => filterPlanningComments,
|
|
43
46
|
getRepoSlug: () => getRepoSlug,
|
|
44
47
|
getRunId: () => getRunId,
|
|
45
48
|
isGitHubActions: () => isGitHubActions,
|
|
49
|
+
isGitHubIssueUrl: () => isGitHubIssueUrl,
|
|
46
50
|
prCreateBlockedReason: () => prCreateBlockedReason,
|
|
47
51
|
setEnv: () => setEnv,
|
|
48
52
|
setOutput: () => setOutput,
|
|
@@ -271,6 +275,138 @@ function createPr(meta, taskBody, options) {
|
|
|
271
275
|
const prUrl = (result.stdout ?? "").trim();
|
|
272
276
|
return { ok: true, prUrl: prUrl || void 0 };
|
|
273
277
|
}
|
|
278
|
+
|
|
279
|
+
// src/lib/issue-content-extractor.ts
|
|
280
|
+
var AC_SECTION_HEADER = /^##\s*(acceptance criteria|ac|definition of done|dod)\s*$/i;
|
|
281
|
+
var NEXT_SECTION_HEADER = /^##\s+/i;
|
|
282
|
+
function cleanBullet(line) {
|
|
283
|
+
const trimmed = line.trim();
|
|
284
|
+
if (!/^[-*]\s+/.test(trimmed))
|
|
285
|
+
return null;
|
|
286
|
+
const cleaned = trimmed.replace(/^[-*]\s+/, "").trim();
|
|
287
|
+
return cleaned.length > 0 ? cleaned : null;
|
|
288
|
+
}
|
|
289
|
+
function isBadgeOnly(body) {
|
|
290
|
+
const normalized = body.trim();
|
|
291
|
+
if (normalized === "")
|
|
292
|
+
return true;
|
|
293
|
+
return /^\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\)$/i.test(normalized);
|
|
294
|
+
}
|
|
295
|
+
function extractAcceptanceCriteria(body) {
|
|
296
|
+
if (!body || typeof body !== "string")
|
|
297
|
+
return [];
|
|
298
|
+
const lines = body.split(/\r?\n/);
|
|
299
|
+
let inAcSection = false;
|
|
300
|
+
const items = [];
|
|
301
|
+
for (const line of lines) {
|
|
302
|
+
if (!inAcSection && AC_SECTION_HEADER.test(line.trim())) {
|
|
303
|
+
inAcSection = true;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (inAcSection && NEXT_SECTION_HEADER.test(line.trim())) {
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
if (inAcSection) {
|
|
310
|
+
const bullet = cleanBullet(line);
|
|
311
|
+
if (bullet)
|
|
312
|
+
items.push(bullet);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return items;
|
|
316
|
+
}
|
|
317
|
+
function filterPlanningComments(comments) {
|
|
318
|
+
return comments.filter((comment) => {
|
|
319
|
+
const login = (comment.user?.login ?? "").toLowerCase();
|
|
320
|
+
if (login.endsWith("[bot]"))
|
|
321
|
+
return false;
|
|
322
|
+
const body = typeof comment.body === "string" ? comment.body : "";
|
|
323
|
+
if (isBadgeOnly(body))
|
|
324
|
+
return false;
|
|
325
|
+
return true;
|
|
326
|
+
}).map((comment) => typeof comment.body === "string" ? comment.body.trim() : "").filter((body) => body.length > 0);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/lib/issue-adapter.ts
|
|
330
|
+
var GITHUB_ISSUE_URL = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)(?:\/)?(?:\?.*)?(?:#.*)?$/i;
|
|
331
|
+
function normalizeDescription(body) {
|
|
332
|
+
if (typeof body !== "string")
|
|
333
|
+
return "";
|
|
334
|
+
return body.replace(/<[^>]+>/g, " ").replace(/\r\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
335
|
+
}
|
|
336
|
+
function parseIssueUrl(url) {
|
|
337
|
+
const match = url.trim().match(GITHUB_ISSUE_URL);
|
|
338
|
+
if (!match)
|
|
339
|
+
return null;
|
|
340
|
+
return {
|
|
341
|
+
owner: match[1],
|
|
342
|
+
repo: match[2],
|
|
343
|
+
number: match[3]
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function isGitHubIssueUrl(url) {
|
|
347
|
+
return parseIssueUrl(url) !== null;
|
|
348
|
+
}
|
|
349
|
+
async function fetchGitHubIssue(url) {
|
|
350
|
+
const parsed = parseIssueUrl(url);
|
|
351
|
+
if (!parsed) {
|
|
352
|
+
throw new Error(`GitHub issue URL is invalid: ${url}`);
|
|
353
|
+
}
|
|
354
|
+
const token = process.env.GITHUB_TOKEN;
|
|
355
|
+
if (typeof token !== "string" || token.trim() === "") {
|
|
356
|
+
throw new Error("GITHUB_TOKEN is required to fetch GitHub issues");
|
|
357
|
+
}
|
|
358
|
+
const apiUrl = `https://api.github.com/repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}`;
|
|
359
|
+
const response = await fetch(apiUrl, {
|
|
360
|
+
headers: {
|
|
361
|
+
Authorization: `Bearer ${token}`,
|
|
362
|
+
Accept: "application/vnd.github+json",
|
|
363
|
+
"User-Agent": "devory-intake"
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
if (response.status === 404) {
|
|
367
|
+
throw new Error(`GitHub issue not found: ${url}`);
|
|
368
|
+
}
|
|
369
|
+
if (response.status === 401) {
|
|
370
|
+
throw new Error("GitHub authentication failed \u2014 check GITHUB_TOKEN");
|
|
371
|
+
}
|
|
372
|
+
if (!response.ok) {
|
|
373
|
+
throw new Error(`GitHub issue fetch failed (${response.status})`);
|
|
374
|
+
}
|
|
375
|
+
const payload = await response.json();
|
|
376
|
+
let planningComments = [];
|
|
377
|
+
if (typeof payload.comments_url === "string" && payload.comments_url.trim() !== "") {
|
|
378
|
+
try {
|
|
379
|
+
const commentsResponse = await fetch(payload.comments_url, {
|
|
380
|
+
headers: {
|
|
381
|
+
Authorization: `Bearer ${token}`,
|
|
382
|
+
Accept: "application/vnd.github+json",
|
|
383
|
+
"User-Agent": "devory-intake"
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
if (commentsResponse.ok) {
|
|
387
|
+
const commentsPayload = await commentsResponse.json();
|
|
388
|
+
planningComments = filterPlanningComments(commentsPayload);
|
|
389
|
+
}
|
|
390
|
+
} catch {
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const normalizedBody = normalizeDescription(payload.body);
|
|
394
|
+
const acceptanceCriteria = extractAcceptanceCriteria(normalizedBody);
|
|
395
|
+
const description = planningComments.length > 0 ? `${normalizedBody}
|
|
396
|
+
|
|
397
|
+
Planning comments:
|
|
398
|
+
${planningComments.map((entry) => `- ${entry}`).join("\n")}` : normalizedBody;
|
|
399
|
+
return {
|
|
400
|
+
source: "github-issue",
|
|
401
|
+
key: `${parsed.owner}/${parsed.repo}#${parsed.number}`,
|
|
402
|
+
url: payload.html_url ?? url,
|
|
403
|
+
title: typeof payload.title === "string" && payload.title.trim() !== "" ? payload.title.trim() : `Issue ${parsed.number}`,
|
|
404
|
+
description,
|
|
405
|
+
acceptance_criteria: acceptanceCriteria,
|
|
406
|
+
labels: Array.isArray(payload.labels) ? payload.labels.map((entry) => typeof entry?.name === "string" ? entry.name.trim() : "").filter((entry) => entry !== "") : [],
|
|
407
|
+
repo: `${parsed.owner}/${parsed.repo}`
|
|
408
|
+
};
|
|
409
|
+
}
|
|
274
410
|
// Annotate the CommonJS export names for ESM import in node:
|
|
275
411
|
0 && (module.exports = {
|
|
276
412
|
appendStepSummary,
|
|
@@ -283,9 +419,13 @@ function createPr(meta, taskBody, options) {
|
|
|
283
419
|
canCreatePr,
|
|
284
420
|
commitType,
|
|
285
421
|
createPr,
|
|
422
|
+
extractAcceptanceCriteria,
|
|
423
|
+
fetchGitHubIssue,
|
|
424
|
+
filterPlanningComments,
|
|
286
425
|
getRepoSlug,
|
|
287
426
|
getRunId,
|
|
288
427
|
isGitHubActions,
|
|
428
|
+
isGitHubIssueUrl,
|
|
289
429
|
prCreateBlockedReason,
|
|
290
430
|
setEnv,
|
|
291
431
|
setOutput,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devory/github",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Devory GitHub integration
|
|
3
|
+
"version": "0.4.6",
|
|
4
|
+
"description": "Devory GitHub integration — branch naming, PR helpers, and GitHub Actions support",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/devoryai/devory"
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"test": "tsx --test src/test/branch-helpers.test.ts src/test/pr-helpers.test.ts src/test/action-helpers.test.ts"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@devory/cli": "0.
|
|
26
|
-
"@devory/core": "0.
|
|
25
|
+
"@devory/cli": "0.4.6",
|
|
26
|
+
"@devory/core": "0.4.6"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"esbuild": "^0.20.0",
|
package/src/index.ts
CHANGED
|
@@ -13,8 +13,8 @@ export {
|
|
|
13
13
|
buildBranchName,
|
|
14
14
|
branchPrefix,
|
|
15
15
|
slugify,
|
|
16
|
-
} from "./lib/branch-helpers.
|
|
17
|
-
export type { BranchResult } from "./lib/branch-helpers.
|
|
16
|
+
} from "./lib/branch-helpers.ts";
|
|
17
|
+
export type { BranchResult } from "./lib/branch-helpers.ts";
|
|
18
18
|
|
|
19
19
|
// ── PR helpers ──────────────────────────────────────────────────────────────
|
|
20
20
|
export {
|
|
@@ -23,8 +23,8 @@ export {
|
|
|
23
23
|
buildPrMetadata,
|
|
24
24
|
commitType,
|
|
25
25
|
taskScope,
|
|
26
|
-
} from "./lib/pr-helpers.
|
|
27
|
-
export type { PrMetadata } from "./lib/pr-helpers.
|
|
26
|
+
} from "./lib/pr-helpers.ts";
|
|
27
|
+
export type { PrMetadata } from "./lib/pr-helpers.ts";
|
|
28
28
|
|
|
29
29
|
// ── GitHub Actions helpers ──────────────────────────────────────────────────
|
|
30
30
|
export {
|
|
@@ -35,7 +35,7 @@ export {
|
|
|
35
35
|
isGitHubActions,
|
|
36
36
|
getRunId,
|
|
37
37
|
getRepoSlug,
|
|
38
|
-
} from "./lib/action-helpers.
|
|
38
|
+
} from "./lib/action-helpers.ts";
|
|
39
39
|
|
|
40
40
|
// ── PR creation (gated) ──────────────────────────────────────────────────────
|
|
41
41
|
export {
|
|
@@ -43,5 +43,12 @@ export {
|
|
|
43
43
|
prCreateBlockedReason,
|
|
44
44
|
buildGhCreateArgs,
|
|
45
45
|
createPr,
|
|
46
|
-
} from "./lib/pr-create.
|
|
47
|
-
export type { PrCreateOptions, PrCreateResult } from "./lib/pr-create.
|
|
46
|
+
} from "./lib/pr-create.ts";
|
|
47
|
+
export type { PrCreateOptions, PrCreateResult } from "./lib/pr-create.ts";
|
|
48
|
+
|
|
49
|
+
// ── External intake adapters ────────────────────────────────────────────────
|
|
50
|
+
export { fetchGitHubIssue, isGitHubIssueUrl } from "./lib/issue-adapter.ts";
|
|
51
|
+
export {
|
|
52
|
+
extractAcceptanceCriteria,
|
|
53
|
+
filterPlanningComments,
|
|
54
|
+
} from "./lib/issue-content-extractor.ts";
|