canopycms 0.12.0 → 0.13.0
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/CHANGELOG.md +326 -48
- package/dist/api/admin.d.ts +4 -4
- package/dist/api/branch-review.d.ts +20 -2
- package/dist/api/branch-review.js +153 -32
- package/dist/api/branch-status.d.ts +23 -2
- package/dist/api/branch-status.js +16 -2
- package/dist/api/branch-update-from-base.d.ts +23 -0
- package/dist/api/branch-update-from-base.js +227 -0
- package/dist/api/branch.d.ts +10 -0
- package/dist/api/branch.js +28 -2
- package/dist/api/client.d.ts +15 -2
- package/dist/api/client.js +24 -2
- package/dist/api/comments.d.ts +2 -2
- package/dist/api/content.d.ts +38 -1
- package/dist/api/content.js +41 -5
- package/dist/api/merge-conflicts.d.ts +235 -0
- package/dist/api/merge-conflicts.js +709 -0
- package/dist/api/routes.js +2 -0
- package/dist/api/types.d.ts +8 -3
- package/dist/base-update.d.ts +32 -0
- package/dist/base-update.js +31 -0
- package/dist/branch-metadata-file.d.ts +66 -0
- package/dist/branch-metadata-file.js +16 -1
- package/dist/branch-schema-cache.d.ts +12 -0
- package/dist/branch-schema-cache.js +27 -2
- package/dist/cli/backfill-item-keys.d.ts +77 -0
- package/dist/cli/backfill-item-keys.js +320 -0
- package/dist/cli/cli.d.ts +1 -1
- package/dist/cli/cli.js +9798 -1509
- package/dist/cli/generate-ai-content.js +373 -249
- package/dist/cli/github-app-manifest.d.ts +4 -1
- package/dist/cli/github-app-manifest.js +5 -1
- package/dist/cli/init.js +12 -0
- package/dist/cli/site-config.d.ts +14 -2
- package/dist/cli/site-config.js +20 -4
- package/dist/comment-store.d.ts +8 -0
- package/dist/comment-store.js +28 -0
- package/dist/content-index-generation.d.ts +1 -4
- package/dist/content-index-generation.js +1 -4
- package/dist/content-store.d.ts +39 -3
- package/dist/content-store.js +48 -15
- package/dist/editor/BranchManager.d.ts +4 -1
- package/dist/editor/BranchManager.js +9 -5
- package/dist/editor/Editor.js +462 -62
- package/dist/editor/EntryNavigator.d.ts +10 -2
- package/dist/editor/EntryNavigator.js +12 -4
- package/dist/editor/FormRenderer.d.ts +8 -2
- package/dist/editor/FormRenderer.js +5 -6
- package/dist/editor/admin/ConflictsStatusAlert.d.ts +8 -0
- package/dist/editor/admin/ConflictsStatusAlert.js +22 -0
- package/dist/editor/admin/SystemHealthPanel.js +4 -3
- package/dist/editor/base-update-wait.d.ts +78 -0
- package/dist/editor/base-update-wait.js +98 -0
- package/dist/editor/branch-status.js +1 -1
- package/dist/editor/components/BaseUpdateNotice.d.ts +12 -0
- package/dist/editor/components/BaseUpdateNotice.js +24 -0
- package/dist/editor/components/BranchPill.d.ts +4 -1
- package/dist/editor/components/BranchPill.js +5 -2
- package/dist/editor/components/ConflictsGroup.d.ts +112 -0
- package/dist/editor/components/ConflictsGroup.js +404 -0
- package/dist/editor/components/EditorHeader.d.ts +18 -1
- package/dist/editor/components/EditorHeader.js +99 -33
- package/dist/editor/components/EntryChangesDrawer.d.ts +16 -2
- package/dist/editor/components/EntryChangesDrawer.js +85 -167
- package/dist/editor/components/EntryHeader.d.ts +3 -1
- package/dist/editor/components/EntryHeader.js +2 -2
- package/dist/editor/components/GetLatestChangesButton.d.ts +15 -0
- package/dist/editor/components/GetLatestChangesButton.js +29 -0
- package/dist/editor/components/ReleaseHoldButton.d.ts +20 -0
- package/dist/editor/components/ReleaseHoldButton.js +36 -0
- package/dist/editor/components/RetryToastMessage.js +1 -1
- package/dist/editor/components/change-parts.d.ts +51 -0
- package/dist/editor/components/change-parts.js +171 -0
- package/dist/editor/conflict-cards.d.ts +93 -0
- package/dist/editor/conflict-cards.js +284 -0
- package/dist/editor/conflict-choices.d.ts +60 -0
- package/dist/editor/conflict-choices.js +108 -0
- package/dist/editor/conflict-notice.d.ts +25 -0
- package/dist/editor/conflict-notice.js +39 -0
- package/dist/editor/copy.d.ts +12 -0
- package/dist/editor/copy.js +12 -0
- package/dist/editor/entry-diff.d.ts +2 -1
- package/dist/editor/entry-diff.js +5 -21
- package/dist/editor/hooks/useBaseUpdate.d.ts +38 -0
- package/dist/editor/hooks/useBaseUpdate.js +279 -0
- package/dist/editor/hooks/useBranchChangesData.d.ts +7 -1
- package/dist/editor/hooks/useBranchChangesData.js +13 -0
- package/dist/editor/hooks/useBranchManager.d.ts +8 -1
- package/dist/editor/hooks/useBranchManager.js +108 -13
- package/dist/editor/hooks/useBranchesData.js +3 -0
- package/dist/editor/hooks/useConflictChoices.d.ts +24 -0
- package/dist/editor/hooks/useConflictChoices.js +75 -0
- package/dist/editor/hooks/useConflictsData.d.ts +26 -0
- package/dist/editor/hooks/useConflictsData.js +89 -0
- package/dist/editor/hooks/useDraftManager.d.ts +13 -1
- package/dist/editor/hooks/useDraftManager.js +40 -9
- package/dist/editor/hooks/useEntryManager.d.ts +17 -3
- package/dist/editor/hooks/useEntryManager.js +11 -5
- package/dist/editor/release-hold.d.ts +12 -0
- package/dist/editor/release-hold.js +39 -0
- package/dist/editor/server-clock.d.ts +4 -0
- package/dist/editor/server-clock.js +15 -0
- package/dist/editor/undo-change.d.ts +7 -0
- package/dist/editor/undo-change.js +19 -4
- package/dist/git-manager.d.ts +6 -0
- package/dist/git-manager.js +38 -3
- package/dist/item-keys.d.ts +13 -0
- package/dist/item-keys.js +36 -14
- package/dist/merge/conflict-path.d.ts +40 -0
- package/dist/merge/conflict-path.js +128 -0
- package/dist/merge/diff3.d.ts +27 -0
- package/dist/merge/diff3.js +113 -0
- package/dist/merge/entry-merge.d.ts +94 -0
- package/dist/merge/entry-merge.js +876 -0
- package/dist/merge/list-alignment.d.ts +55 -0
- package/dist/merge/list-alignment.js +490 -0
- package/dist/merge/rekey.d.ts +11 -0
- package/dist/merge/rekey.js +75 -0
- package/dist/merge/text-merge.d.ts +29 -0
- package/dist/merge/text-merge.js +59 -0
- package/dist/merge/value-equality.d.ts +18 -0
- package/dist/merge/value-equality.js +50 -0
- package/dist/merge-conflicts.d.ts +232 -0
- package/dist/merge-conflicts.js +451 -0
- package/dist/operating-mode/client-safe-strategy.d.ts +2 -0
- package/dist/operating-mode/client-safe-strategy.js +6 -0
- package/dist/operating-mode/client-unsafe-strategy.js +6 -0
- package/dist/operating-mode/types.d.ts +13 -0
- package/dist/services.d.ts +24 -1
- package/dist/services.js +138 -22
- package/dist/task-queue/cms-task-queue.d.ts +3 -1
- package/dist/types.d.ts +63 -5
- package/dist/utils/content-serialize.d.ts +18 -1
- package/dist/utils/content-serialize.js +12 -0
- package/dist/utils/content-write-lock.d.ts +3 -3
- package/dist/utils/content-write-lock.js +3 -3
- package/dist/utils/git.d.ts +7 -0
- package/dist/utils/git.js +35 -0
- package/dist/utils/markdown-body-splice.d.ts +1 -1
- package/dist/utils/markdown-body-splice.js +1 -19
- package/dist/utils/markdown-parse.d.ts +9 -0
- package/dist/utils/markdown-parse.js +27 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/branch-merge.d.ts +80 -40
- package/dist/worker/branch-merge.js +244 -58
- package/dist/worker/branch-policy.d.ts +18 -2
- package/dist/worker/branch-policy.js +36 -0
- package/dist/worker/cms-worker.d.ts +37 -3
- package/dist/worker/cms-worker.js +88 -16
- package/dist/worker/conflicts-status.d.ts +20 -0
- package/dist/worker/conflicts-status.js +204 -0
- package/dist/worker/field-merge.d.ts +80 -0
- package/dist/worker/field-merge.js +729 -0
- package/dist/worker/git-sync.d.ts +3 -2
- package/dist/worker/git-sync.js +16 -6
- package/dist/worker/github-commits.d.ts +42 -10
- package/dist/worker/github-commits.js +444 -52
- package/dist/worker/github-errors.d.ts +15 -0
- package/dist/worker/github-errors.js +47 -0
- package/dist/worker/github-gateway-http.js +24 -9
- package/dist/worker/github-gateway-wire.d.ts +49 -20
- package/dist/worker/github-gateway-wire.js +19 -3
- package/dist/worker/github-gateway.d.ts +27 -1
- package/dist/worker/github-gateway.js +55 -7
- package/dist/worker/github-transfer.d.ts +5 -3
- package/dist/worker/github-transfer.js +8 -5
- package/dist/worker/history-rewrite.d.ts +40 -8
- package/dist/worker/history-rewrite.js +51 -23
- package/dist/worker/publish-decision.d.ts +37 -0
- package/dist/worker/publish-decision.js +16 -0
- package/dist/worker/rebase.d.ts +29 -8
- package/dist/worker/rebase.js +492 -211
- package/dist/worker/task-runner.d.ts +1 -1
- package/dist/worker/task-runner.js +30 -41
- package/dist/worker/worker-context.d.ts +24 -2
- package/package.json +1 -1
|
@@ -16,7 +16,8 @@ import type { WorkerContext } from './worker-context.js';
|
|
|
16
16
|
* says the serving editor lacks a schema the incoming content names), push this
|
|
17
17
|
* deployment's own settings
|
|
18
18
|
* branch, fast-forward the base branch's workspace, ask the gateway for its branch policy,
|
|
19
|
-
* rebase every branch that is behind it (rebase.ts),
|
|
19
|
+
* rebase every branch that is behind it (rebase.ts), set each pull request's conflicts status
|
|
20
|
+
* (conflicts-status.ts), then sweep old tasks, expired trashed
|
|
20
21
|
* branch directories and, where retention is on, expired archived branches.
|
|
21
22
|
*
|
|
22
23
|
* One ordering is load-bearing and nothing enforces it: `runRebaseCycle` MUST
|
|
@@ -32,7 +33,7 @@ import type { WorkerContext } from './worker-context.js';
|
|
|
32
33
|
* The whole cycle is wrapped so both outcomes record a worker-status.json
|
|
33
34
|
* snapshot, since an operator's only view of this loop is the admin panel.
|
|
34
35
|
*/
|
|
35
|
-
export type GitSyncContext = Pick<WorkerContext, 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'remoteGitPath' | 'schemaHoldMaxMs' | 'archivedBranchRetentionDays' | 'taskDir' | 'taskTimeoutMs' | 'log' | 'github' | 'ensureSettingsBranch' | 'ensureStatusReport' | 'warnedDivergences' | 'isRunning' | 'isDraining' | 'shutdownSignal'> & RebaseContext;
|
|
36
|
+
export type GitSyncContext = Pick<WorkerContext, 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'remoteGitPath' | 'schemaHoldMaxMs' | 'archivedBranchRetentionDays' | 'taskDir' | 'taskTimeoutMs' | 'log' | 'github' | 'ensureSettingsBranch' | 'ensureStatusReport' | 'warnedDivergences' | 'conflictsStatusesSet' | 'isRunning' | 'takeBranchSyncRequests' | 'isDraining' | 'shutdownSignal'> & RebaseContext;
|
|
36
37
|
/**
|
|
37
38
|
* Push THIS deployment's own settings branch (`ensureSettingsBranch()`) from
|
|
38
39
|
* remote.git to GitHub. Non-fatal. Skipped when `trackedTips`, GitHub's tips
|
package/dist/worker/git-sync.js
CHANGED
|
@@ -14,6 +14,7 @@ import { escapeForLog } from '../utils/escape-text.js';
|
|
|
14
14
|
import { CANOPY_META_DIR, isCanopyInternalPath, isNonFastForwardRejection } from '../utils/git.js';
|
|
15
15
|
import { MAX_REPORTED_PATHS, TRACKED_CANOPY_STATE_FIX, isUntracked, listTrackedCanopyState, restoreRetiredSchemaCache, splitByUpstreamTracking, untrackInIndex, } from './canopy-state.js';
|
|
16
16
|
import { sweepArchivedBranches } from './archived-sweep.js';
|
|
17
|
+
import { setConflictsStatuses } from './conflicts-status.js';
|
|
17
18
|
import { hasPendingHistoryRewrite, recordSeenOnGitHub } from './history-rewrite.js';
|
|
18
19
|
import { runRebaseCycle } from './rebase.js';
|
|
19
20
|
import { describeMove } from './github-gateway.js';
|
|
@@ -418,6 +419,9 @@ function warnOnce(warned, lines) {
|
|
|
418
419
|
export async function syncGit(ctx) {
|
|
419
420
|
if (!ctx.isRunning())
|
|
420
421
|
return;
|
|
422
|
+
// Taken first, so a cycle that fails before its fetch can't leave the loop waking early for good.
|
|
423
|
+
// A request made later in the cycle waits for the next one, whose fetch begins after it.
|
|
424
|
+
const requested = ctx.takeBranchSyncRequests();
|
|
421
425
|
// The CDK worker-down alarm counts this line (WORKER_SYNC_LOG_PHRASE in
|
|
422
426
|
// canopycms-cdk worker-lifecycle.ts); changing its text breaks the alarm.
|
|
423
427
|
workerLog('Syncing git...');
|
|
@@ -468,8 +472,9 @@ export async function syncGit(ctx) {
|
|
|
468
472
|
// deadline: the wait for the gateway's GitHub fetch, which runs on detached, then the gateway's
|
|
469
473
|
// bundle, the unbundle and the ref update; a killed ref update leaves each ref as it was or
|
|
470
474
|
// fully moved.
|
|
471
|
-
|
|
472
|
-
|
|
475
|
+
// A woken cycle takes no GitHub fetch the gateway began earlier: answers to a request for the
|
|
476
|
+
// latest changes are timed by this fetch's start (worker/rebase.ts, answerBaseUpdate).
|
|
477
|
+
const { refs: githubTips, fetchedAt, needsOperator, } = await fetchGitHubIntoRemoteGit(ctx, ctx.shutdownSignal(), requested.requested);
|
|
473
478
|
workerLog('Fetched from GitHub');
|
|
474
479
|
if (needsOperator !== null)
|
|
475
480
|
workerLogError(needsOperator);
|
|
@@ -512,12 +517,12 @@ export async function syncGit(ctx) {
|
|
|
512
517
|
report.gatewayProtectedBranches = branchPolicy.configured.filter((n) => !n.includes('*'));
|
|
513
518
|
await writeWorkerStatus(ctx.taskDir, report).catch((writeErr) => workerLogError('Failed to write worker status:', getErrorMessage(writeErr)));
|
|
514
519
|
}
|
|
515
|
-
const rebaseSummary = await runRebaseCycle(ctx, branchPolicy, {
|
|
516
|
-
tips: githubTips,
|
|
517
|
-
fetchedAt,
|
|
518
|
-
});
|
|
520
|
+
const rebaseSummary = await runRebaseCycle(ctx, branchPolicy, { tips: githubTips, fetchedAt }, requested.branches);
|
|
519
521
|
if (stoppedForDrain(ctx, 'the cleanup sweeps'))
|
|
520
522
|
return;
|
|
523
|
+
// After the rebase cycle, whose merges can change a branch's conflicts. Heads the cycle's own
|
|
524
|
+
// pushes move are set by the cycle each push wakes.
|
|
525
|
+
const conflictsStatusFailure = await setConflictsStatuses(ctx, githubTips);
|
|
521
526
|
await cleanupOldTasks(ctx.taskDir, undefined, ctx.log);
|
|
522
527
|
// For System health: the branches the gateway would refuse to publish, read after the rebase
|
|
523
528
|
// cycle, which archives merged branches and restores renamed ones. Without a policy, a fatal
|
|
@@ -550,6 +555,11 @@ export async function syncGit(ctx) {
|
|
|
550
555
|
const report = ctx.ensureStatusReport();
|
|
551
556
|
report.lastGitSyncAt = new Date().toISOString();
|
|
552
557
|
delete report.lastGitSyncError;
|
|
558
|
+
// null: the stage could not say, so the last report stands.
|
|
559
|
+
if (conflictsStatusFailure)
|
|
560
|
+
report.conflictsStatusFailure = conflictsStatusFailure;
|
|
561
|
+
else if (conflictsStatusFailure === undefined)
|
|
562
|
+
delete report.conflictsStatusFailure;
|
|
553
563
|
// Recorded once the cycle has done everything it can, so System health shows it.
|
|
554
564
|
if (needsOperator !== null) {
|
|
555
565
|
report.lastGitSyncError = { message: needsOperator, at: report.lastGitSyncAt };
|
|
@@ -44,9 +44,13 @@ export type GitHubCommitsOutcome =
|
|
|
44
44
|
| {
|
|
45
45
|
kind: 'unpushed';
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* A merge landed. A rebase now would replace a merge GitHub has not received. `keptEntries`
|
|
49
|
+
* counts the entries with a conflict it left for a person.
|
|
50
|
+
*/
|
|
48
51
|
| {
|
|
49
52
|
kind: 'merged';
|
|
53
|
+
keptEntries: number;
|
|
50
54
|
}
|
|
51
55
|
/** Left as it is until a person acts. `reason` says what to do. */
|
|
52
56
|
| {
|
|
@@ -76,28 +80,56 @@ export declare const SEEN_COMMIT_GONE_PUSH_REFUSAL = "A commit this branch had o
|
|
|
76
80
|
* be combined. The failed sync it left goes too, unless {@link awaitsSubmitRetry}.
|
|
77
81
|
*/
|
|
78
82
|
export declare function rewriteCleared(branch: BranchMetadata): Partial<BranchMetadata>;
|
|
83
|
+
/** A branch this deployment put on GitHub. Any other GitHub branch of that name is not its own. */
|
|
84
|
+
export declare function isPublished({ branch }: BranchMetadataFile): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Fast-forward the clone to the merge this worker was landing, when `remote.git` holds it on top of
|
|
87
|
+
* the clone, as a crash or a lost lock between publishing it and moving the clone leaves it,
|
|
88
|
+
* whether or not the branch is on GitHub. Resolves why it stopped, or null when there was nothing
|
|
89
|
+
* to catch up with or it caught up.
|
|
90
|
+
*/
|
|
91
|
+
export declare function catchUpWithPublished(ctx: GitHubCommitsContext, args: GitHubCommitsArgs): Promise<GitHubCommitsOutcome | null>;
|
|
79
92
|
/** Bring GitHub's commits into the clone. Throws what git throws; the caller records it. */
|
|
80
93
|
export declare function bringInGitHubCommits(ctx: GitHubCommitsContext, args: GitHubCommitsArgs): Promise<GitHubCommitsOutcome>;
|
|
81
94
|
/**
|
|
82
|
-
* `other` merged into the branch: built, published to `remote.git
|
|
83
|
-
*
|
|
84
|
-
* last touches the working tree. `fromGitHub` says `other` is GitHub's tip rather than the
|
|
85
|
-
* `
|
|
86
|
-
*
|
|
95
|
+
* `other` merged into the branch: built, recorded, published to `remote.git` and queued for GitHub
|
|
96
|
+
* unless it holds unsubmitted work (publish-decision.ts), and the clone moved to it, in that order,
|
|
97
|
+
* so each step leaves what the next cycle picks up and only the last touches the working tree. `fromGitHub` says `other` is GitHub's tip rather than the
|
|
98
|
+
* base. `inReview` takes only a merge with nothing for a person to choose; any other leaves the
|
|
99
|
+
* branch as it is and records nothing, and GitHub's own conflict notice stands on the pull request. A lock lost before the clone moves leaves it where it was: `wait`.
|
|
87
100
|
*/
|
|
88
101
|
export declare function mergeIntoBranch(ctx: GitHubCommitsContext, args: GitHubCommitsArgs, merge: {
|
|
89
102
|
head: string;
|
|
90
103
|
other: string;
|
|
91
104
|
message: string;
|
|
92
105
|
fromGitHub: boolean;
|
|
93
|
-
|
|
106
|
+
inReview?: boolean;
|
|
94
107
|
}): Promise<GitHubCommitsOutcome>;
|
|
95
108
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
109
|
+
* Whether `commit` contains `ancestor`. A commit this clone does not hold counts as no. Any other
|
|
110
|
+
* failure throws, since it says nothing about either commit, and the caller's catch retries next
|
|
111
|
+
* cycle: read as no, it would report a rewrite that never happened.
|
|
112
|
+
*/
|
|
113
|
+
export declare function contains(git: SimpleGit, commit: string, ancestor: string): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Send an approved branch back to review and clear the verdict from the PR body. Called before the
|
|
116
|
+
* clone moves, where a failed save throws, so a crash or a failure leaves the commits for the next
|
|
117
|
+
* cycle to judge again rather than an approval standing over them.
|
|
99
118
|
*/
|
|
100
119
|
export declare function returnToReview(ctx: GitHubCommitsContext, { branchPath, branchDir, branchRef, metaFile }: GitHubCommitsArgs): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Bring merge-conflicts.json in line with the branch's history: a record changed by a merge the
|
|
122
|
+
* branch never got gives back the one it replaced (`withoutMergesGone`), and `branch.json`
|
|
123
|
+
* `conflictFiles` follows the record when the two differ. A merge counts as held while the clone or
|
|
124
|
+
* `remote.git` holds it, since a clone behind its published merge catches up with it; comment
|
|
125
|
+
* threads take a merge's item keys only once the clone holds it. While either can't be read in the
|
|
126
|
+
* clone, nothing is judged. A record that does not parse is moved aside, so the branch's merges
|
|
127
|
+
* carry on with a new one. Each cycle, before the branch takes anything in. A clone with no record
|
|
128
|
+
* has no conflict open, so `conflictFiles` written before the record existed clears. Never throws.
|
|
129
|
+
*/
|
|
130
|
+
export declare function reconcileMergeConflicts(ctx: GitHubCommitsContext, { git, branchPath, branchDir, branchRef, }: Pick<GitHubCommitsArgs, 'git' | 'branchPath' | 'branchDir'> & {
|
|
131
|
+
branchRef: string | null;
|
|
132
|
+
}): Promise<void>;
|
|
101
133
|
/**
|
|
102
134
|
* Re-render the PR body's review block alone: the worker has no `config.editorUrl`, so a full
|
|
103
135
|
* sync from here would strip the comment summary's links. Best-effort: a failure leaves the block
|