@teambit/ci 1.0.383 → 1.0.385

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.
@@ -9,6 +9,7 @@ type Options = {
9
9
  lane?: string;
10
10
  strict?: boolean;
11
11
  dryRun?: boolean;
12
+ keepLane?: boolean;
12
13
  };
13
14
 
14
15
  export class CiPrCmd implements Command {
@@ -23,6 +24,11 @@ export class CiPrCmd implements Command {
23
24
  ['b', 'build', 'Set to true to build the app locally, false (default) will build on Ripple CI'],
24
25
  ['s', 'strict', 'Set to true to fail on warnings as well as errors, false (default) only fails on errors'],
25
26
  ['d', 'dry-run', 'Run the full pipeline but skip exporting to remote (build runs only if --build is set)'],
27
+ [
28
+ '',
29
+ 'keep-lane',
30
+ 'Reuse the same remote lane across PR commits (preserves lane history and cloud UI edits) instead of recreating it on every run',
31
+ ],
26
32
  ];
27
33
 
28
34
  constructor(
@@ -67,6 +73,7 @@ export class CiPrCmd implements Command {
67
73
  build: options.build,
68
74
  strict: options.strict,
69
75
  dryRun: options.dryRun,
76
+ keepLane: options.keepLane,
70
77
  });
71
78
 
72
79
  if (results) {
@@ -112,18 +112,106 @@ export declare class CiMain {
112
112
  private parseVersionBumpFromCommit;
113
113
  private getCustomCommitMessage;
114
114
  private verifyWorkspaceStatusInternal;
115
+ /**
116
+ * Returns the caught Error on failure, or undefined on success (including the "already checked
117
+ * out" no-op case). Callers that need to react to a specific failure mode (e.g. stale lane) can
118
+ * inspect the returned error; existing callers ignore it and rely on a follow-up
119
+ * `getCurrentLane()` check.
120
+ */
115
121
  private switchToLane;
122
+ /**
123
+ * Sync *config-only* changes from main onto the lane — without a full `bit lane merge`.
124
+ *
125
+ * In this workflow git is the source of truth for files: the PR author merges the default branch
126
+ * into their PR branch, so source changes arrive via git. The one thing git can't carry is
127
+ * config that's already been *tagged into objects* on main — e.g. another PR ran `bit env set` /
128
+ * `bit deps set`; those records lived in `.bitmap`, rode git into main, and `bit ci merge` baked
129
+ * them into the component's Version (clearing them from `.bitmap`). A long-running PR's lane
130
+ * would otherwise miss them.
131
+ *
132
+ * A full lane merge is the wrong tool here: it does a 3-way *file* merge and refuses to run while
133
+ * the workspace has modified components — but in `bit ci pr` the workspace is always dirty (the
134
+ * PR's changes, not yet snapped). So instead we do a per-component 3-way merge of the aspect
135
+ * *config only* (base = common ancestor, ours = lane, theirs = main), keeping the PR's config on
136
+ * conflict, and stash the result on an `unmergedComponents` entry's `mergedConfig`. The
137
+ * subsequent `snap` reads it (via the aspects-merger on component load) and bakes main's config
138
+ * into the new snap, while the snap's files still come from the workspace (git). No file
139
+ * checkout, so no clean-workspace requirement.
140
+ */
141
+ private syncConfigFromMain;
142
+ /**
143
+ * Copied from `merging.main.runtime` (`filterDeletedDependenciesFromConfig`): the config merge
144
+ * can emit deletion markers (`version: '-'`) for deps removed on main. The aspects-merger applies
145
+ * `mergedConfig` verbatim, so strip those here to avoid writing a policy entry with version '-'.
146
+ */
147
+ private filterDeletedDependenciesFromConfig;
148
+ /**
149
+ * Best-effort, fetch-free check for whether the current (PR) branch is *behind* the default
150
+ * branch — i.e. the default branch has commits the PR branch doesn't contain.
151
+ *
152
+ * We intentionally do NOT `git fetch` here (a fetch in CI can hang on an interactive SSH
153
+ * host-key prompt — that's why `isStaleCiRun` was removed in #10300). We compare against
154
+ * whatever `origin/<default>` ref the checkout already has, which reflects the state the default
155
+ * branch was in when this CI run started — exactly the reference point we care about.
156
+ *
157
+ * Returns true only when we can *confirm* the branch is behind. If the ref can't be resolved or
158
+ * anything else goes wrong, returns false (treat as "not behind" / proceed) so we never silently
159
+ * disable the main→lane config propagation.
160
+ */
161
+ private isBranchBehindDefaultBranch;
116
162
  verifyWorkspaceStatus(): Promise<{
117
163
  code: number;
118
164
  data: string;
119
165
  }>;
120
- snapPrCommit({ laneIdStr, message, build, strict, dryRun, }: {
166
+ snapPrCommit({ laneIdStr, message, build, strict, dryRun, keepLane, }: {
121
167
  laneIdStr: string;
122
168
  message: string;
123
169
  build: boolean | undefined;
124
170
  strict: boolean | undefined;
125
171
  dryRun?: boolean;
172
+ keepLane?: boolean;
126
173
  }): Promise<string | undefined>;
174
+ /**
175
+ * `--keep-lane` flow: reuse the existing remote lane (or create it on the first run), merge main
176
+ * into it to pick up config changes that landed since the fork, snap, and export with
177
+ * adopt-on-conflict recovery for concurrent CI pushes. The lane object is preserved across PR
178
+ * commits, so its history and lane-based UI edits on Bit Cloud survive.
179
+ */
180
+ private snapAndExportReusingLane;
181
+ /**
182
+ * Default flow: snap onto a uniquely-named temporary lane, then at export time delete any
183
+ * existing remote lane and rename the temp lane to the final name. The temp name minimizes the
184
+ * race window when multiple CI jobs run concurrently on the same branch. Trade-off: the final
185
+ * lane is recreated on every PR commit, so its history and any lane-based UI edits on Bit Cloud
186
+ * don't survive across commits — use `--keep-lane` for that.
187
+ */
188
+ private snapAndExportWithTempLane;
189
+ /**
190
+ * Export with a recovery path for the two concurrent-CI conflicts that can surface from the
191
+ * remote (see the marker constants at the top of the file): lane-hash mismatch (both runners
192
+ * created fresh lane objects when the lane didn't yet exist on the remote) and per-component
193
+ * divergence (both reused the existing lane but snapped the same component with different
194
+ * content).
195
+ *
196
+ * Recovery: adopt-the-winner. The remote lane (whoever pushed first) becomes canonical. We
197
+ * drop our local lane object, fetch the remote, rebase our snapped Version objects so each
198
+ * one's parent points to the remote head for that component, then swap those rebased Versions
199
+ * in as the new lane heads and re-export. Build artifacts are preserved — only the parent
200
+ * pointers on the Version objects change. Result: both runners' snaps end up chained on a
201
+ * single lane object (last-writer-wins on content for any contested component, with the
202
+ * winner's snap preserved in history as the parent).
203
+ */
204
+ private exportWithAdoptOnConflict;
205
+ /**
206
+ * Wrap `exporter.export()` with retry on the "server is busy" error. The retried export's
207
+ * pending-dir lands behind whichever concurrent client is still in the remote's queue (we
208
+ * arrived second by definition — we're the loser of the original race). The 60s wait inside
209
+ * `export-validate.waitIfNeeded` covers the common case, but on slow CI hosts or large pushes
210
+ * we sometimes time out before the other client finishes its persist. A short sleep + retry
211
+ * here just gives the queue room to drain.
212
+ */
213
+ private exportWithBusyRetry;
214
+ private rebaseOntoRemoteLane;
127
215
  mergePr({ message: argMessage, build, strict, releaseType, preReleaseId, incrementBy, explicitVersionBump, verbose, versionsFile, autoMergeResolve, forceTheirs, laneName, skipPush, noBitmapCommit, }: {
128
216
  message?: string;
129
217
  build?: boolean;
@@ -163,9 +251,10 @@ export declare class CiMain {
163
251
  /**
164
252
  * Export with retry on lane hash-mismatch, caused by a concurrent `bit ci pr` run pushing the
165
253
  * same lane id between our pre-export delete and the hub's merge (the export takes 1-2 minutes,
166
- * plenty of time to race). Before each retry we skip if the PR branch has advanced past our
167
- * commit - in that case a newer run will publish the correct lane, and retrying with our older
168
- * snaps would regress the PR preview.
254
+ * plenty of time to race). Used by the default (temp-lane) flow. On mismatch we delete the
255
+ * remote lane and retry the temp-lane flow recreates the lane on every run anyway, so there's
256
+ * no lane history to preserve. (The `--keep-lane` flow instead adopts the remote lane and
257
+ * rebases onto it; see `exportWithAdoptOnConflict`.)
169
258
  */
170
259
  private exportWithRetryOnLaneHashMismatch;
171
260
  /**