paperclip-github-plugin 0.7.3 → 0.7.5
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/README.md +12 -5
- package/dist/manifest.js +5 -1
- package/dist/ui/index.js +266 -14
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +533 -56
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -255,6 +255,10 @@ var GITHUB_AGENT_TOOLS = [
|
|
|
255
255
|
required: ["head", "base", "title"],
|
|
256
256
|
properties: {
|
|
257
257
|
repository: repositoryProperty,
|
|
258
|
+
paperclipIssueId: {
|
|
259
|
+
type: "string",
|
|
260
|
+
description: "Optional Paperclip issue id to link with the created pull request so GitHub Sync can monitor PR status for that issue."
|
|
261
|
+
},
|
|
258
262
|
head: {
|
|
259
263
|
type: "string",
|
|
260
264
|
description: "Head branch name or owner:branch."
|
|
@@ -2300,6 +2304,18 @@ async function resolvePaperclipIssueGitHubLink(ctx, issueId, companyId, options
|
|
|
2300
2304
|
};
|
|
2301
2305
|
return await hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLink) ?? fallbackLink;
|
|
2302
2306
|
}
|
|
2307
|
+
async function resolvePaperclipIssueGitHubPullRequestLink(ctx, issueId, companyId) {
|
|
2308
|
+
const links = await listGitHubPullRequestLinkRecords(ctx, {
|
|
2309
|
+
paperclipIssueId: issueId
|
|
2310
|
+
});
|
|
2311
|
+
return links.filter((record) => !record.data.companyId || record.data.companyId === companyId).sort((left, right) => {
|
|
2312
|
+
const rightTimestamp = Date.parse(right.updatedAt ?? right.createdAt ?? "");
|
|
2313
|
+
const leftTimestamp = Date.parse(left.updatedAt ?? left.createdAt ?? "");
|
|
2314
|
+
const safeRightTimestamp = Number.isFinite(rightTimestamp) ? rightTimestamp : 0;
|
|
2315
|
+
const safeLeftTimestamp = Number.isFinite(leftTimestamp) ? leftTimestamp : 0;
|
|
2316
|
+
return safeRightTimestamp - safeLeftTimestamp;
|
|
2317
|
+
})[0] ?? null;
|
|
2318
|
+
}
|
|
2303
2319
|
async function hydrateRecoveredPaperclipIssueGitHubLink(ctx, issueId, fallbackLink) {
|
|
2304
2320
|
const repository = parseRepositoryReference(fallbackLink.repositoryUrl);
|
|
2305
2321
|
if (!repository) {
|
|
@@ -2375,21 +2391,33 @@ async function resolveManualSyncTarget(ctx, settings, input) {
|
|
|
2375
2391
|
}
|
|
2376
2392
|
const link = await resolvePaperclipIssueGitHubLink(ctx, input.issueId, companyId2);
|
|
2377
2393
|
if (!link) {
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2394
|
+
const pullRequestLink = await resolvePaperclipIssueGitHubPullRequestLink(ctx, input.issueId, companyId2);
|
|
2395
|
+
if (!pullRequestLink) {
|
|
2396
|
+
throw new Error("This Paperclip issue is not linked to a GitHub issue or pull request yet. Run a broader sync first.");
|
|
2397
|
+
}
|
|
2398
|
+
const candidateMappings = getSyncableMappingsForTarget(settings.mappings, {
|
|
2399
|
+
kind: "issue",
|
|
2400
|
+
companyId: companyId2,
|
|
2401
|
+
projectId: pullRequestLink.data.paperclipProjectId,
|
|
2402
|
+
repositoryUrl: pullRequestLink.data.repositoryUrl,
|
|
2403
|
+
issueId: input.issueId,
|
|
2404
|
+
githubPullRequestNumber: pullRequestLink.data.githubPullRequestNumber,
|
|
2405
|
+
githubPullRequestUrl: pullRequestLink.data.githubPullRequestUrl,
|
|
2406
|
+
displayLabel: `pull request #${pullRequestLink.data.githubPullRequestNumber}`
|
|
2407
|
+
});
|
|
2408
|
+
if (candidateMappings.length === 0) {
|
|
2409
|
+
throw new Error("No saved GitHub repository mapping matches this Paperclip issue.");
|
|
2410
|
+
}
|
|
2411
|
+
return {
|
|
2412
|
+
kind: "issue",
|
|
2413
|
+
companyId: companyId2,
|
|
2414
|
+
projectId: pullRequestLink.data.paperclipProjectId,
|
|
2415
|
+
issueId: input.issueId,
|
|
2416
|
+
repositoryUrl: pullRequestLink.data.repositoryUrl,
|
|
2417
|
+
githubPullRequestNumber: pullRequestLink.data.githubPullRequestNumber,
|
|
2418
|
+
githubPullRequestUrl: pullRequestLink.data.githubPullRequestUrl,
|
|
2419
|
+
displayLabel: `pull request #${pullRequestLink.data.githubPullRequestNumber}`
|
|
2420
|
+
};
|
|
2393
2421
|
}
|
|
2394
2422
|
return {
|
|
2395
2423
|
kind: "issue",
|
|
@@ -2513,23 +2541,46 @@ async function buildToolbarSyncState(ctx, input) {
|
|
|
2513
2541
|
}
|
|
2514
2542
|
if (entityType === "issue" && entityId && companyId) {
|
|
2515
2543
|
const link = await resolvePaperclipIssueGitHubLink(ctx, entityId, companyId);
|
|
2516
|
-
|
|
2544
|
+
if (link) {
|
|
2545
|
+
const mappings2 = getSyncableMappingsForTarget(settings.mappings, {
|
|
2546
|
+
kind: "issue",
|
|
2547
|
+
companyId,
|
|
2548
|
+
projectId: link.paperclipProjectId,
|
|
2549
|
+
issueId: entityId,
|
|
2550
|
+
repositoryUrl: link.repositoryUrl,
|
|
2551
|
+
githubIssueId: link.githubIssueId,
|
|
2552
|
+
githubIssueNumber: link.githubIssueNumber,
|
|
2553
|
+
githubIssueUrl: link.githubIssueUrl,
|
|
2554
|
+
displayLabel: `issue #${link.githubIssueNumber}`
|
|
2555
|
+
});
|
|
2556
|
+
return {
|
|
2557
|
+
kind: "issue",
|
|
2558
|
+
visible: false,
|
|
2559
|
+
canRun: githubTokenConfigured && mappings2.length > 0,
|
|
2560
|
+
label: `Sync #${link.githubIssueNumber}`,
|
|
2561
|
+
message: `Sync ${link.repositoryUrl.replace(/^https:\/\/github\.com\//, "")} issue #${link.githubIssueNumber}.`,
|
|
2562
|
+
syncState: settings.syncState,
|
|
2563
|
+
githubTokenConfigured,
|
|
2564
|
+
savedMappingCount
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
2567
|
+
const pullRequestLink = await resolvePaperclipIssueGitHubPullRequestLink(ctx, entityId, companyId);
|
|
2568
|
+
const mappings = pullRequestLink ? getSyncableMappingsForTarget(settings.mappings, {
|
|
2517
2569
|
kind: "issue",
|
|
2518
2570
|
companyId,
|
|
2519
|
-
projectId:
|
|
2571
|
+
projectId: pullRequestLink.data.paperclipProjectId,
|
|
2520
2572
|
issueId: entityId,
|
|
2521
|
-
repositoryUrl:
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
displayLabel: `issue #${link.githubIssueNumber}`
|
|
2573
|
+
repositoryUrl: pullRequestLink.data.repositoryUrl,
|
|
2574
|
+
githubPullRequestNumber: pullRequestLink.data.githubPullRequestNumber,
|
|
2575
|
+
githubPullRequestUrl: pullRequestLink.data.githubPullRequestUrl,
|
|
2576
|
+
displayLabel: `pull request #${pullRequestLink.data.githubPullRequestNumber}`
|
|
2526
2577
|
}) : [];
|
|
2527
2578
|
return {
|
|
2528
2579
|
kind: "issue",
|
|
2529
2580
|
visible: false,
|
|
2530
2581
|
canRun: githubTokenConfigured && mappings.length > 0,
|
|
2531
|
-
label:
|
|
2532
|
-
message:
|
|
2582
|
+
label: pullRequestLink?.data.githubPullRequestNumber ? `Sync PR #${pullRequestLink.data.githubPullRequestNumber}` : "Sync issue",
|
|
2583
|
+
message: pullRequestLink ? `Sync ${pullRequestLink.data.repositoryUrl.replace(/^https:\/\/github\.com\//, "")} pull request #${pullRequestLink.data.githubPullRequestNumber}.` : "This Paperclip issue is not linked to GitHub yet.",
|
|
2533
2584
|
syncState: settings.syncState,
|
|
2534
2585
|
githubTokenConfigured,
|
|
2535
2586
|
savedMappingCount
|
|
@@ -2696,13 +2747,11 @@ async function buildIssueGitHubDetails(ctx, input) {
|
|
|
2696
2747
|
const link = await resolvePaperclipIssueGitHubLink(ctx, issueId, companyId, {
|
|
2697
2748
|
linkRecords
|
|
2698
2749
|
});
|
|
2699
|
-
if (
|
|
2700
|
-
|
|
2701
|
-
}
|
|
2702
|
-
const entityMatch = link.entityRecord;
|
|
2703
|
-
if (entityMatch) {
|
|
2750
|
+
if (link?.entityRecord) {
|
|
2751
|
+
const entityMatch = link.entityRecord;
|
|
2704
2752
|
return {
|
|
2705
2753
|
paperclipIssueId: issueId,
|
|
2754
|
+
kind: "issue",
|
|
2706
2755
|
source: "entity",
|
|
2707
2756
|
githubIssueNumber: entityMatch.data.githubIssueNumber,
|
|
2708
2757
|
githubIssueUrl: entityMatch.data.githubIssueUrl,
|
|
@@ -2723,14 +2772,48 @@ async function buildIssueGitHubDetails(ctx, input) {
|
|
|
2723
2772
|
syncedAt: entityMatch.data.syncedAt
|
|
2724
2773
|
};
|
|
2725
2774
|
}
|
|
2775
|
+
if (link) {
|
|
2776
|
+
return {
|
|
2777
|
+
paperclipIssueId: issueId,
|
|
2778
|
+
kind: "issue",
|
|
2779
|
+
source: link.source,
|
|
2780
|
+
githubIssueNumber: link.githubIssueNumber,
|
|
2781
|
+
githubIssueUrl: link.githubIssueUrl,
|
|
2782
|
+
repositoryUrl: link.repositoryUrl,
|
|
2783
|
+
linkedPullRequestNumbers: link.linkedPullRequestNumbers,
|
|
2784
|
+
linkedPullRequests: link.linkedPullRequests
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
const pullRequestLinks = await listGitHubPullRequestLinkRecords(ctx, {
|
|
2788
|
+
paperclipIssueId: issueId
|
|
2789
|
+
});
|
|
2790
|
+
const pullRequestLink = pullRequestLinks.filter((record) => !record.data.companyId || record.data.companyId === companyId).sort((left, right) => {
|
|
2791
|
+
const rightTimestamp = Date.parse(right.updatedAt ?? right.createdAt ?? "");
|
|
2792
|
+
const leftTimestamp = Date.parse(left.updatedAt ?? left.createdAt ?? "");
|
|
2793
|
+
const safeRightTimestamp = Number.isFinite(rightTimestamp) ? rightTimestamp : 0;
|
|
2794
|
+
const safeLeftTimestamp = Number.isFinite(leftTimestamp) ? leftTimestamp : 0;
|
|
2795
|
+
return safeRightTimestamp - safeLeftTimestamp;
|
|
2796
|
+
})[0];
|
|
2797
|
+
if (!pullRequestLink) {
|
|
2798
|
+
return null;
|
|
2799
|
+
}
|
|
2726
2800
|
return {
|
|
2727
2801
|
paperclipIssueId: issueId,
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2802
|
+
kind: "pull_request",
|
|
2803
|
+
source: "pull_request_entity",
|
|
2804
|
+
repositoryUrl: pullRequestLink.data.repositoryUrl,
|
|
2805
|
+
githubPullRequestNumber: pullRequestLink.data.githubPullRequestNumber,
|
|
2806
|
+
githubPullRequestUrl: pullRequestLink.data.githubPullRequestUrl,
|
|
2807
|
+
githubPullRequestState: pullRequestLink.data.githubPullRequestState,
|
|
2808
|
+
title: pullRequestLink.data.title,
|
|
2809
|
+
linkedPullRequestNumbers: [pullRequestLink.data.githubPullRequestNumber],
|
|
2810
|
+
linkedPullRequests: [
|
|
2811
|
+
{
|
|
2812
|
+
number: pullRequestLink.data.githubPullRequestNumber,
|
|
2813
|
+
repositoryUrl: pullRequestLink.data.repositoryUrl
|
|
2814
|
+
}
|
|
2815
|
+
],
|
|
2816
|
+
syncedAt: pullRequestLink.data.syncedAt
|
|
2734
2817
|
};
|
|
2735
2818
|
}
|
|
2736
2819
|
async function resolveIssueByIdentifier(ctx, input) {
|
|
@@ -6014,24 +6097,34 @@ function parseGitHubIssueHtmlUrl(value) {
|
|
|
6014
6097
|
function normalizeGitHubIssueHtmlUrl(value) {
|
|
6015
6098
|
return parseGitHubIssueHtmlUrl(value)?.issueUrl;
|
|
6016
6099
|
}
|
|
6017
|
-
function
|
|
6018
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
6019
|
-
return void 0;
|
|
6020
|
-
}
|
|
6100
|
+
function parseGitHubPullRequestHtmlUrl(value) {
|
|
6021
6101
|
try {
|
|
6022
|
-
const
|
|
6023
|
-
|
|
6102
|
+
const url = new URL(value.trim());
|
|
6103
|
+
const hostname = url.hostname.trim().toLowerCase();
|
|
6104
|
+
if (hostname !== "github.com" && hostname !== "www.github.com") {
|
|
6024
6105
|
return void 0;
|
|
6025
6106
|
}
|
|
6026
|
-
const match =
|
|
6107
|
+
const match = url.pathname.match(/^\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/pull\/(\d+)\/?$/);
|
|
6027
6108
|
if (!match) {
|
|
6028
6109
|
return void 0;
|
|
6029
6110
|
}
|
|
6030
|
-
return
|
|
6111
|
+
return {
|
|
6112
|
+
owner: match[1],
|
|
6113
|
+
repo: match[2],
|
|
6114
|
+
repositoryUrl: `https://github.com/${match[1]}/${match[2]}`,
|
|
6115
|
+
pullRequestNumber: Number(match[3]),
|
|
6116
|
+
pullRequestUrl: `https://github.com/${match[1]}/${match[2]}/pull/${match[3]}`
|
|
6117
|
+
};
|
|
6031
6118
|
} catch {
|
|
6032
6119
|
return void 0;
|
|
6033
6120
|
}
|
|
6034
6121
|
}
|
|
6122
|
+
function normalizeGitHubPullRequestHtmlUrl(value) {
|
|
6123
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
6124
|
+
return void 0;
|
|
6125
|
+
}
|
|
6126
|
+
return parseGitHubPullRequestHtmlUrl(value)?.pullRequestUrl;
|
|
6127
|
+
}
|
|
6035
6128
|
function escapeRegExp(value) {
|
|
6036
6129
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6037
6130
|
}
|
|
@@ -6705,6 +6798,257 @@ async function upsertGitHubPullRequestLinkRecord(ctx, params) {
|
|
|
6705
6798
|
}
|
|
6706
6799
|
});
|
|
6707
6800
|
}
|
|
6801
|
+
function normalizeIssueGitHubLinkKind(value) {
|
|
6802
|
+
if (value === "issue" || value === "github_issue") {
|
|
6803
|
+
return "issue";
|
|
6804
|
+
}
|
|
6805
|
+
if (value === "pull_request" || value === "pr" || value === "github_pull_request") {
|
|
6806
|
+
return "pull_request";
|
|
6807
|
+
}
|
|
6808
|
+
return null;
|
|
6809
|
+
}
|
|
6810
|
+
function getGitHubPullRequestStateForLink(value) {
|
|
6811
|
+
return getPullRequestApiState(value) === "open" ? "open" : "closed";
|
|
6812
|
+
}
|
|
6813
|
+
async function assertPaperclipIssueHasNoManualGitHubLink(ctx, params) {
|
|
6814
|
+
const existingIssueLink = await resolvePaperclipIssueGitHubLink(ctx, params.issueId, params.companyId);
|
|
6815
|
+
if (existingIssueLink) {
|
|
6816
|
+
throw new Error("This Paperclip issue is already linked to a GitHub issue.");
|
|
6817
|
+
}
|
|
6818
|
+
const existingPullRequestLinks = await listGitHubPullRequestLinkRecords(ctx, {
|
|
6819
|
+
paperclipIssueId: params.issueId
|
|
6820
|
+
});
|
|
6821
|
+
const matchingPullRequestLink = existingPullRequestLinks.find(
|
|
6822
|
+
(record) => !record.data.companyId || record.data.companyId === params.companyId
|
|
6823
|
+
);
|
|
6824
|
+
if (matchingPullRequestLink) {
|
|
6825
|
+
throw new Error("This Paperclip issue is already linked to a GitHub pull request.");
|
|
6826
|
+
}
|
|
6827
|
+
}
|
|
6828
|
+
async function resolveIssueGitHubLinkMapping(ctx, params) {
|
|
6829
|
+
const issue = await ctx.issues.get(params.issueId, params.companyId);
|
|
6830
|
+
if (!issue) {
|
|
6831
|
+
throw new Error("Paperclip issue was not found.");
|
|
6832
|
+
}
|
|
6833
|
+
const projectId = typeof issue.projectId === "string" && issue.projectId.trim() ? issue.projectId.trim() : void 0;
|
|
6834
|
+
if (!projectId) {
|
|
6835
|
+
throw new Error("This Paperclip issue is not in a project that can be mapped to a GitHub repository.");
|
|
6836
|
+
}
|
|
6837
|
+
const settings = normalizeSettings(await ctx.state.get(SETTINGS_SCOPE));
|
|
6838
|
+
const mappings = await resolveProjectScopedMappings(ctx, settings.mappings, {
|
|
6839
|
+
companyId: params.companyId,
|
|
6840
|
+
projectId
|
|
6841
|
+
});
|
|
6842
|
+
if (mappings.length === 0) {
|
|
6843
|
+
throw new Error("This Paperclip issue project is not mapped to a GitHub repository.");
|
|
6844
|
+
}
|
|
6845
|
+
const requestedRepository = params.repositoryUrl ? parseRepositoryReference(params.repositoryUrl) : null;
|
|
6846
|
+
if (params.repositoryUrl && !requestedRepository) {
|
|
6847
|
+
throw new Error(`Invalid GitHub repository: ${params.repositoryUrl}. Use owner/repo or https://github.com/owner/repo.`);
|
|
6848
|
+
}
|
|
6849
|
+
const matchingMappings = requestedRepository ? mappings.filter(
|
|
6850
|
+
(mapping2) => areRepositoriesEqual(requireRepositoryReference(mapping2.repositoryUrl), requestedRepository)
|
|
6851
|
+
) : mappings;
|
|
6852
|
+
if (matchingMappings.length === 0 && requestedRepository) {
|
|
6853
|
+
throw new Error("The current Paperclip issue project is not mapped to the selected GitHub repository.");
|
|
6854
|
+
}
|
|
6855
|
+
if (matchingMappings.length > 1 && !requestedRepository) {
|
|
6856
|
+
throw new Error("This Paperclip issue project has multiple GitHub repositories. Enter the full GitHub URL.");
|
|
6857
|
+
}
|
|
6858
|
+
const mapping = matchingMappings[0];
|
|
6859
|
+
if (!mapping) {
|
|
6860
|
+
throw new Error("This Paperclip issue project is not mapped to a GitHub repository.");
|
|
6861
|
+
}
|
|
6862
|
+
return {
|
|
6863
|
+
issue,
|
|
6864
|
+
projectId,
|
|
6865
|
+
mapping,
|
|
6866
|
+
repository: requestedRepository ?? requireRepositoryReference(mapping.repositoryUrl)
|
|
6867
|
+
};
|
|
6868
|
+
}
|
|
6869
|
+
function resolveGitHubIssueLinkReference(input) {
|
|
6870
|
+
const reference = normalizeOptionalString2(input.reference);
|
|
6871
|
+
if (reference) {
|
|
6872
|
+
const parsedIssueUrl = parseGitHubIssueHtmlUrl(reference);
|
|
6873
|
+
if (parsedIssueUrl) {
|
|
6874
|
+
return {
|
|
6875
|
+
repositoryUrl: parsedIssueUrl.repositoryUrl,
|
|
6876
|
+
issueNumber: parsedIssueUrl.issueNumber,
|
|
6877
|
+
issueUrl: parsedIssueUrl.issueUrl
|
|
6878
|
+
};
|
|
6879
|
+
}
|
|
6880
|
+
if (parseGitHubPullRequestHtmlUrl(reference)) {
|
|
6881
|
+
throw new Error("That reference is a GitHub pull request. Choose pull request instead.");
|
|
6882
|
+
}
|
|
6883
|
+
const referenceNumber = normalizePositiveIntegerReference(reference);
|
|
6884
|
+
if (referenceNumber) {
|
|
6885
|
+
return {
|
|
6886
|
+
repositoryUrl: input.repositoryUrl,
|
|
6887
|
+
issueNumber: referenceNumber
|
|
6888
|
+
};
|
|
6889
|
+
}
|
|
6890
|
+
}
|
|
6891
|
+
const explicitIssueNumber = normalizePositiveIntegerReference(input.issueNumber);
|
|
6892
|
+
if (explicitIssueNumber) {
|
|
6893
|
+
return {
|
|
6894
|
+
repositoryUrl: input.repositoryUrl,
|
|
6895
|
+
issueNumber: explicitIssueNumber
|
|
6896
|
+
};
|
|
6897
|
+
}
|
|
6898
|
+
throw new Error("Enter a GitHub issue number or full GitHub issue URL.");
|
|
6899
|
+
}
|
|
6900
|
+
function resolveGitHubPullRequestLinkReference(input) {
|
|
6901
|
+
const explicitPullRequestUrl = normalizeGitHubPullRequestHtmlUrl(normalizeOptionalString2(input.pullRequestUrl));
|
|
6902
|
+
const parsedExplicitPullRequestUrl = explicitPullRequestUrl ? parseGitHubPullRequestHtmlUrl(explicitPullRequestUrl) : void 0;
|
|
6903
|
+
const reference = normalizeOptionalString2(input.reference);
|
|
6904
|
+
const parsedReferenceUrl = reference ? parseGitHubPullRequestHtmlUrl(reference) : void 0;
|
|
6905
|
+
if (reference && parseGitHubIssueHtmlUrl(reference)) {
|
|
6906
|
+
throw new Error("That reference is a GitHub issue. Choose issue instead.");
|
|
6907
|
+
}
|
|
6908
|
+
const parsedUrl = parsedReferenceUrl ?? parsedExplicitPullRequestUrl;
|
|
6909
|
+
const explicitPullRequestNumber = normalizePositiveIntegerReference(input.pullRequestNumber);
|
|
6910
|
+
const referenceNumber = reference && !parsedReferenceUrl ? normalizePositiveIntegerReference(reference) : void 0;
|
|
6911
|
+
const pullRequestNumber = parsedUrl?.pullRequestNumber ?? explicitPullRequestNumber ?? referenceNumber;
|
|
6912
|
+
const repositoryUrl = parsedUrl?.repositoryUrl ?? input.repositoryUrl;
|
|
6913
|
+
if (!pullRequestNumber) {
|
|
6914
|
+
throw new Error("Enter a GitHub pull request number or full GitHub pull request URL.");
|
|
6915
|
+
}
|
|
6916
|
+
if (parsedUrl && explicitPullRequestNumber && explicitPullRequestNumber !== parsedUrl.pullRequestNumber) {
|
|
6917
|
+
throw new Error("pullRequestNumber must match the supplied GitHub pull request URL.");
|
|
6918
|
+
}
|
|
6919
|
+
if (parsedUrl && input.repositoryUrl) {
|
|
6920
|
+
const requestedRepository = parseRepositoryReference(input.repositoryUrl);
|
|
6921
|
+
const urlRepository = parseRepositoryReference(parsedUrl.repositoryUrl);
|
|
6922
|
+
if (requestedRepository && urlRepository && !areRepositoriesEqual(requestedRepository, urlRepository)) {
|
|
6923
|
+
throw new Error("repository must match the supplied GitHub pull request URL.");
|
|
6924
|
+
}
|
|
6925
|
+
}
|
|
6926
|
+
return {
|
|
6927
|
+
repositoryUrl,
|
|
6928
|
+
pullRequestNumber,
|
|
6929
|
+
...parsedUrl?.pullRequestUrl ? { pullRequestUrl: parsedUrl.pullRequestUrl } : {}
|
|
6930
|
+
};
|
|
6931
|
+
}
|
|
6932
|
+
async function linkPaperclipIssueToGitHubIssue(ctx, params) {
|
|
6933
|
+
const companyId = normalizeCompanyId(params.companyId);
|
|
6934
|
+
const issueId = normalizeOptionalString2(params.issueId);
|
|
6935
|
+
if (!companyId || !issueId) {
|
|
6936
|
+
throw new Error("companyId and issueId are required.");
|
|
6937
|
+
}
|
|
6938
|
+
if (params.requireUnlinked) {
|
|
6939
|
+
await assertPaperclipIssueHasNoManualGitHubLink(ctx, {
|
|
6940
|
+
companyId,
|
|
6941
|
+
issueId
|
|
6942
|
+
});
|
|
6943
|
+
}
|
|
6944
|
+
const reference = resolveGitHubIssueLinkReference({
|
|
6945
|
+
kind: "issue",
|
|
6946
|
+
reference: params.reference,
|
|
6947
|
+
repositoryUrl: params.repositoryUrl,
|
|
6948
|
+
issueNumber: params.issueNumber
|
|
6949
|
+
});
|
|
6950
|
+
const scope = await resolveIssueGitHubLinkMapping(ctx, {
|
|
6951
|
+
companyId,
|
|
6952
|
+
issueId,
|
|
6953
|
+
repositoryUrl: reference.repositoryUrl
|
|
6954
|
+
});
|
|
6955
|
+
const octokit = await createGitHubToolOctokit(ctx, companyId);
|
|
6956
|
+
const response = await octokit.rest.issues.get({
|
|
6957
|
+
owner: scope.repository.owner,
|
|
6958
|
+
repo: scope.repository.repo,
|
|
6959
|
+
issue_number: reference.issueNumber,
|
|
6960
|
+
headers: {
|
|
6961
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
6962
|
+
}
|
|
6963
|
+
});
|
|
6964
|
+
const rawIssue = response.data;
|
|
6965
|
+
if (rawIssue.pull_request) {
|
|
6966
|
+
throw new Error("That GitHub number is a pull request. Choose pull request instead.");
|
|
6967
|
+
}
|
|
6968
|
+
const githubIssue = normalizeGitHubIssueRecord(rawIssue);
|
|
6969
|
+
const linkedPullRequests = await listLinkedPullRequestsForIssue(octokit, scope.repository, githubIssue.number);
|
|
6970
|
+
await upsertGitHubIssueLinkRecord(ctx, scope.mapping, issueId, githubIssue, linkedPullRequests);
|
|
6971
|
+
const importRegistry = normalizeImportRegistry(await ctx.state.get(IMPORT_REGISTRY_SCOPE));
|
|
6972
|
+
upsertImportedIssueRecord(
|
|
6973
|
+
importRegistry,
|
|
6974
|
+
buildImportedIssueRecord(scope.mapping, githubIssue, issueId, (/* @__PURE__ */ new Date()).toISOString())
|
|
6975
|
+
);
|
|
6976
|
+
await ctx.state.set(IMPORT_REGISTRY_SCOPE, importRegistry);
|
|
6977
|
+
invalidateProjectPullRequestCaches({
|
|
6978
|
+
companyId,
|
|
6979
|
+
projectId: scope.mapping.paperclipProjectId ?? scope.projectId,
|
|
6980
|
+
repository: scope.repository
|
|
6981
|
+
});
|
|
6982
|
+
return {
|
|
6983
|
+
kind: "issue",
|
|
6984
|
+
paperclipIssueId: issueId,
|
|
6985
|
+
repositoryUrl: scope.repository.url,
|
|
6986
|
+
githubIssueNumber: githubIssue.number,
|
|
6987
|
+
githubIssueUrl: normalizeGitHubIssueHtmlUrl(githubIssue.htmlUrl) ?? githubIssue.htmlUrl,
|
|
6988
|
+
linkedPullRequestNumbers: linkedPullRequests.map((pullRequest) => pullRequest.number)
|
|
6989
|
+
};
|
|
6990
|
+
}
|
|
6991
|
+
async function linkPaperclipIssueToGitHubPullRequest(ctx, params) {
|
|
6992
|
+
const companyId = normalizeCompanyId(params.companyId);
|
|
6993
|
+
const issueId = normalizeOptionalString2(params.issueId);
|
|
6994
|
+
if (!companyId || !issueId) {
|
|
6995
|
+
throw new Error("companyId and issueId are required.");
|
|
6996
|
+
}
|
|
6997
|
+
if (params.requireUnlinked) {
|
|
6998
|
+
await assertPaperclipIssueHasNoManualGitHubLink(ctx, {
|
|
6999
|
+
companyId,
|
|
7000
|
+
issueId
|
|
7001
|
+
});
|
|
7002
|
+
}
|
|
7003
|
+
const reference = resolveGitHubPullRequestLinkReference({
|
|
7004
|
+
reference: params.reference,
|
|
7005
|
+
repositoryUrl: params.repositoryUrl,
|
|
7006
|
+
pullRequestNumber: params.pullRequestNumber,
|
|
7007
|
+
pullRequestUrl: params.pullRequestUrl
|
|
7008
|
+
});
|
|
7009
|
+
const scope = await resolveIssueGitHubLinkMapping(ctx, {
|
|
7010
|
+
companyId,
|
|
7011
|
+
issueId,
|
|
7012
|
+
repositoryUrl: reference.repositoryUrl
|
|
7013
|
+
});
|
|
7014
|
+
const octokit = await createGitHubToolOctokit(ctx, companyId);
|
|
7015
|
+
const response = await octokit.rest.pulls.get({
|
|
7016
|
+
owner: scope.repository.owner,
|
|
7017
|
+
repo: scope.repository.repo,
|
|
7018
|
+
pull_number: reference.pullRequestNumber,
|
|
7019
|
+
headers: {
|
|
7020
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
7021
|
+
}
|
|
7022
|
+
});
|
|
7023
|
+
const pullRequestUrl = normalizeGitHubPullRequestHtmlUrl(response.data.html_url ?? reference.pullRequestUrl) ?? reference.pullRequestUrl ?? `${scope.repository.url}/pull/${reference.pullRequestNumber}`;
|
|
7024
|
+
const pullRequestState = getGitHubPullRequestStateForLink({
|
|
7025
|
+
state: response.data.state,
|
|
7026
|
+
merged: response.data.merged
|
|
7027
|
+
});
|
|
7028
|
+
await upsertGitHubPullRequestLinkRecord(ctx, {
|
|
7029
|
+
companyId,
|
|
7030
|
+
projectId: scope.mapping.paperclipProjectId ?? scope.projectId,
|
|
7031
|
+
issueId,
|
|
7032
|
+
repositoryUrl: scope.repository.url,
|
|
7033
|
+
pullRequestNumber: reference.pullRequestNumber,
|
|
7034
|
+
pullRequestUrl,
|
|
7035
|
+
pullRequestTitle: response.data.title || `Pull request #${reference.pullRequestNumber}`,
|
|
7036
|
+
pullRequestState
|
|
7037
|
+
});
|
|
7038
|
+
invalidateProjectPullRequestCaches({
|
|
7039
|
+
companyId,
|
|
7040
|
+
projectId: scope.mapping.paperclipProjectId ?? scope.projectId,
|
|
7041
|
+
repository: scope.repository
|
|
7042
|
+
});
|
|
7043
|
+
return {
|
|
7044
|
+
kind: "pull_request",
|
|
7045
|
+
paperclipIssueId: issueId,
|
|
7046
|
+
repositoryUrl: scope.repository.url,
|
|
7047
|
+
githubPullRequestNumber: reference.pullRequestNumber,
|
|
7048
|
+
githubPullRequestUrl: pullRequestUrl,
|
|
7049
|
+
githubPullRequestState: pullRequestState
|
|
7050
|
+
};
|
|
7051
|
+
}
|
|
6708
7052
|
async function upsertStatusTransitionCommentAnnotation(ctx, params) {
|
|
6709
7053
|
const { issueId, commentId, annotation } = params;
|
|
6710
7054
|
await ctx.entities.upsert({
|
|
@@ -7743,6 +8087,40 @@ async function listRepositoryIssues(octokit, repository, state = "open", options
|
|
|
7743
8087
|
}
|
|
7744
8088
|
return normalizedIssues;
|
|
7745
8089
|
}
|
|
8090
|
+
async function listRepositoryIssuesForSyncTarget(octokit, repository, state, target, options = {}) {
|
|
8091
|
+
if (target?.kind !== "issue") {
|
|
8092
|
+
return listRepositoryIssues(octokit, repository, state, options);
|
|
8093
|
+
}
|
|
8094
|
+
if (target.githubIssueNumber === void 0) {
|
|
8095
|
+
if (options.onProgress) {
|
|
8096
|
+
await options.onProgress({
|
|
8097
|
+
loadedIssueCount: 0
|
|
8098
|
+
});
|
|
8099
|
+
}
|
|
8100
|
+
return [];
|
|
8101
|
+
}
|
|
8102
|
+
const response = await octokit.rest.issues.get({
|
|
8103
|
+
owner: repository.owner,
|
|
8104
|
+
repo: repository.repo,
|
|
8105
|
+
issue_number: target.githubIssueNumber,
|
|
8106
|
+
headers: {
|
|
8107
|
+
accept: "application/vnd.github+json",
|
|
8108
|
+
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
8109
|
+
}
|
|
8110
|
+
});
|
|
8111
|
+
const issue = response.data;
|
|
8112
|
+
if ("pull_request" in issue) {
|
|
8113
|
+
return [];
|
|
8114
|
+
}
|
|
8115
|
+
const normalizedIssue = normalizeGitHubIssueRecord(issue);
|
|
8116
|
+
const issues = state === "open" && normalizedIssue.state !== "open" ? [] : [normalizedIssue];
|
|
8117
|
+
if (options.onProgress) {
|
|
8118
|
+
await options.onProgress({
|
|
8119
|
+
loadedIssueCount: issues.length
|
|
8120
|
+
});
|
|
8121
|
+
}
|
|
8122
|
+
return issues;
|
|
8123
|
+
}
|
|
7746
8124
|
async function listRepositoryIssuesForImport(allIssues) {
|
|
7747
8125
|
return sortIssuesForImport(allIssues.filter((issue) => issue.state === "open"));
|
|
7748
8126
|
}
|
|
@@ -8565,6 +8943,20 @@ function normalizeOptionalToolString(value) {
|
|
|
8565
8943
|
function normalizeToolPositiveInteger(value) {
|
|
8566
8944
|
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
|
|
8567
8945
|
}
|
|
8946
|
+
function normalizePositiveIntegerReference(value) {
|
|
8947
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
|
|
8948
|
+
return value;
|
|
8949
|
+
}
|
|
8950
|
+
if (typeof value !== "string") {
|
|
8951
|
+
return void 0;
|
|
8952
|
+
}
|
|
8953
|
+
const match = value.trim().match(/^#?(\d+)$/);
|
|
8954
|
+
if (!match) {
|
|
8955
|
+
return void 0;
|
|
8956
|
+
}
|
|
8957
|
+
const parsed = Number(match[1]);
|
|
8958
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
8959
|
+
}
|
|
8568
8960
|
function normalizeToolStringArray(value) {
|
|
8569
8961
|
if (!Array.isArray(value)) {
|
|
8570
8962
|
return [];
|
|
@@ -8722,12 +9114,34 @@ async function handleCompanyMetricApiRoute(ctx, input) {
|
|
|
8722
9114
|
const pullRequestNumber = normalizeToolPositiveInteger(payload.pullRequestNumber);
|
|
8723
9115
|
const pullRequestUrl = normalizeGitHubPullRequestHtmlUrl(normalizeOptionalString2(payload.pullRequestUrl));
|
|
8724
9116
|
const eventKey = normalizeOptionalString2(payload.eventKey);
|
|
9117
|
+
const paperclipIssueId = normalizeOptionalString2(payload.paperclipIssueId);
|
|
9118
|
+
let linkedPaperclipIssueId;
|
|
9119
|
+
let linkedRepository = null;
|
|
9120
|
+
let linkedPullRequestNumber;
|
|
9121
|
+
let linkedPullRequestUrl;
|
|
9122
|
+
if (paperclipIssueId) {
|
|
9123
|
+
const linkResult = await linkPaperclipIssueToGitHubPullRequest(ctx, {
|
|
9124
|
+
companyId,
|
|
9125
|
+
issueId: paperclipIssueId,
|
|
9126
|
+
repositoryUrl: repository?.url,
|
|
9127
|
+
pullRequestNumber,
|
|
9128
|
+
pullRequestUrl
|
|
9129
|
+
});
|
|
9130
|
+
linkedPaperclipIssueId = typeof linkResult.paperclipIssueId === "string" ? linkResult.paperclipIssueId : paperclipIssueId;
|
|
9131
|
+
const resultRepositoryUrl = normalizeOptionalString2(linkResult.repositoryUrl);
|
|
9132
|
+
linkedRepository = resultRepositoryUrl ? parseRepositoryReference(resultRepositoryUrl) : null;
|
|
9133
|
+
linkedPullRequestNumber = normalizeToolPositiveInteger(linkResult.githubPullRequestNumber);
|
|
9134
|
+
linkedPullRequestUrl = normalizeGitHubPullRequestHtmlUrl(normalizeOptionalString2(linkResult.githubPullRequestUrl));
|
|
9135
|
+
}
|
|
9136
|
+
const metricRepositoryUrl = repository?.url ?? linkedRepository?.url;
|
|
9137
|
+
const metricPullRequestNumber = pullRequestNumber ?? linkedPullRequestNumber;
|
|
9138
|
+
const metricPullRequestUrl = pullRequestUrl ?? linkedPullRequestUrl;
|
|
8725
9139
|
const dedupeKey = buildCompanyMetricEventKey({
|
|
8726
9140
|
metric,
|
|
8727
9141
|
eventKey,
|
|
8728
|
-
repositoryUrl:
|
|
8729
|
-
pullRequestNumber,
|
|
8730
|
-
pullRequestUrl
|
|
9142
|
+
repositoryUrl: metricRepositoryUrl,
|
|
9143
|
+
pullRequestNumber: metricPullRequestNumber,
|
|
9144
|
+
pullRequestUrl: metricPullRequestUrl
|
|
8731
9145
|
});
|
|
8732
9146
|
if (!dedupeKey) {
|
|
8733
9147
|
throw new Error(
|
|
@@ -8742,9 +9156,9 @@ async function handleCompanyMetricApiRoute(ctx, input) {
|
|
|
8742
9156
|
count: normalizeToolPositiveInteger(payload.count),
|
|
8743
9157
|
occurredAt: normalizeOptionalString2(payload.occurredAt),
|
|
8744
9158
|
eventKey,
|
|
8745
|
-
repositoryUrl:
|
|
8746
|
-
pullRequestNumber,
|
|
8747
|
-
pullRequestUrl
|
|
9159
|
+
repositoryUrl: metricRepositoryUrl,
|
|
9160
|
+
pullRequestNumber: metricPullRequestNumber,
|
|
9161
|
+
pullRequestUrl: metricPullRequestUrl
|
|
8748
9162
|
},
|
|
8749
9163
|
{
|
|
8750
9164
|
throwOnPersistFailure: true
|
|
@@ -8756,9 +9170,10 @@ async function handleCompanyMetricApiRoute(ctx, input) {
|
|
|
8756
9170
|
routeKey: input.routeKey,
|
|
8757
9171
|
companyId,
|
|
8758
9172
|
metric,
|
|
8759
|
-
repositoryUrl:
|
|
8760
|
-
pullRequestNumber,
|
|
8761
|
-
pullRequestUrl,
|
|
9173
|
+
repositoryUrl: metricRepositoryUrl,
|
|
9174
|
+
pullRequestNumber: metricPullRequestNumber,
|
|
9175
|
+
pullRequestUrl: metricPullRequestUrl,
|
|
9176
|
+
linkedPaperclipIssueId: linkedPaperclipIssueId ?? null,
|
|
8762
9177
|
agentId: input.actor.agentId ?? null,
|
|
8763
9178
|
runId: input.actor.runId ?? null
|
|
8764
9179
|
}
|
|
@@ -8769,7 +9184,8 @@ async function handleCompanyMetricApiRoute(ctx, input) {
|
|
|
8769
9184
|
status: recordedMetric.recorded ? "recorded" : "duplicate",
|
|
8770
9185
|
recorded: recordedMetric.recorded,
|
|
8771
9186
|
companyId,
|
|
8772
|
-
metric: "pull_request_created"
|
|
9187
|
+
metric: "pull_request_created",
|
|
9188
|
+
...linkedPaperclipIssueId ? { paperclipIssueId: linkedPaperclipIssueId } : {}
|
|
8773
9189
|
}
|
|
8774
9190
|
};
|
|
8775
9191
|
}
|
|
@@ -11966,10 +12382,11 @@ async function performSync(ctx, trigger, options = {}) {
|
|
|
11966
12382
|
updateSyncFailureContext(failureContext, {
|
|
11967
12383
|
phase: "listing_github_issues"
|
|
11968
12384
|
});
|
|
11969
|
-
const allIssues = await
|
|
12385
|
+
const allIssues = await listRepositoryIssuesForSyncTarget(
|
|
11970
12386
|
octokit,
|
|
11971
12387
|
repository,
|
|
11972
12388
|
shouldLoadClosedIssues ? "all" : "open",
|
|
12389
|
+
options.target,
|
|
11973
12390
|
{
|
|
11974
12391
|
onProgress: async (progress) => {
|
|
11975
12392
|
currentProgress = {
|
|
@@ -12092,7 +12509,7 @@ async function performSync(ctx, trigger, options = {}) {
|
|
|
12092
12509
|
};
|
|
12093
12510
|
await persistRunningProgress(true);
|
|
12094
12511
|
try {
|
|
12095
|
-
const warmedLinkedPullRequests = await loadLinkedPullRequestsForOpenIssues(octokit, repository);
|
|
12512
|
+
const warmedLinkedPullRequests = options.target?.kind === "issue" ? /* @__PURE__ */ new Map() : await loadLinkedPullRequestsForOpenIssues(octokit, repository);
|
|
12096
12513
|
for (const [issueNumber, linkedPullRequests] of warmedLinkedPullRequests.entries()) {
|
|
12097
12514
|
linkedPullRequestsByIssueNumber.set(issueNumber, linkedPullRequests);
|
|
12098
12515
|
}
|
|
@@ -12727,7 +13144,13 @@ function registerGitHubAgentTools(ctx) {
|
|
|
12727
13144
|
getGitHubAgentToolDeclaration("create_pull_request"),
|
|
12728
13145
|
async (params, runCtx) => executeGitHubTool(async () => {
|
|
12729
13146
|
const input = getToolInputRecord(params);
|
|
12730
|
-
const
|
|
13147
|
+
const paperclipIssueId = normalizeOptionalToolString(input.paperclipIssueId);
|
|
13148
|
+
const explicitRepository = normalizeOptionalToolString(input.repository);
|
|
13149
|
+
const issueLinkScope = paperclipIssueId && !explicitRepository ? await resolveIssueGitHubLinkMapping(ctx, {
|
|
13150
|
+
companyId: runCtx.companyId,
|
|
13151
|
+
issueId: paperclipIssueId
|
|
13152
|
+
}) : null;
|
|
13153
|
+
const repository = issueLinkScope?.repository ?? await resolveGitHubToolRepository(ctx, runCtx, input);
|
|
12731
13154
|
const head = normalizeOptionalToolString(input.head);
|
|
12732
13155
|
const base = normalizeOptionalToolString(input.base);
|
|
12733
13156
|
const title = normalizeOptionalToolString(input.title);
|
|
@@ -12752,6 +13175,32 @@ function registerGitHubAgentTools(ctx) {
|
|
|
12752
13175
|
"X-GitHub-Api-Version": GITHUB_API_VERSION
|
|
12753
13176
|
}
|
|
12754
13177
|
});
|
|
13178
|
+
if (paperclipIssueId) {
|
|
13179
|
+
const linkScope = issueLinkScope ?? await resolveIssueGitHubLinkMapping(ctx, {
|
|
13180
|
+
companyId: runCtx.companyId,
|
|
13181
|
+
issueId: paperclipIssueId,
|
|
13182
|
+
repositoryUrl: repository.url
|
|
13183
|
+
});
|
|
13184
|
+
const pullRequestUrl = normalizeGitHubPullRequestHtmlUrl(response.data.html_url) ?? `${repository.url}/pull/${response.data.number}`;
|
|
13185
|
+
await upsertGitHubPullRequestLinkRecord(ctx, {
|
|
13186
|
+
companyId: runCtx.companyId,
|
|
13187
|
+
projectId: linkScope.mapping.paperclipProjectId ?? linkScope.projectId,
|
|
13188
|
+
issueId: paperclipIssueId,
|
|
13189
|
+
repositoryUrl: repository.url,
|
|
13190
|
+
pullRequestNumber: response.data.number,
|
|
13191
|
+
pullRequestUrl,
|
|
13192
|
+
pullRequestTitle: response.data.title || title,
|
|
13193
|
+
pullRequestState: getGitHubPullRequestStateForLink({
|
|
13194
|
+
state: response.data.state,
|
|
13195
|
+
merged: false
|
|
13196
|
+
})
|
|
13197
|
+
});
|
|
13198
|
+
invalidateProjectPullRequestCaches({
|
|
13199
|
+
companyId: runCtx.companyId,
|
|
13200
|
+
projectId: linkScope.mapping.paperclipProjectId ?? linkScope.projectId,
|
|
13201
|
+
repository
|
|
13202
|
+
});
|
|
13203
|
+
}
|
|
12755
13204
|
await persistCompanyActivityMetricEvent(
|
|
12756
13205
|
ctx,
|
|
12757
13206
|
{
|
|
@@ -13346,6 +13795,34 @@ var plugin = definePlugin({
|
|
|
13346
13795
|
const record = input && typeof input === "object" ? input : {};
|
|
13347
13796
|
return buildCommentAnnotationData(ctx, record);
|
|
13348
13797
|
});
|
|
13798
|
+
ctx.actions.register("issue.linkGitHubItem", async (input) => {
|
|
13799
|
+
const record = input && typeof input === "object" ? input : {};
|
|
13800
|
+
const kind = normalizeIssueGitHubLinkKind(record.kind);
|
|
13801
|
+
if (!kind) {
|
|
13802
|
+
throw new Error('kind must be "issue" or "pull_request".');
|
|
13803
|
+
}
|
|
13804
|
+
const companyId = normalizeCompanyId(record.companyId);
|
|
13805
|
+
const issueId = normalizeOptionalString2(record.issueId);
|
|
13806
|
+
if (!companyId || !issueId) {
|
|
13807
|
+
throw new Error("companyId and issueId are required.");
|
|
13808
|
+
}
|
|
13809
|
+
return kind === "issue" ? linkPaperclipIssueToGitHubIssue(ctx, {
|
|
13810
|
+
companyId,
|
|
13811
|
+
issueId,
|
|
13812
|
+
reference: record.reference,
|
|
13813
|
+
repositoryUrl: normalizeOptionalString2(record.repository),
|
|
13814
|
+
issueNumber: record.issueNumber,
|
|
13815
|
+
requireUnlinked: true
|
|
13816
|
+
}) : linkPaperclipIssueToGitHubPullRequest(ctx, {
|
|
13817
|
+
companyId,
|
|
13818
|
+
issueId,
|
|
13819
|
+
reference: record.reference,
|
|
13820
|
+
repositoryUrl: normalizeOptionalString2(record.repository),
|
|
13821
|
+
pullRequestNumber: record.pullRequestNumber,
|
|
13822
|
+
pullRequestUrl: record.pullRequestUrl,
|
|
13823
|
+
requireUnlinked: true
|
|
13824
|
+
});
|
|
13825
|
+
});
|
|
13349
13826
|
ctx.actions.register("settings.saveRegistration", async (input) => {
|
|
13350
13827
|
const previous = normalizeSettings(await ctx.state.get(SETTINGS_SCOPE));
|
|
13351
13828
|
const config = await getResolvedConfig(ctx);
|