paperclip-github-plugin 0.4.5 → 0.4.7
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 +3 -2
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +60 -11
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +129 -29
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -623,6 +623,8 @@ var GITHUB_TOKEN_PERMISSION_AUDIT_CACHE_TTL_MS = 5 * 6e4;
|
|
|
623
623
|
var MANUAL_SYNC_RESPONSE_GRACE_PERIOD_MS = 500;
|
|
624
624
|
var RUNNING_SYNC_MESSAGE = "GitHub sync is running in the background. This page will update when it finishes.";
|
|
625
625
|
var CANCELLING_SYNC_MESSAGE = "Cancellation requested. GitHub sync will stop after the current step finishes.";
|
|
626
|
+
var INTERRUPTED_SYNC_MESSAGE = "GitHub sync stopped unexpectedly before it finished. The worker restarted while the sync was running.";
|
|
627
|
+
var INTERRUPTED_SYNC_ACTION = "Run GitHub sync again. If it stops on the same repository or issue, retry that narrower scope to isolate the failing step.";
|
|
626
628
|
var SYNC_PROGRESS_PERSIST_INTERVAL_MS = 250;
|
|
627
629
|
var MAX_SYNC_FAILURE_LOG_ENTRIES = 25;
|
|
628
630
|
var GITHUB_SECONDARY_RATE_LIMIT_FALLBACK_MS = 6e4;
|
|
@@ -2895,6 +2897,97 @@ async function getSyncCancellationRequest(ctx) {
|
|
|
2895
2897
|
}
|
|
2896
2898
|
return normalizeSyncCancellationRequest(await ctx.state.get(SYNC_CANCELLATION_SCOPE));
|
|
2897
2899
|
}
|
|
2900
|
+
function buildInterruptedSyncMessage(progress) {
|
|
2901
|
+
const completedIssueCount = typeof progress?.completedIssueCount === "number" ? Math.max(0, progress.completedIssueCount) : void 0;
|
|
2902
|
+
const totalIssueCount = typeof progress?.totalIssueCount === "number" ? Math.max(0, progress.totalIssueCount) : void 0;
|
|
2903
|
+
const completionSummary = completedIssueCount !== void 0 && totalIssueCount !== void 0 ? ` Completed ${Math.min(completedIssueCount, totalIssueCount)} of ${totalIssueCount} issues before the worker restarted.` : "";
|
|
2904
|
+
return `${INTERRUPTED_SYNC_MESSAGE}${completionSummary}`;
|
|
2905
|
+
}
|
|
2906
|
+
function getInterruptedSyncFailurePhase(progress) {
|
|
2907
|
+
switch (progress?.phase) {
|
|
2908
|
+
case "preparing":
|
|
2909
|
+
return "building_import_plan";
|
|
2910
|
+
case "importing":
|
|
2911
|
+
return "importing_issue";
|
|
2912
|
+
case "syncing":
|
|
2913
|
+
return "evaluating_github_status";
|
|
2914
|
+
default:
|
|
2915
|
+
return void 0;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
function getActiveRunningSyncForScope(companyId) {
|
|
2919
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2920
|
+
if (activeRunningSyncState?.syncState.status !== "running") {
|
|
2921
|
+
return null;
|
|
2922
|
+
}
|
|
2923
|
+
const activeSyncMatchesScope = normalizedCompanyId === void 0 || activeRunningSyncCompanyId === void 0 || activeRunningSyncCompanyId === normalizedCompanyId;
|
|
2924
|
+
if (!activeSyncMatchesScope) {
|
|
2925
|
+
return null;
|
|
2926
|
+
}
|
|
2927
|
+
return materializeScopedSettings(activeRunningSyncState, null, normalizedCompanyId);
|
|
2928
|
+
}
|
|
2929
|
+
async function reconcileOrphanedRunningSyncState(ctx, companyId, resolution = "error") {
|
|
2930
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2931
|
+
const activeRunningSync = getActiveRunningSyncForScope(normalizedCompanyId);
|
|
2932
|
+
if (activeRunningSync) {
|
|
2933
|
+
return activeRunningSync;
|
|
2934
|
+
}
|
|
2935
|
+
const current = normalizeSettings(await ctx.state.get(SETTINGS_SCOPE));
|
|
2936
|
+
const scopedSyncState = getScopedSyncState(current, normalizedCompanyId);
|
|
2937
|
+
if (scopedSyncState.status !== "running") {
|
|
2938
|
+
return materializeScopedSettings(current, null, normalizedCompanyId);
|
|
2939
|
+
}
|
|
2940
|
+
const trigger = scopedSyncState.lastRunTrigger ?? "manual";
|
|
2941
|
+
const progress = normalizeSyncProgress(scopedSyncState.progress);
|
|
2942
|
+
const syncCounts = {
|
|
2943
|
+
syncedIssuesCount: scopedSyncState.syncedIssuesCount ?? 0,
|
|
2944
|
+
createdIssuesCount: scopedSyncState.createdIssuesCount ?? 0,
|
|
2945
|
+
skippedIssuesCount: scopedSyncState.skippedIssuesCount ?? 0,
|
|
2946
|
+
erroredIssuesCount: scopedSyncState.erroredIssuesCount ?? 0
|
|
2947
|
+
};
|
|
2948
|
+
const nextSyncState = resolution === "cancelled" || Boolean(scopedSyncState.cancelRequestedAt?.trim()) ? createCancelledSyncState({
|
|
2949
|
+
message: buildCancelledSyncMessage(void 0, progress),
|
|
2950
|
+
trigger,
|
|
2951
|
+
...syncCounts,
|
|
2952
|
+
...progress ? { progress } : {}
|
|
2953
|
+
}) : (() => {
|
|
2954
|
+
const errorDetails = normalizeSyncErrorDetails({
|
|
2955
|
+
...getInterruptedSyncFailurePhase(progress) ? { phase: getInterruptedSyncFailurePhase(progress) } : {},
|
|
2956
|
+
...progress?.currentRepositoryUrl ? { repositoryUrl: progress.currentRepositoryUrl } : {},
|
|
2957
|
+
...typeof progress?.currentIssueNumber === "number" ? { githubIssueNumber: progress.currentIssueNumber } : {},
|
|
2958
|
+
rawMessage: INTERRUPTED_SYNC_MESSAGE,
|
|
2959
|
+
suggestedAction: INTERRUPTED_SYNC_ACTION
|
|
2960
|
+
});
|
|
2961
|
+
const message = buildInterruptedSyncMessage(progress);
|
|
2962
|
+
return createErrorSyncState({
|
|
2963
|
+
message,
|
|
2964
|
+
trigger,
|
|
2965
|
+
...syncCounts,
|
|
2966
|
+
...progress ? { progress } : {},
|
|
2967
|
+
...errorDetails ? { errorDetails } : {},
|
|
2968
|
+
recentFailures: appendRecentSyncFailureLogEntry(
|
|
2969
|
+
scopedSyncState.recentFailures,
|
|
2970
|
+
createSyncFailureLogEntry({
|
|
2971
|
+
message,
|
|
2972
|
+
...errorDetails ? { errorDetails } : {}
|
|
2973
|
+
})
|
|
2974
|
+
)
|
|
2975
|
+
});
|
|
2976
|
+
})();
|
|
2977
|
+
const next = await saveSettingsSyncState(ctx, current, nextSyncState, normalizedCompanyId);
|
|
2978
|
+
await setSyncCancellationRequest(ctx, null);
|
|
2979
|
+
return next;
|
|
2980
|
+
}
|
|
2981
|
+
function resolvePersistedRunningSyncCompanyId(settings) {
|
|
2982
|
+
if (normalizeSyncState(settings.syncState).status === "running") {
|
|
2983
|
+
return void 0;
|
|
2984
|
+
}
|
|
2985
|
+
const runningCompanyIds = Object.entries(settings.syncStateByCompanyId ?? {}).flatMap(([companyId, syncState]) => {
|
|
2986
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2987
|
+
return normalizedCompanyId && normalizeSyncState(syncState).status === "running" ? [normalizedCompanyId] : [];
|
|
2988
|
+
});
|
|
2989
|
+
return runningCompanyIds.length === 1 ? runningCompanyIds[0] : null;
|
|
2990
|
+
}
|
|
2898
2991
|
function buildCancelledSyncMessage(target, progress) {
|
|
2899
2992
|
const completedIssueCount = typeof progress?.completedIssueCount === "number" ? Math.max(0, progress.completedIssueCount) : void 0;
|
|
2900
2993
|
const totalIssueCount = typeof progress?.totalIssueCount === "number" ? Math.max(0, progress.totalIssueCount) : void 0;
|
|
@@ -2949,11 +3042,11 @@ async function waitForSyncResultWithinGracePeriod(promise, timeoutMs) {
|
|
|
2949
3042
|
}
|
|
2950
3043
|
async function getActiveOrCurrentSyncState(ctx, companyId) {
|
|
2951
3044
|
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2952
|
-
|
|
2953
|
-
|
|
3045
|
+
const activeRunningSync = getActiveRunningSyncForScope(normalizedCompanyId);
|
|
3046
|
+
if (activeRunningSync) {
|
|
3047
|
+
return activeRunningSync;
|
|
2954
3048
|
}
|
|
2955
|
-
|
|
2956
|
-
return materializeScopedSettings(current, null, normalizedCompanyId);
|
|
3049
|
+
return reconcileOrphanedRunningSyncState(ctx, normalizedCompanyId);
|
|
2957
3050
|
}
|
|
2958
3051
|
function updateSyncFailureContext(current, next) {
|
|
2959
3052
|
if ("phase" in next) {
|
|
@@ -9467,6 +9560,9 @@ function shouldRunScheduledSync(settings, scheduledAt) {
|
|
|
9467
9560
|
if (getActiveGitHubRateLimitPause(settings.syncState, now)) {
|
|
9468
9561
|
return false;
|
|
9469
9562
|
}
|
|
9563
|
+
if (settings.syncState.status === "running") {
|
|
9564
|
+
return false;
|
|
9565
|
+
}
|
|
9470
9566
|
if (!settings.syncState.checkedAt) {
|
|
9471
9567
|
return true;
|
|
9472
9568
|
}
|
|
@@ -9956,28 +10052,25 @@ async function performSync(ctx, trigger, options = {}) {
|
|
|
9956
10052
|
await ctx.state.set(IMPORT_REGISTRY_SCOPE, nextRegistry);
|
|
9957
10053
|
return materializeScopedSettings(next2, config, targetCompanyId);
|
|
9958
10054
|
}
|
|
9959
|
-
const
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9968
|
-
erroredIssuesCount: 0,
|
|
9969
|
-
lastRunTrigger: trigger
|
|
9970
|
-
}
|
|
10055
|
+
const nextSyncState = {
|
|
10056
|
+
status: "success",
|
|
10057
|
+
message: `${options.target ? `GitHub sync for ${options.target.displayLabel} is complete. ` : "Sync complete. "}Imported ${createdIssuesCount} issues, updated ${updatedStatusesCount} issue status${updatedStatusesCount === 1 ? "" : "es"}, updated ${updatedLabelsCount} issue label set${updatedLabelsCount === 1 ? "" : "s"}, updated ${updatedDescriptionsCount} issue description${updatedDescriptionsCount === 1 ? "" : "s"}, and skipped ${skippedIssuesCount} already-synced issue${skippedIssuesCount === 1 ? "" : "s"}.`,
|
|
10058
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10059
|
+
syncedIssuesCount,
|
|
10060
|
+
createdIssuesCount,
|
|
10061
|
+
skippedIssuesCount,
|
|
10062
|
+
erroredIssuesCount: 0,
|
|
10063
|
+
lastRunTrigger: trigger
|
|
9971
10064
|
};
|
|
9972
|
-
await ctx
|
|
9973
|
-
await ctx.state.set(SYNC_STATE_SCOPE, next.syncState);
|
|
10065
|
+
const next = await saveSettingsSyncState(ctx, currentSettings, nextSyncState, targetCompanyId);
|
|
9974
10066
|
await ctx.state.set(IMPORT_REGISTRY_SCOPE, nextRegistry);
|
|
9975
10067
|
return next;
|
|
9976
10068
|
} catch (error) {
|
|
9977
10069
|
if (error instanceof SyncCancellationError) {
|
|
9978
|
-
const next2 =
|
|
9979
|
-
|
|
9980
|
-
|
|
10070
|
+
const next2 = await saveSettingsSyncState(
|
|
10071
|
+
ctx,
|
|
10072
|
+
currentSettings,
|
|
10073
|
+
createCancelledSyncState({
|
|
9981
10074
|
message: buildCancelledSyncMessage(options.target, currentProgress),
|
|
9982
10075
|
trigger,
|
|
9983
10076
|
syncedIssuesCount,
|
|
@@ -9985,10 +10078,9 @@ async function performSync(ctx, trigger, options = {}) {
|
|
|
9985
10078
|
skippedIssuesCount,
|
|
9986
10079
|
erroredIssuesCount: recoverableFailures.length,
|
|
9987
10080
|
progress: currentProgress
|
|
9988
|
-
})
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
await ctx.state.set(SYNC_STATE_SCOPE, next2.syncState);
|
|
10081
|
+
}),
|
|
10082
|
+
targetCompanyId
|
|
10083
|
+
);
|
|
9992
10084
|
await ctx.state.set(IMPORT_REGISTRY_SCOPE, nextRegistry);
|
|
9993
10085
|
return next2;
|
|
9994
10086
|
}
|
|
@@ -10026,6 +10118,7 @@ async function startSync(ctx, trigger, options = {}) {
|
|
|
10026
10118
|
);
|
|
10027
10119
|
return quickResult2 ?? await getActiveOrCurrentSyncState(ctx);
|
|
10028
10120
|
}
|
|
10121
|
+
await reconcileOrphanedRunningSyncState(ctx, options.target?.companyId);
|
|
10029
10122
|
const [config, persistedSettings] = await Promise.all([
|
|
10030
10123
|
getResolvedConfig(ctx),
|
|
10031
10124
|
ctx.state.get(SETTINGS_SCOPE).then((value) => normalizeSettings(value))
|
|
@@ -10893,6 +10986,7 @@ var plugin = definePlugin({
|
|
|
10893
10986
|
const record = input && typeof input === "object" ? input : {};
|
|
10894
10987
|
const requestedCompanyId = normalizeCompanyId(record.companyId);
|
|
10895
10988
|
const includeAssignees = Boolean(requestedCompanyId && record.includeAssignees === true);
|
|
10989
|
+
await reconcileOrphanedRunningSyncState(ctx, requestedCompanyId);
|
|
10896
10990
|
const saved = await ctx.state.get(SETTINGS_SCOPE);
|
|
10897
10991
|
const importRegistry = normalizeImportRegistry(await ctx.state.get(IMPORT_REGISTRY_SCOPE));
|
|
10898
10992
|
const normalizedSettings = normalizeSettings(saved);
|
|
@@ -11179,7 +11273,12 @@ var plugin = definePlugin({
|
|
|
11179
11273
|
});
|
|
11180
11274
|
});
|
|
11181
11275
|
ctx.actions.register("sync.cancel", async () => {
|
|
11182
|
-
const
|
|
11276
|
+
const persistedRunningSyncCompanyId = activeRunningSyncState?.syncState.status === "running" ? activeRunningSyncCompanyId : resolvePersistedRunningSyncCompanyId(normalizeSettings(await ctx.state.get(SETTINGS_SCOPE)));
|
|
11277
|
+
const currentSettings = await reconcileOrphanedRunningSyncState(
|
|
11278
|
+
ctx,
|
|
11279
|
+
persistedRunningSyncCompanyId === null ? void 0 : persistedRunningSyncCompanyId,
|
|
11280
|
+
"cancelled"
|
|
11281
|
+
);
|
|
11183
11282
|
if (currentSettings.syncState.status !== "running") {
|
|
11184
11283
|
return currentSettings;
|
|
11185
11284
|
}
|
|
@@ -11200,7 +11299,7 @@ var plugin = definePlugin({
|
|
|
11200
11299
|
message: CANCELLING_SYNC_MESSAGE,
|
|
11201
11300
|
cancelRequestedAt: cancellationRequest.requestedAt
|
|
11202
11301
|
}),
|
|
11203
|
-
|
|
11302
|
+
persistedRunningSyncCompanyId === null ? void 0 : persistedRunningSyncCompanyId
|
|
11204
11303
|
);
|
|
11205
11304
|
activeRunningSyncState = next;
|
|
11206
11305
|
return next;
|
|
@@ -11211,14 +11310,15 @@ var plugin = definePlugin({
|
|
|
11211
11310
|
const trigger = job.trigger === "retry" ? "retry" : "schedule";
|
|
11212
11311
|
const scheduledTargets = listScheduledSyncTargets(settings);
|
|
11213
11312
|
if (scheduledTargets.length === 0) {
|
|
11214
|
-
|
|
11313
|
+
const reconciledSettings = await reconcileOrphanedRunningSyncState(ctx);
|
|
11314
|
+
if (job.trigger === "schedule" && !shouldRunScheduledSync(reconciledSettings, job.scheduledAt)) {
|
|
11215
11315
|
return;
|
|
11216
11316
|
}
|
|
11217
11317
|
await startSync(ctx, trigger);
|
|
11218
11318
|
return;
|
|
11219
11319
|
}
|
|
11220
11320
|
for (const target of scheduledTargets) {
|
|
11221
|
-
const scopedSettings =
|
|
11321
|
+
const scopedSettings = await reconcileOrphanedRunningSyncState(ctx, target?.companyId);
|
|
11222
11322
|
if (job.trigger === "schedule" && !shouldRunScheduledSync(scopedSettings, job.scheduledAt)) {
|
|
11223
11323
|
continue;
|
|
11224
11324
|
}
|