@teambit/ci 1.0.382 → 1.0.384

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