@bretwardjames/ghp-core 0.1.1 → 0.1.3
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.cjs +84 -117
- package/dist/index.d.cts +43 -117
- package/dist/index.d.ts +43 -117
- package/dist/index.js +80 -115
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,6 @@ __export(index_exports, {
|
|
|
30
30
|
buildRepoUrl: () => buildRepoUrl,
|
|
31
31
|
checkoutBranch: () => checkoutBranch,
|
|
32
32
|
createBranch: () => createBranch,
|
|
33
|
-
createInMemoryAdapter: () => createInMemoryAdapter,
|
|
34
33
|
detectRepository: () => detectRepository,
|
|
35
34
|
fetchOrigin: () => fetchOrigin,
|
|
36
35
|
generateBranchName: () => generateBranchName,
|
|
@@ -41,11 +40,14 @@ __export(index_exports, {
|
|
|
41
40
|
getRepositoryRoot: () => getRepositoryRoot,
|
|
42
41
|
hasUncommittedChanges: () => hasUncommittedChanges,
|
|
43
42
|
isGitRepository: () => isGitRepository,
|
|
43
|
+
parseBranchLink: () => parseBranchLink,
|
|
44
44
|
parseGitHubUrl: () => parseGitHubUrl,
|
|
45
45
|
parseIssueUrl: () => parseIssueUrl,
|
|
46
46
|
pullLatest: () => pullLatest,
|
|
47
47
|
queries: () => queries_exports,
|
|
48
|
-
|
|
48
|
+
removeBranchLinkFromBody: () => removeBranchLinkFromBody,
|
|
49
|
+
sanitizeForBranchName: () => sanitizeForBranchName,
|
|
50
|
+
setBranchLinkInBody: () => setBranchLinkInBody
|
|
49
51
|
});
|
|
50
52
|
module.exports = __toCommonJS(index_exports);
|
|
51
53
|
|
|
@@ -75,6 +77,7 @@ __export(queries_exports, {
|
|
|
75
77
|
REPOSITORY_ID_QUERY: () => REPOSITORY_ID_QUERY,
|
|
76
78
|
REPOSITORY_PROJECTS_QUERY: () => REPOSITORY_PROJECTS_QUERY,
|
|
77
79
|
UPDATE_ISSUE_BODY_MUTATION: () => UPDATE_ISSUE_BODY_MUTATION,
|
|
80
|
+
UPDATE_ISSUE_MUTATION: () => UPDATE_ISSUE_MUTATION,
|
|
78
81
|
UPDATE_ISSUE_TYPE_MUTATION: () => UPDATE_ISSUE_TYPE_MUTATION,
|
|
79
82
|
UPDATE_ITEM_FIELD_MUTATION: () => UPDATE_ITEM_FIELD_MUTATION,
|
|
80
83
|
UPDATE_ITEM_STATUS_MUTATION: () => UPDATE_ITEM_STATUS_MUTATION,
|
|
@@ -430,6 +433,15 @@ var UPDATE_ISSUE_BODY_MUTATION = `
|
|
|
430
433
|
}
|
|
431
434
|
}
|
|
432
435
|
`;
|
|
436
|
+
var UPDATE_ISSUE_MUTATION = `
|
|
437
|
+
mutation($issueId: ID!, $title: String, $body: String) {
|
|
438
|
+
updateIssue(input: { id: $issueId, title: $title, body: $body }) {
|
|
439
|
+
issue {
|
|
440
|
+
id
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
`;
|
|
433
445
|
|
|
434
446
|
// src/github-api.ts
|
|
435
447
|
function createAuthError(message, type, details) {
|
|
@@ -968,141 +980,94 @@ var GitHubAPI = class {
|
|
|
968
980
|
return false;
|
|
969
981
|
}
|
|
970
982
|
}
|
|
983
|
+
/**
|
|
984
|
+
* Update an issue's title and/or body
|
|
985
|
+
*/
|
|
986
|
+
async updateIssue(repo, issueNumber, updates) {
|
|
987
|
+
if (!this.graphqlWithAuth) throw new Error("Not authenticated");
|
|
988
|
+
try {
|
|
989
|
+
const issueResponse = await this.graphqlWithAuth(ISSUE_FOR_UPDATE_QUERY, {
|
|
990
|
+
owner: repo.owner,
|
|
991
|
+
name: repo.name,
|
|
992
|
+
number: issueNumber
|
|
993
|
+
});
|
|
994
|
+
if (!issueResponse.repository.issue) {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
await this.graphqlWithAuth(UPDATE_ISSUE_MUTATION, {
|
|
998
|
+
issueId: issueResponse.repository.issue.id,
|
|
999
|
+
title: updates.title,
|
|
1000
|
+
body: updates.body
|
|
1001
|
+
});
|
|
1002
|
+
return true;
|
|
1003
|
+
} catch {
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
971
1007
|
};
|
|
972
1008
|
|
|
973
1009
|
// src/branch-linker.ts
|
|
974
|
-
var
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
return
|
|
1010
|
+
var BRANCH_LINK_PATTERN = /<!--\s*ghp-branch:\s*(.+?)\s*-->/;
|
|
1011
|
+
function parseBranchLink(body) {
|
|
1012
|
+
if (!body) return null;
|
|
1013
|
+
const match = body.match(BRANCH_LINK_PATTERN);
|
|
1014
|
+
return match ? match[1].trim() : null;
|
|
1015
|
+
}
|
|
1016
|
+
function setBranchLinkInBody(body, branch) {
|
|
1017
|
+
const currentBody = body || "";
|
|
1018
|
+
const tag = `<!-- ghp-branch: ${branch} -->`;
|
|
1019
|
+
if (BRANCH_LINK_PATTERN.test(currentBody)) {
|
|
1020
|
+
return currentBody.replace(BRANCH_LINK_PATTERN, tag);
|
|
1021
|
+
} else {
|
|
1022
|
+
return currentBody.trim() + "\n\n" + tag;
|
|
985
1023
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1024
|
+
}
|
|
1025
|
+
function removeBranchLinkFromBody(body) {
|
|
1026
|
+
if (!body) return "";
|
|
1027
|
+
return body.replace(BRANCH_LINK_PATTERN, "").trim();
|
|
1028
|
+
}
|
|
1029
|
+
var BranchLinker = class {
|
|
1030
|
+
api;
|
|
1031
|
+
constructor(api) {
|
|
1032
|
+
this.api = api;
|
|
994
1033
|
}
|
|
995
1034
|
/**
|
|
996
1035
|
* Create a link between a branch and an issue.
|
|
997
|
-
*
|
|
1036
|
+
* Stores the link as a hidden comment in the issue body.
|
|
998
1037
|
*/
|
|
999
|
-
async link(
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
);
|
|
1004
|
-
filtered.push({
|
|
1005
|
-
branch,
|
|
1006
|
-
issueNumber,
|
|
1007
|
-
issueTitle,
|
|
1008
|
-
itemId,
|
|
1009
|
-
repo,
|
|
1010
|
-
linkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1011
|
-
});
|
|
1012
|
-
await this.saveLinks(filtered);
|
|
1038
|
+
async link(repo, issueNumber, branch) {
|
|
1039
|
+
const details = await this.api.getIssueDetails(repo, issueNumber);
|
|
1040
|
+
if (!details) return false;
|
|
1041
|
+
const newBody = setBranchLinkInBody(details.body, branch);
|
|
1042
|
+
return this.api.updateIssueBody(repo, issueNumber, newBody);
|
|
1013
1043
|
}
|
|
1014
1044
|
/**
|
|
1015
|
-
* Remove the link
|
|
1016
|
-
* @returns true if a link was removed, false if no link existed
|
|
1045
|
+
* Remove the branch link from an issue.
|
|
1017
1046
|
*/
|
|
1018
1047
|
async unlink(repo, issueNumber) {
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
);
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
await this.saveLinks(filtered);
|
|
1027
|
-
return true;
|
|
1028
|
-
}
|
|
1029
|
-
/**
|
|
1030
|
-
* Remove the link for a branch.
|
|
1031
|
-
* @returns true if a link was removed, false if no link existed
|
|
1032
|
-
*/
|
|
1033
|
-
async unlinkBranch(repo, branch) {
|
|
1034
|
-
const links = await this.loadLinks();
|
|
1035
|
-
const filtered = links.filter(
|
|
1036
|
-
(l) => !(l.repo === repo && l.branch === branch)
|
|
1037
|
-
);
|
|
1038
|
-
if (filtered.length === links.length) {
|
|
1039
|
-
return false;
|
|
1040
|
-
}
|
|
1041
|
-
await this.saveLinks(filtered);
|
|
1042
|
-
return true;
|
|
1048
|
+
const details = await this.api.getIssueDetails(repo, issueNumber);
|
|
1049
|
+
if (!details) return false;
|
|
1050
|
+
const currentBranch = parseBranchLink(details.body);
|
|
1051
|
+
if (!currentBranch) return false;
|
|
1052
|
+
const newBody = removeBranchLinkFromBody(details.body);
|
|
1053
|
+
return this.api.updateIssueBody(repo, issueNumber, newBody);
|
|
1043
1054
|
}
|
|
1044
1055
|
/**
|
|
1045
1056
|
* Get the branch linked to an issue.
|
|
1046
1057
|
*/
|
|
1047
1058
|
async getBranchForIssue(repo, issueNumber) {
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
return
|
|
1059
|
+
const details = await this.api.getIssueDetails(repo, issueNumber);
|
|
1060
|
+
if (!details) return null;
|
|
1061
|
+
return parseBranchLink(details.body);
|
|
1051
1062
|
}
|
|
1052
1063
|
/**
|
|
1053
|
-
*
|
|
1064
|
+
* Check if an issue has a branch link.
|
|
1054
1065
|
*/
|
|
1055
|
-
async
|
|
1056
|
-
const
|
|
1057
|
-
return
|
|
1058
|
-
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Get the full link info for an issue.
|
|
1061
|
-
*/
|
|
1062
|
-
async getLinkForIssue(repo, issueNumber) {
|
|
1063
|
-
const links = await this.loadLinks();
|
|
1064
|
-
return links.find((l) => l.repo === repo && l.issueNumber === issueNumber) || null;
|
|
1065
|
-
}
|
|
1066
|
-
/**
|
|
1067
|
-
* Get all links for a repository.
|
|
1068
|
-
*/
|
|
1069
|
-
async getLinksForRepo(repo) {
|
|
1070
|
-
const links = await this.loadLinks();
|
|
1071
|
-
return links.filter((l) => l.repo === repo);
|
|
1072
|
-
}
|
|
1073
|
-
/**
|
|
1074
|
-
* Get all links.
|
|
1075
|
-
*/
|
|
1076
|
-
async getAllLinks() {
|
|
1077
|
-
return this.loadLinks();
|
|
1078
|
-
}
|
|
1079
|
-
/**
|
|
1080
|
-
* Check if a branch has a link.
|
|
1081
|
-
*/
|
|
1082
|
-
async hasLinkForBranch(repo, branch) {
|
|
1083
|
-
const link = await this.getLinkForBranch(repo, branch);
|
|
1084
|
-
return link !== null;
|
|
1085
|
-
}
|
|
1086
|
-
/**
|
|
1087
|
-
* Check if an issue has a link.
|
|
1088
|
-
*/
|
|
1089
|
-
async hasLinkForIssue(repo, issueNumber) {
|
|
1090
|
-
const link = await this.getLinkForIssue(repo, issueNumber);
|
|
1091
|
-
return link !== null;
|
|
1066
|
+
async hasLink(repo, issueNumber) {
|
|
1067
|
+
const branch = await this.getBranchForIssue(repo, issueNumber);
|
|
1068
|
+
return branch !== null;
|
|
1092
1069
|
}
|
|
1093
1070
|
};
|
|
1094
|
-
function createInMemoryAdapter() {
|
|
1095
|
-
const adapter = {
|
|
1096
|
-
links: [],
|
|
1097
|
-
load() {
|
|
1098
|
-
return [...this.links];
|
|
1099
|
-
},
|
|
1100
|
-
save(links) {
|
|
1101
|
-
this.links = [...links];
|
|
1102
|
-
}
|
|
1103
|
-
};
|
|
1104
|
-
return adapter;
|
|
1105
|
-
}
|
|
1106
1071
|
|
|
1107
1072
|
// src/git-utils.ts
|
|
1108
1073
|
var import_child_process = require("child_process");
|
|
@@ -1290,7 +1255,6 @@ async function getDefaultBranch(options = {}) {
|
|
|
1290
1255
|
buildRepoUrl,
|
|
1291
1256
|
checkoutBranch,
|
|
1292
1257
|
createBranch,
|
|
1293
|
-
createInMemoryAdapter,
|
|
1294
1258
|
detectRepository,
|
|
1295
1259
|
fetchOrigin,
|
|
1296
1260
|
generateBranchName,
|
|
@@ -1301,9 +1265,12 @@ async function getDefaultBranch(options = {}) {
|
|
|
1301
1265
|
getRepositoryRoot,
|
|
1302
1266
|
hasUncommittedChanges,
|
|
1303
1267
|
isGitRepository,
|
|
1268
|
+
parseBranchLink,
|
|
1304
1269
|
parseGitHubUrl,
|
|
1305
1270
|
parseIssueUrl,
|
|
1306
1271
|
pullLatest,
|
|
1307
1272
|
queries,
|
|
1308
|
-
|
|
1273
|
+
removeBranchLinkFromBody,
|
|
1274
|
+
sanitizeForBranchName,
|
|
1275
|
+
setBranchLinkInBody
|
|
1309
1276
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -29,25 +29,6 @@ interface AuthError extends Error {
|
|
|
29
29
|
requiredScopes?: string[];
|
|
30
30
|
ssoUrl?: string;
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Interface for persisting branch-issue links.
|
|
34
|
-
* Implement this for different storage backends (file system, VSCode state, etc.)
|
|
35
|
-
*/
|
|
36
|
-
interface StorageAdapter {
|
|
37
|
-
load(): BranchLink[] | Promise<BranchLink[]>;
|
|
38
|
-
save(links: BranchLink[]): void | Promise<void>;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* A link between a git branch and a GitHub issue/item
|
|
42
|
-
*/
|
|
43
|
-
interface BranchLink {
|
|
44
|
-
branch: string;
|
|
45
|
-
issueNumber: number;
|
|
46
|
-
issueTitle: string;
|
|
47
|
-
itemId: string;
|
|
48
|
-
repo: string;
|
|
49
|
-
linkedAt: string;
|
|
50
|
-
}
|
|
51
32
|
/**
|
|
52
33
|
* Options for git operations
|
|
53
34
|
*/
|
|
@@ -517,123 +498,63 @@ declare class GitHubAPI {
|
|
|
517
498
|
* Update an issue's body/description
|
|
518
499
|
*/
|
|
519
500
|
updateIssueBody(repo: RepoInfo, issueNumber: number, body: string): Promise<boolean>;
|
|
501
|
+
/**
|
|
502
|
+
* Update an issue's title and/or body
|
|
503
|
+
*/
|
|
504
|
+
updateIssue(repo: RepoInfo, issueNumber: number, updates: {
|
|
505
|
+
title?: string;
|
|
506
|
+
body?: string;
|
|
507
|
+
}): Promise<boolean>;
|
|
520
508
|
}
|
|
521
509
|
|
|
522
510
|
/**
|
|
523
|
-
* Branch-issue linking
|
|
524
|
-
*
|
|
525
|
-
* The BranchLinker class manages associations between git branches and GitHub issues.
|
|
526
|
-
* Storage is abstracted via the StorageAdapter interface, allowing different backends:
|
|
527
|
-
* - File system (for CLI)
|
|
528
|
-
* - VSCode workspaceState (for extensions)
|
|
529
|
-
* - In-memory (for testing)
|
|
530
|
-
*
|
|
531
|
-
* @example CLI usage with file storage:
|
|
532
|
-
* ```typescript
|
|
533
|
-
* import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
534
|
-
* import { homedir } from 'os';
|
|
535
|
-
* import { join } from 'path';
|
|
511
|
+
* Branch-issue linking stored directly in GitHub issue bodies.
|
|
536
512
|
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
513
|
+
* Links are stored as hidden HTML comments in the issue body:
|
|
514
|
+
* <!-- ghp-branch: feature/my-branch -->
|
|
539
515
|
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* if (existsSync(LINKS_FILE)) {
|
|
543
|
-
* return JSON.parse(readFileSync(LINKS_FILE, 'utf-8'));
|
|
544
|
-
* }
|
|
545
|
-
* return [];
|
|
546
|
-
* },
|
|
547
|
-
* save(links) {
|
|
548
|
-
* if (!existsSync(DATA_DIR)) {
|
|
549
|
-
* mkdirSync(DATA_DIR, { recursive: true });
|
|
550
|
-
* }
|
|
551
|
-
* writeFileSync(LINKS_FILE, JSON.stringify(links, null, 2));
|
|
552
|
-
* }
|
|
553
|
-
* };
|
|
554
|
-
*
|
|
555
|
-
* const linker = new BranchLinker(fileAdapter);
|
|
556
|
-
* ```
|
|
557
|
-
*
|
|
558
|
-
* @example VSCode usage with workspaceState:
|
|
559
|
-
* ```typescript
|
|
560
|
-
* const vscodeAdapter: StorageAdapter = {
|
|
561
|
-
* load() {
|
|
562
|
-
* return context.workspaceState.get<BranchLink[]>('branchLinks', []);
|
|
563
|
-
* },
|
|
564
|
-
* save(links) {
|
|
565
|
-
* context.workspaceState.update('branchLinks', links);
|
|
566
|
-
* }
|
|
567
|
-
* };
|
|
568
|
-
*
|
|
569
|
-
* const linker = new BranchLinker(vscodeAdapter);
|
|
570
|
-
* ```
|
|
516
|
+
* This allows branch links to be shared across all consumers (CLI, VSCode, etc.)
|
|
517
|
+
* since they're stored on GitHub itself.
|
|
571
518
|
*/
|
|
572
519
|
|
|
573
520
|
/**
|
|
574
|
-
*
|
|
521
|
+
* Parse the linked branch from an issue body.
|
|
522
|
+
*/
|
|
523
|
+
declare function parseBranchLink(body: string | null | undefined): string | null;
|
|
524
|
+
/**
|
|
525
|
+
* Set or update the branch link in an issue body.
|
|
526
|
+
* Returns the updated body string.
|
|
527
|
+
*/
|
|
528
|
+
declare function setBranchLinkInBody(body: string | null | undefined, branch: string): string;
|
|
529
|
+
/**
|
|
530
|
+
* Remove the branch link from an issue body.
|
|
531
|
+
* Returns the updated body string.
|
|
532
|
+
*/
|
|
533
|
+
declare function removeBranchLinkFromBody(body: string | null | undefined): string;
|
|
534
|
+
/**
|
|
535
|
+
* Manages branch-issue links stored in GitHub issue bodies.
|
|
575
536
|
*/
|
|
576
537
|
declare class BranchLinker {
|
|
577
|
-
private
|
|
578
|
-
constructor(
|
|
579
|
-
/**
|
|
580
|
-
* Load links from storage (handles both sync and async adapters)
|
|
581
|
-
*/
|
|
582
|
-
private loadLinks;
|
|
583
|
-
/**
|
|
584
|
-
* Save links to storage (handles both sync and async adapters)
|
|
585
|
-
*/
|
|
586
|
-
private saveLinks;
|
|
538
|
+
private api;
|
|
539
|
+
constructor(api: GitHubAPI);
|
|
587
540
|
/**
|
|
588
541
|
* Create a link between a branch and an issue.
|
|
589
|
-
*
|
|
590
|
-
*/
|
|
591
|
-
link(branch: string, issueNumber: number, issueTitle: string, itemId: string, repo: string): Promise<void>;
|
|
592
|
-
/**
|
|
593
|
-
* Remove the link for an issue.
|
|
594
|
-
* @returns true if a link was removed, false if no link existed
|
|
542
|
+
* Stores the link as a hidden comment in the issue body.
|
|
595
543
|
*/
|
|
596
|
-
|
|
544
|
+
link(repo: RepoInfo, issueNumber: number, branch: string): Promise<boolean>;
|
|
597
545
|
/**
|
|
598
|
-
* Remove the link
|
|
599
|
-
* @returns true if a link was removed, false if no link existed
|
|
546
|
+
* Remove the branch link from an issue.
|
|
600
547
|
*/
|
|
601
|
-
|
|
548
|
+
unlink(repo: RepoInfo, issueNumber: number): Promise<boolean>;
|
|
602
549
|
/**
|
|
603
550
|
* Get the branch linked to an issue.
|
|
604
551
|
*/
|
|
605
|
-
getBranchForIssue(repo:
|
|
606
|
-
/**
|
|
607
|
-
* Get the full link info for a branch.
|
|
608
|
-
*/
|
|
609
|
-
getLinkForBranch(repo: string, branch: string): Promise<BranchLink | null>;
|
|
552
|
+
getBranchForIssue(repo: RepoInfo, issueNumber: number): Promise<string | null>;
|
|
610
553
|
/**
|
|
611
|
-
*
|
|
554
|
+
* Check if an issue has a branch link.
|
|
612
555
|
*/
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* Get all links for a repository.
|
|
616
|
-
*/
|
|
617
|
-
getLinksForRepo(repo: string): Promise<BranchLink[]>;
|
|
618
|
-
/**
|
|
619
|
-
* Get all links.
|
|
620
|
-
*/
|
|
621
|
-
getAllLinks(): Promise<BranchLink[]>;
|
|
622
|
-
/**
|
|
623
|
-
* Check if a branch has a link.
|
|
624
|
-
*/
|
|
625
|
-
hasLinkForBranch(repo: string, branch: string): Promise<boolean>;
|
|
626
|
-
/**
|
|
627
|
-
* Check if an issue has a link.
|
|
628
|
-
*/
|
|
629
|
-
hasLinkForIssue(repo: string, issueNumber: number): Promise<boolean>;
|
|
556
|
+
hasLink(repo: RepoInfo, issueNumber: number): Promise<boolean>;
|
|
630
557
|
}
|
|
631
|
-
/**
|
|
632
|
-
* Create an in-memory storage adapter for testing.
|
|
633
|
-
*/
|
|
634
|
-
declare function createInMemoryAdapter(): StorageAdapter & {
|
|
635
|
-
links: BranchLink[];
|
|
636
|
-
};
|
|
637
558
|
|
|
638
559
|
/**
|
|
639
560
|
* Git utility functions for working with local repositories.
|
|
@@ -862,6 +783,10 @@ declare const UPDATE_ISSUE_TYPE_MUTATION = "\n mutation($issueId: ID!, $issue
|
|
|
862
783
|
* Mutation to update issue body/description
|
|
863
784
|
*/
|
|
864
785
|
declare const UPDATE_ISSUE_BODY_MUTATION = "\n mutation($issueId: ID!, $body: String!) {\n updateIssue(input: { id: $issueId, body: $body }) {\n issue {\n id\n }\n }\n }\n";
|
|
786
|
+
/**
|
|
787
|
+
* Mutation to update issue title and/or body
|
|
788
|
+
*/
|
|
789
|
+
declare const UPDATE_ISSUE_MUTATION = "\n mutation($issueId: ID!, $title: String, $body: String) {\n updateIssue(input: { id: $issueId, title: $title, body: $body }) {\n issue {\n id\n }\n }\n }\n";
|
|
865
790
|
|
|
866
791
|
declare const queries_ADD_COMMENT_MUTATION: typeof ADD_COMMENT_MUTATION;
|
|
867
792
|
declare const queries_ADD_LABELS_MUTATION: typeof ADD_LABELS_MUTATION;
|
|
@@ -883,12 +808,13 @@ declare const queries_REMOVE_LABELS_MUTATION: typeof REMOVE_LABELS_MUTATION;
|
|
|
883
808
|
declare const queries_REPOSITORY_ID_QUERY: typeof REPOSITORY_ID_QUERY;
|
|
884
809
|
declare const queries_REPOSITORY_PROJECTS_QUERY: typeof REPOSITORY_PROJECTS_QUERY;
|
|
885
810
|
declare const queries_UPDATE_ISSUE_BODY_MUTATION: typeof UPDATE_ISSUE_BODY_MUTATION;
|
|
811
|
+
declare const queries_UPDATE_ISSUE_MUTATION: typeof UPDATE_ISSUE_MUTATION;
|
|
886
812
|
declare const queries_UPDATE_ISSUE_TYPE_MUTATION: typeof UPDATE_ISSUE_TYPE_MUTATION;
|
|
887
813
|
declare const queries_UPDATE_ITEM_FIELD_MUTATION: typeof UPDATE_ITEM_FIELD_MUTATION;
|
|
888
814
|
declare const queries_UPDATE_ITEM_STATUS_MUTATION: typeof UPDATE_ITEM_STATUS_MUTATION;
|
|
889
815
|
declare const queries_VIEWER_QUERY: typeof VIEWER_QUERY;
|
|
890
816
|
declare namespace queries {
|
|
891
|
-
export { queries_ADD_COMMENT_MUTATION as ADD_COMMENT_MUTATION, queries_ADD_LABELS_MUTATION as ADD_LABELS_MUTATION, queries_ADD_TO_PROJECT_MUTATION as ADD_TO_PROJECT_MUTATION, queries_COLLABORATORS_QUERY as COLLABORATORS_QUERY, queries_CREATE_ISSUE_MUTATION as CREATE_ISSUE_MUTATION, queries_ISSUES_WITH_LABEL_QUERY as ISSUES_WITH_LABEL_QUERY, queries_ISSUE_AND_LABEL_QUERY as ISSUE_AND_LABEL_QUERY, queries_ISSUE_DETAILS_QUERY as ISSUE_DETAILS_QUERY, queries_ISSUE_FOR_UPDATE_QUERY as ISSUE_FOR_UPDATE_QUERY, queries_ISSUE_NODE_ID_QUERY as ISSUE_NODE_ID_QUERY, queries_ISSUE_TYPES_QUERY as ISSUE_TYPES_QUERY, queries_LABEL_EXISTS_QUERY as LABEL_EXISTS_QUERY, queries_PROJECT_FIELDS_QUERY as PROJECT_FIELDS_QUERY, queries_PROJECT_ITEMS_QUERY as PROJECT_ITEMS_QUERY, queries_PROJECT_VIEWS_QUERY as PROJECT_VIEWS_QUERY, queries_RECENT_ISSUES_QUERY as RECENT_ISSUES_QUERY, queries_REMOVE_LABELS_MUTATION as REMOVE_LABELS_MUTATION, queries_REPOSITORY_ID_QUERY as REPOSITORY_ID_QUERY, queries_REPOSITORY_PROJECTS_QUERY as REPOSITORY_PROJECTS_QUERY, queries_UPDATE_ISSUE_BODY_MUTATION as UPDATE_ISSUE_BODY_MUTATION, queries_UPDATE_ISSUE_TYPE_MUTATION as UPDATE_ISSUE_TYPE_MUTATION, queries_UPDATE_ITEM_FIELD_MUTATION as UPDATE_ITEM_FIELD_MUTATION, queries_UPDATE_ITEM_STATUS_MUTATION as UPDATE_ITEM_STATUS_MUTATION, queries_VIEWER_QUERY as VIEWER_QUERY };
|
|
817
|
+
export { queries_ADD_COMMENT_MUTATION as ADD_COMMENT_MUTATION, queries_ADD_LABELS_MUTATION as ADD_LABELS_MUTATION, queries_ADD_TO_PROJECT_MUTATION as ADD_TO_PROJECT_MUTATION, queries_COLLABORATORS_QUERY as COLLABORATORS_QUERY, queries_CREATE_ISSUE_MUTATION as CREATE_ISSUE_MUTATION, queries_ISSUES_WITH_LABEL_QUERY as ISSUES_WITH_LABEL_QUERY, queries_ISSUE_AND_LABEL_QUERY as ISSUE_AND_LABEL_QUERY, queries_ISSUE_DETAILS_QUERY as ISSUE_DETAILS_QUERY, queries_ISSUE_FOR_UPDATE_QUERY as ISSUE_FOR_UPDATE_QUERY, queries_ISSUE_NODE_ID_QUERY as ISSUE_NODE_ID_QUERY, queries_ISSUE_TYPES_QUERY as ISSUE_TYPES_QUERY, queries_LABEL_EXISTS_QUERY as LABEL_EXISTS_QUERY, queries_PROJECT_FIELDS_QUERY as PROJECT_FIELDS_QUERY, queries_PROJECT_ITEMS_QUERY as PROJECT_ITEMS_QUERY, queries_PROJECT_VIEWS_QUERY as PROJECT_VIEWS_QUERY, queries_RECENT_ISSUES_QUERY as RECENT_ISSUES_QUERY, queries_REMOVE_LABELS_MUTATION as REMOVE_LABELS_MUTATION, queries_REPOSITORY_ID_QUERY as REPOSITORY_ID_QUERY, queries_REPOSITORY_PROJECTS_QUERY as REPOSITORY_PROJECTS_QUERY, queries_UPDATE_ISSUE_BODY_MUTATION as UPDATE_ISSUE_BODY_MUTATION, queries_UPDATE_ISSUE_MUTATION as UPDATE_ISSUE_MUTATION, queries_UPDATE_ISSUE_TYPE_MUTATION as UPDATE_ISSUE_TYPE_MUTATION, queries_UPDATE_ITEM_FIELD_MUTATION as UPDATE_ITEM_FIELD_MUTATION, queries_UPDATE_ITEM_STATUS_MUTATION as UPDATE_ITEM_STATUS_MUTATION, queries_VIEWER_QUERY as VIEWER_QUERY };
|
|
892
818
|
}
|
|
893
819
|
|
|
894
|
-
export { type AssigneeInfo, type AuthError,
|
|
820
|
+
export { type AssigneeInfo, type AuthError, BranchLinker, type Collaborator, type DateFieldValue, type FieldInfo, type FieldValue, type FieldValueConnection, GitHubAPI, type GitHubAPIOptions, type GitOptions, type IssueDetails, type IssueReference, type IterationFieldValue, type LabelInfo, type NumberFieldValue, type Project, type ProjectConfig, type ProjectItem, type ProjectItemContent, type ProjectItemsQueryResponse, type ProjectV2, type ProjectV2Field, type ProjectV2Item, type ProjectV2View, type ProjectWithViews, type ProjectsQueryResponse, type RepoInfo, type SingleSelectFieldValue, type StatusField, type TextFieldValue, type TokenProvider, branchExists, buildIssueUrl, buildOrgProjectUrl, buildProjectUrl, buildPullRequestUrl, buildRepoUrl, checkoutBranch, createBranch, detectRepository, fetchOrigin, generateBranchName, getCommitsAhead, getCommitsBehind, getCurrentBranch, getDefaultBranch, getRepositoryRoot, hasUncommittedChanges, isGitRepository, parseBranchLink, parseGitHubUrl, parseIssueUrl, pullLatest, queries, removeBranchLinkFromBody, sanitizeForBranchName, setBranchLinkInBody };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,25 +29,6 @@ interface AuthError extends Error {
|
|
|
29
29
|
requiredScopes?: string[];
|
|
30
30
|
ssoUrl?: string;
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Interface for persisting branch-issue links.
|
|
34
|
-
* Implement this for different storage backends (file system, VSCode state, etc.)
|
|
35
|
-
*/
|
|
36
|
-
interface StorageAdapter {
|
|
37
|
-
load(): BranchLink[] | Promise<BranchLink[]>;
|
|
38
|
-
save(links: BranchLink[]): void | Promise<void>;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* A link between a git branch and a GitHub issue/item
|
|
42
|
-
*/
|
|
43
|
-
interface BranchLink {
|
|
44
|
-
branch: string;
|
|
45
|
-
issueNumber: number;
|
|
46
|
-
issueTitle: string;
|
|
47
|
-
itemId: string;
|
|
48
|
-
repo: string;
|
|
49
|
-
linkedAt: string;
|
|
50
|
-
}
|
|
51
32
|
/**
|
|
52
33
|
* Options for git operations
|
|
53
34
|
*/
|
|
@@ -517,123 +498,63 @@ declare class GitHubAPI {
|
|
|
517
498
|
* Update an issue's body/description
|
|
518
499
|
*/
|
|
519
500
|
updateIssueBody(repo: RepoInfo, issueNumber: number, body: string): Promise<boolean>;
|
|
501
|
+
/**
|
|
502
|
+
* Update an issue's title and/or body
|
|
503
|
+
*/
|
|
504
|
+
updateIssue(repo: RepoInfo, issueNumber: number, updates: {
|
|
505
|
+
title?: string;
|
|
506
|
+
body?: string;
|
|
507
|
+
}): Promise<boolean>;
|
|
520
508
|
}
|
|
521
509
|
|
|
522
510
|
/**
|
|
523
|
-
* Branch-issue linking
|
|
524
|
-
*
|
|
525
|
-
* The BranchLinker class manages associations between git branches and GitHub issues.
|
|
526
|
-
* Storage is abstracted via the StorageAdapter interface, allowing different backends:
|
|
527
|
-
* - File system (for CLI)
|
|
528
|
-
* - VSCode workspaceState (for extensions)
|
|
529
|
-
* - In-memory (for testing)
|
|
530
|
-
*
|
|
531
|
-
* @example CLI usage with file storage:
|
|
532
|
-
* ```typescript
|
|
533
|
-
* import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
534
|
-
* import { homedir } from 'os';
|
|
535
|
-
* import { join } from 'path';
|
|
511
|
+
* Branch-issue linking stored directly in GitHub issue bodies.
|
|
536
512
|
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
513
|
+
* Links are stored as hidden HTML comments in the issue body:
|
|
514
|
+
* <!-- ghp-branch: feature/my-branch -->
|
|
539
515
|
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* if (existsSync(LINKS_FILE)) {
|
|
543
|
-
* return JSON.parse(readFileSync(LINKS_FILE, 'utf-8'));
|
|
544
|
-
* }
|
|
545
|
-
* return [];
|
|
546
|
-
* },
|
|
547
|
-
* save(links) {
|
|
548
|
-
* if (!existsSync(DATA_DIR)) {
|
|
549
|
-
* mkdirSync(DATA_DIR, { recursive: true });
|
|
550
|
-
* }
|
|
551
|
-
* writeFileSync(LINKS_FILE, JSON.stringify(links, null, 2));
|
|
552
|
-
* }
|
|
553
|
-
* };
|
|
554
|
-
*
|
|
555
|
-
* const linker = new BranchLinker(fileAdapter);
|
|
556
|
-
* ```
|
|
557
|
-
*
|
|
558
|
-
* @example VSCode usage with workspaceState:
|
|
559
|
-
* ```typescript
|
|
560
|
-
* const vscodeAdapter: StorageAdapter = {
|
|
561
|
-
* load() {
|
|
562
|
-
* return context.workspaceState.get<BranchLink[]>('branchLinks', []);
|
|
563
|
-
* },
|
|
564
|
-
* save(links) {
|
|
565
|
-
* context.workspaceState.update('branchLinks', links);
|
|
566
|
-
* }
|
|
567
|
-
* };
|
|
568
|
-
*
|
|
569
|
-
* const linker = new BranchLinker(vscodeAdapter);
|
|
570
|
-
* ```
|
|
516
|
+
* This allows branch links to be shared across all consumers (CLI, VSCode, etc.)
|
|
517
|
+
* since they're stored on GitHub itself.
|
|
571
518
|
*/
|
|
572
519
|
|
|
573
520
|
/**
|
|
574
|
-
*
|
|
521
|
+
* Parse the linked branch from an issue body.
|
|
522
|
+
*/
|
|
523
|
+
declare function parseBranchLink(body: string | null | undefined): string | null;
|
|
524
|
+
/**
|
|
525
|
+
* Set or update the branch link in an issue body.
|
|
526
|
+
* Returns the updated body string.
|
|
527
|
+
*/
|
|
528
|
+
declare function setBranchLinkInBody(body: string | null | undefined, branch: string): string;
|
|
529
|
+
/**
|
|
530
|
+
* Remove the branch link from an issue body.
|
|
531
|
+
* Returns the updated body string.
|
|
532
|
+
*/
|
|
533
|
+
declare function removeBranchLinkFromBody(body: string | null | undefined): string;
|
|
534
|
+
/**
|
|
535
|
+
* Manages branch-issue links stored in GitHub issue bodies.
|
|
575
536
|
*/
|
|
576
537
|
declare class BranchLinker {
|
|
577
|
-
private
|
|
578
|
-
constructor(
|
|
579
|
-
/**
|
|
580
|
-
* Load links from storage (handles both sync and async adapters)
|
|
581
|
-
*/
|
|
582
|
-
private loadLinks;
|
|
583
|
-
/**
|
|
584
|
-
* Save links to storage (handles both sync and async adapters)
|
|
585
|
-
*/
|
|
586
|
-
private saveLinks;
|
|
538
|
+
private api;
|
|
539
|
+
constructor(api: GitHubAPI);
|
|
587
540
|
/**
|
|
588
541
|
* Create a link between a branch and an issue.
|
|
589
|
-
*
|
|
590
|
-
*/
|
|
591
|
-
link(branch: string, issueNumber: number, issueTitle: string, itemId: string, repo: string): Promise<void>;
|
|
592
|
-
/**
|
|
593
|
-
* Remove the link for an issue.
|
|
594
|
-
* @returns true if a link was removed, false if no link existed
|
|
542
|
+
* Stores the link as a hidden comment in the issue body.
|
|
595
543
|
*/
|
|
596
|
-
|
|
544
|
+
link(repo: RepoInfo, issueNumber: number, branch: string): Promise<boolean>;
|
|
597
545
|
/**
|
|
598
|
-
* Remove the link
|
|
599
|
-
* @returns true if a link was removed, false if no link existed
|
|
546
|
+
* Remove the branch link from an issue.
|
|
600
547
|
*/
|
|
601
|
-
|
|
548
|
+
unlink(repo: RepoInfo, issueNumber: number): Promise<boolean>;
|
|
602
549
|
/**
|
|
603
550
|
* Get the branch linked to an issue.
|
|
604
551
|
*/
|
|
605
|
-
getBranchForIssue(repo:
|
|
606
|
-
/**
|
|
607
|
-
* Get the full link info for a branch.
|
|
608
|
-
*/
|
|
609
|
-
getLinkForBranch(repo: string, branch: string): Promise<BranchLink | null>;
|
|
552
|
+
getBranchForIssue(repo: RepoInfo, issueNumber: number): Promise<string | null>;
|
|
610
553
|
/**
|
|
611
|
-
*
|
|
554
|
+
* Check if an issue has a branch link.
|
|
612
555
|
*/
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* Get all links for a repository.
|
|
616
|
-
*/
|
|
617
|
-
getLinksForRepo(repo: string): Promise<BranchLink[]>;
|
|
618
|
-
/**
|
|
619
|
-
* Get all links.
|
|
620
|
-
*/
|
|
621
|
-
getAllLinks(): Promise<BranchLink[]>;
|
|
622
|
-
/**
|
|
623
|
-
* Check if a branch has a link.
|
|
624
|
-
*/
|
|
625
|
-
hasLinkForBranch(repo: string, branch: string): Promise<boolean>;
|
|
626
|
-
/**
|
|
627
|
-
* Check if an issue has a link.
|
|
628
|
-
*/
|
|
629
|
-
hasLinkForIssue(repo: string, issueNumber: number): Promise<boolean>;
|
|
556
|
+
hasLink(repo: RepoInfo, issueNumber: number): Promise<boolean>;
|
|
630
557
|
}
|
|
631
|
-
/**
|
|
632
|
-
* Create an in-memory storage adapter for testing.
|
|
633
|
-
*/
|
|
634
|
-
declare function createInMemoryAdapter(): StorageAdapter & {
|
|
635
|
-
links: BranchLink[];
|
|
636
|
-
};
|
|
637
558
|
|
|
638
559
|
/**
|
|
639
560
|
* Git utility functions for working with local repositories.
|
|
@@ -862,6 +783,10 @@ declare const UPDATE_ISSUE_TYPE_MUTATION = "\n mutation($issueId: ID!, $issue
|
|
|
862
783
|
* Mutation to update issue body/description
|
|
863
784
|
*/
|
|
864
785
|
declare const UPDATE_ISSUE_BODY_MUTATION = "\n mutation($issueId: ID!, $body: String!) {\n updateIssue(input: { id: $issueId, body: $body }) {\n issue {\n id\n }\n }\n }\n";
|
|
786
|
+
/**
|
|
787
|
+
* Mutation to update issue title and/or body
|
|
788
|
+
*/
|
|
789
|
+
declare const UPDATE_ISSUE_MUTATION = "\n mutation($issueId: ID!, $title: String, $body: String) {\n updateIssue(input: { id: $issueId, title: $title, body: $body }) {\n issue {\n id\n }\n }\n }\n";
|
|
865
790
|
|
|
866
791
|
declare const queries_ADD_COMMENT_MUTATION: typeof ADD_COMMENT_MUTATION;
|
|
867
792
|
declare const queries_ADD_LABELS_MUTATION: typeof ADD_LABELS_MUTATION;
|
|
@@ -883,12 +808,13 @@ declare const queries_REMOVE_LABELS_MUTATION: typeof REMOVE_LABELS_MUTATION;
|
|
|
883
808
|
declare const queries_REPOSITORY_ID_QUERY: typeof REPOSITORY_ID_QUERY;
|
|
884
809
|
declare const queries_REPOSITORY_PROJECTS_QUERY: typeof REPOSITORY_PROJECTS_QUERY;
|
|
885
810
|
declare const queries_UPDATE_ISSUE_BODY_MUTATION: typeof UPDATE_ISSUE_BODY_MUTATION;
|
|
811
|
+
declare const queries_UPDATE_ISSUE_MUTATION: typeof UPDATE_ISSUE_MUTATION;
|
|
886
812
|
declare const queries_UPDATE_ISSUE_TYPE_MUTATION: typeof UPDATE_ISSUE_TYPE_MUTATION;
|
|
887
813
|
declare const queries_UPDATE_ITEM_FIELD_MUTATION: typeof UPDATE_ITEM_FIELD_MUTATION;
|
|
888
814
|
declare const queries_UPDATE_ITEM_STATUS_MUTATION: typeof UPDATE_ITEM_STATUS_MUTATION;
|
|
889
815
|
declare const queries_VIEWER_QUERY: typeof VIEWER_QUERY;
|
|
890
816
|
declare namespace queries {
|
|
891
|
-
export { queries_ADD_COMMENT_MUTATION as ADD_COMMENT_MUTATION, queries_ADD_LABELS_MUTATION as ADD_LABELS_MUTATION, queries_ADD_TO_PROJECT_MUTATION as ADD_TO_PROJECT_MUTATION, queries_COLLABORATORS_QUERY as COLLABORATORS_QUERY, queries_CREATE_ISSUE_MUTATION as CREATE_ISSUE_MUTATION, queries_ISSUES_WITH_LABEL_QUERY as ISSUES_WITH_LABEL_QUERY, queries_ISSUE_AND_LABEL_QUERY as ISSUE_AND_LABEL_QUERY, queries_ISSUE_DETAILS_QUERY as ISSUE_DETAILS_QUERY, queries_ISSUE_FOR_UPDATE_QUERY as ISSUE_FOR_UPDATE_QUERY, queries_ISSUE_NODE_ID_QUERY as ISSUE_NODE_ID_QUERY, queries_ISSUE_TYPES_QUERY as ISSUE_TYPES_QUERY, queries_LABEL_EXISTS_QUERY as LABEL_EXISTS_QUERY, queries_PROJECT_FIELDS_QUERY as PROJECT_FIELDS_QUERY, queries_PROJECT_ITEMS_QUERY as PROJECT_ITEMS_QUERY, queries_PROJECT_VIEWS_QUERY as PROJECT_VIEWS_QUERY, queries_RECENT_ISSUES_QUERY as RECENT_ISSUES_QUERY, queries_REMOVE_LABELS_MUTATION as REMOVE_LABELS_MUTATION, queries_REPOSITORY_ID_QUERY as REPOSITORY_ID_QUERY, queries_REPOSITORY_PROJECTS_QUERY as REPOSITORY_PROJECTS_QUERY, queries_UPDATE_ISSUE_BODY_MUTATION as UPDATE_ISSUE_BODY_MUTATION, queries_UPDATE_ISSUE_TYPE_MUTATION as UPDATE_ISSUE_TYPE_MUTATION, queries_UPDATE_ITEM_FIELD_MUTATION as UPDATE_ITEM_FIELD_MUTATION, queries_UPDATE_ITEM_STATUS_MUTATION as UPDATE_ITEM_STATUS_MUTATION, queries_VIEWER_QUERY as VIEWER_QUERY };
|
|
817
|
+
export { queries_ADD_COMMENT_MUTATION as ADD_COMMENT_MUTATION, queries_ADD_LABELS_MUTATION as ADD_LABELS_MUTATION, queries_ADD_TO_PROJECT_MUTATION as ADD_TO_PROJECT_MUTATION, queries_COLLABORATORS_QUERY as COLLABORATORS_QUERY, queries_CREATE_ISSUE_MUTATION as CREATE_ISSUE_MUTATION, queries_ISSUES_WITH_LABEL_QUERY as ISSUES_WITH_LABEL_QUERY, queries_ISSUE_AND_LABEL_QUERY as ISSUE_AND_LABEL_QUERY, queries_ISSUE_DETAILS_QUERY as ISSUE_DETAILS_QUERY, queries_ISSUE_FOR_UPDATE_QUERY as ISSUE_FOR_UPDATE_QUERY, queries_ISSUE_NODE_ID_QUERY as ISSUE_NODE_ID_QUERY, queries_ISSUE_TYPES_QUERY as ISSUE_TYPES_QUERY, queries_LABEL_EXISTS_QUERY as LABEL_EXISTS_QUERY, queries_PROJECT_FIELDS_QUERY as PROJECT_FIELDS_QUERY, queries_PROJECT_ITEMS_QUERY as PROJECT_ITEMS_QUERY, queries_PROJECT_VIEWS_QUERY as PROJECT_VIEWS_QUERY, queries_RECENT_ISSUES_QUERY as RECENT_ISSUES_QUERY, queries_REMOVE_LABELS_MUTATION as REMOVE_LABELS_MUTATION, queries_REPOSITORY_ID_QUERY as REPOSITORY_ID_QUERY, queries_REPOSITORY_PROJECTS_QUERY as REPOSITORY_PROJECTS_QUERY, queries_UPDATE_ISSUE_BODY_MUTATION as UPDATE_ISSUE_BODY_MUTATION, queries_UPDATE_ISSUE_MUTATION as UPDATE_ISSUE_MUTATION, queries_UPDATE_ISSUE_TYPE_MUTATION as UPDATE_ISSUE_TYPE_MUTATION, queries_UPDATE_ITEM_FIELD_MUTATION as UPDATE_ITEM_FIELD_MUTATION, queries_UPDATE_ITEM_STATUS_MUTATION as UPDATE_ITEM_STATUS_MUTATION, queries_VIEWER_QUERY as VIEWER_QUERY };
|
|
892
818
|
}
|
|
893
819
|
|
|
894
|
-
export { type AssigneeInfo, type AuthError,
|
|
820
|
+
export { type AssigneeInfo, type AuthError, BranchLinker, type Collaborator, type DateFieldValue, type FieldInfo, type FieldValue, type FieldValueConnection, GitHubAPI, type GitHubAPIOptions, type GitOptions, type IssueDetails, type IssueReference, type IterationFieldValue, type LabelInfo, type NumberFieldValue, type Project, type ProjectConfig, type ProjectItem, type ProjectItemContent, type ProjectItemsQueryResponse, type ProjectV2, type ProjectV2Field, type ProjectV2Item, type ProjectV2View, type ProjectWithViews, type ProjectsQueryResponse, type RepoInfo, type SingleSelectFieldValue, type StatusField, type TextFieldValue, type TokenProvider, branchExists, buildIssueUrl, buildOrgProjectUrl, buildProjectUrl, buildPullRequestUrl, buildRepoUrl, checkoutBranch, createBranch, detectRepository, fetchOrigin, generateBranchName, getCommitsAhead, getCommitsBehind, getCurrentBranch, getDefaultBranch, getRepositoryRoot, hasUncommittedChanges, isGitRepository, parseBranchLink, parseGitHubUrl, parseIssueUrl, pullLatest, queries, removeBranchLinkFromBody, sanitizeForBranchName, setBranchLinkInBody };
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ __export(queries_exports, {
|
|
|
30
30
|
REPOSITORY_ID_QUERY: () => REPOSITORY_ID_QUERY,
|
|
31
31
|
REPOSITORY_PROJECTS_QUERY: () => REPOSITORY_PROJECTS_QUERY,
|
|
32
32
|
UPDATE_ISSUE_BODY_MUTATION: () => UPDATE_ISSUE_BODY_MUTATION,
|
|
33
|
+
UPDATE_ISSUE_MUTATION: () => UPDATE_ISSUE_MUTATION,
|
|
33
34
|
UPDATE_ISSUE_TYPE_MUTATION: () => UPDATE_ISSUE_TYPE_MUTATION,
|
|
34
35
|
UPDATE_ITEM_FIELD_MUTATION: () => UPDATE_ITEM_FIELD_MUTATION,
|
|
35
36
|
UPDATE_ITEM_STATUS_MUTATION: () => UPDATE_ITEM_STATUS_MUTATION,
|
|
@@ -385,6 +386,15 @@ var UPDATE_ISSUE_BODY_MUTATION = `
|
|
|
385
386
|
}
|
|
386
387
|
}
|
|
387
388
|
`;
|
|
389
|
+
var UPDATE_ISSUE_MUTATION = `
|
|
390
|
+
mutation($issueId: ID!, $title: String, $body: String) {
|
|
391
|
+
updateIssue(input: { id: $issueId, title: $title, body: $body }) {
|
|
392
|
+
issue {
|
|
393
|
+
id
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
`;
|
|
388
398
|
|
|
389
399
|
// src/github-api.ts
|
|
390
400
|
function createAuthError(message, type, details) {
|
|
@@ -923,141 +933,94 @@ var GitHubAPI = class {
|
|
|
923
933
|
return false;
|
|
924
934
|
}
|
|
925
935
|
}
|
|
936
|
+
/**
|
|
937
|
+
* Update an issue's title and/or body
|
|
938
|
+
*/
|
|
939
|
+
async updateIssue(repo, issueNumber, updates) {
|
|
940
|
+
if (!this.graphqlWithAuth) throw new Error("Not authenticated");
|
|
941
|
+
try {
|
|
942
|
+
const issueResponse = await this.graphqlWithAuth(ISSUE_FOR_UPDATE_QUERY, {
|
|
943
|
+
owner: repo.owner,
|
|
944
|
+
name: repo.name,
|
|
945
|
+
number: issueNumber
|
|
946
|
+
});
|
|
947
|
+
if (!issueResponse.repository.issue) {
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
await this.graphqlWithAuth(UPDATE_ISSUE_MUTATION, {
|
|
951
|
+
issueId: issueResponse.repository.issue.id,
|
|
952
|
+
title: updates.title,
|
|
953
|
+
body: updates.body
|
|
954
|
+
});
|
|
955
|
+
return true;
|
|
956
|
+
} catch {
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
926
960
|
};
|
|
927
961
|
|
|
928
962
|
// src/branch-linker.ts
|
|
929
|
-
var
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
return
|
|
963
|
+
var BRANCH_LINK_PATTERN = /<!--\s*ghp-branch:\s*(.+?)\s*-->/;
|
|
964
|
+
function parseBranchLink(body) {
|
|
965
|
+
if (!body) return null;
|
|
966
|
+
const match = body.match(BRANCH_LINK_PATTERN);
|
|
967
|
+
return match ? match[1].trim() : null;
|
|
968
|
+
}
|
|
969
|
+
function setBranchLinkInBody(body, branch) {
|
|
970
|
+
const currentBody = body || "";
|
|
971
|
+
const tag = `<!-- ghp-branch: ${branch} -->`;
|
|
972
|
+
if (BRANCH_LINK_PATTERN.test(currentBody)) {
|
|
973
|
+
return currentBody.replace(BRANCH_LINK_PATTERN, tag);
|
|
974
|
+
} else {
|
|
975
|
+
return currentBody.trim() + "\n\n" + tag;
|
|
940
976
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
977
|
+
}
|
|
978
|
+
function removeBranchLinkFromBody(body) {
|
|
979
|
+
if (!body) return "";
|
|
980
|
+
return body.replace(BRANCH_LINK_PATTERN, "").trim();
|
|
981
|
+
}
|
|
982
|
+
var BranchLinker = class {
|
|
983
|
+
api;
|
|
984
|
+
constructor(api) {
|
|
985
|
+
this.api = api;
|
|
949
986
|
}
|
|
950
987
|
/**
|
|
951
988
|
* Create a link between a branch and an issue.
|
|
952
|
-
*
|
|
989
|
+
* Stores the link as a hidden comment in the issue body.
|
|
953
990
|
*/
|
|
954
|
-
async link(
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
);
|
|
959
|
-
filtered.push({
|
|
960
|
-
branch,
|
|
961
|
-
issueNumber,
|
|
962
|
-
issueTitle,
|
|
963
|
-
itemId,
|
|
964
|
-
repo,
|
|
965
|
-
linkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
966
|
-
});
|
|
967
|
-
await this.saveLinks(filtered);
|
|
991
|
+
async link(repo, issueNumber, branch) {
|
|
992
|
+
const details = await this.api.getIssueDetails(repo, issueNumber);
|
|
993
|
+
if (!details) return false;
|
|
994
|
+
const newBody = setBranchLinkInBody(details.body, branch);
|
|
995
|
+
return this.api.updateIssueBody(repo, issueNumber, newBody);
|
|
968
996
|
}
|
|
969
997
|
/**
|
|
970
|
-
* Remove the link
|
|
971
|
-
* @returns true if a link was removed, false if no link existed
|
|
998
|
+
* Remove the branch link from an issue.
|
|
972
999
|
*/
|
|
973
1000
|
async unlink(repo, issueNumber) {
|
|
974
|
-
const
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
);
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
}
|
|
981
|
-
await this.saveLinks(filtered);
|
|
982
|
-
return true;
|
|
983
|
-
}
|
|
984
|
-
/**
|
|
985
|
-
* Remove the link for a branch.
|
|
986
|
-
* @returns true if a link was removed, false if no link existed
|
|
987
|
-
*/
|
|
988
|
-
async unlinkBranch(repo, branch) {
|
|
989
|
-
const links = await this.loadLinks();
|
|
990
|
-
const filtered = links.filter(
|
|
991
|
-
(l) => !(l.repo === repo && l.branch === branch)
|
|
992
|
-
);
|
|
993
|
-
if (filtered.length === links.length) {
|
|
994
|
-
return false;
|
|
995
|
-
}
|
|
996
|
-
await this.saveLinks(filtered);
|
|
997
|
-
return true;
|
|
1001
|
+
const details = await this.api.getIssueDetails(repo, issueNumber);
|
|
1002
|
+
if (!details) return false;
|
|
1003
|
+
const currentBranch = parseBranchLink(details.body);
|
|
1004
|
+
if (!currentBranch) return false;
|
|
1005
|
+
const newBody = removeBranchLinkFromBody(details.body);
|
|
1006
|
+
return this.api.updateIssueBody(repo, issueNumber, newBody);
|
|
998
1007
|
}
|
|
999
1008
|
/**
|
|
1000
1009
|
* Get the branch linked to an issue.
|
|
1001
1010
|
*/
|
|
1002
1011
|
async getBranchForIssue(repo, issueNumber) {
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
return
|
|
1012
|
+
const details = await this.api.getIssueDetails(repo, issueNumber);
|
|
1013
|
+
if (!details) return null;
|
|
1014
|
+
return parseBranchLink(details.body);
|
|
1006
1015
|
}
|
|
1007
1016
|
/**
|
|
1008
|
-
*
|
|
1017
|
+
* Check if an issue has a branch link.
|
|
1009
1018
|
*/
|
|
1010
|
-
async
|
|
1011
|
-
const
|
|
1012
|
-
return
|
|
1013
|
-
}
|
|
1014
|
-
/**
|
|
1015
|
-
* Get the full link info for an issue.
|
|
1016
|
-
*/
|
|
1017
|
-
async getLinkForIssue(repo, issueNumber) {
|
|
1018
|
-
const links = await this.loadLinks();
|
|
1019
|
-
return links.find((l) => l.repo === repo && l.issueNumber === issueNumber) || null;
|
|
1020
|
-
}
|
|
1021
|
-
/**
|
|
1022
|
-
* Get all links for a repository.
|
|
1023
|
-
*/
|
|
1024
|
-
async getLinksForRepo(repo) {
|
|
1025
|
-
const links = await this.loadLinks();
|
|
1026
|
-
return links.filter((l) => l.repo === repo);
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Get all links.
|
|
1030
|
-
*/
|
|
1031
|
-
async getAllLinks() {
|
|
1032
|
-
return this.loadLinks();
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Check if a branch has a link.
|
|
1036
|
-
*/
|
|
1037
|
-
async hasLinkForBranch(repo, branch) {
|
|
1038
|
-
const link = await this.getLinkForBranch(repo, branch);
|
|
1039
|
-
return link !== null;
|
|
1040
|
-
}
|
|
1041
|
-
/**
|
|
1042
|
-
* Check if an issue has a link.
|
|
1043
|
-
*/
|
|
1044
|
-
async hasLinkForIssue(repo, issueNumber) {
|
|
1045
|
-
const link = await this.getLinkForIssue(repo, issueNumber);
|
|
1046
|
-
return link !== null;
|
|
1019
|
+
async hasLink(repo, issueNumber) {
|
|
1020
|
+
const branch = await this.getBranchForIssue(repo, issueNumber);
|
|
1021
|
+
return branch !== null;
|
|
1047
1022
|
}
|
|
1048
1023
|
};
|
|
1049
|
-
function createInMemoryAdapter() {
|
|
1050
|
-
const adapter = {
|
|
1051
|
-
links: [],
|
|
1052
|
-
load() {
|
|
1053
|
-
return [...this.links];
|
|
1054
|
-
},
|
|
1055
|
-
save(links) {
|
|
1056
|
-
this.links = [...links];
|
|
1057
|
-
}
|
|
1058
|
-
};
|
|
1059
|
-
return adapter;
|
|
1060
|
-
}
|
|
1061
1024
|
|
|
1062
1025
|
// src/git-utils.ts
|
|
1063
1026
|
import { exec } from "child_process";
|
|
@@ -1244,7 +1207,6 @@ export {
|
|
|
1244
1207
|
buildRepoUrl,
|
|
1245
1208
|
checkoutBranch,
|
|
1246
1209
|
createBranch,
|
|
1247
|
-
createInMemoryAdapter,
|
|
1248
1210
|
detectRepository,
|
|
1249
1211
|
fetchOrigin,
|
|
1250
1212
|
generateBranchName,
|
|
@@ -1255,9 +1217,12 @@ export {
|
|
|
1255
1217
|
getRepositoryRoot,
|
|
1256
1218
|
hasUncommittedChanges,
|
|
1257
1219
|
isGitRepository,
|
|
1220
|
+
parseBranchLink,
|
|
1258
1221
|
parseGitHubUrl,
|
|
1259
1222
|
parseIssueUrl,
|
|
1260
1223
|
pullLatest,
|
|
1261
1224
|
queries_exports as queries,
|
|
1262
|
-
|
|
1225
|
+
removeBranchLinkFromBody,
|
|
1226
|
+
sanitizeForBranchName,
|
|
1227
|
+
setBranchLinkInBody
|
|
1263
1228
|
};
|