bstack 1.5.0 → 1.5.1

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.
Files changed (2) hide show
  1. package/dist/bstack.mjs +47 -19
  2. package/package.json +1 -1
package/dist/bstack.mjs CHANGED
@@ -6,7 +6,7 @@ import * as v from "valibot";
6
6
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
7
7
  import { dirname } from "node:path";
8
8
  //#region package.json
9
- var version = "1.5.0";
9
+ var version = "1.5.1";
10
10
  //#endregion
11
11
  //#region src/command.ts
12
12
  var CommandError = class extends Error {
@@ -666,10 +666,12 @@ var Stack = class Stack {
666
666
  const currentIdSet = new Set(currentIds);
667
667
  const removed = previous.changes.filter((change) => !currentIdSet.has(change.id));
668
668
  const added = this.changes.filter((change) => !previousIdSet.has(change.id));
669
+ const baseChanged = previous.base !== options.base;
669
670
  if (removed.length === 0) {
670
671
  const previousIsPrefix = previousIds.every((id, index) => currentIds[index] === id);
671
- if (previousIsPrefix && added.length === 0) return { kind: "skip" };
672
+ if (previousIsPrefix && added.length === 0) return baseChanged ? this.transitionForChangedBase(previous, options) : { kind: "skip" };
672
673
  if (previousIsPrefix) {
674
+ if (baseChanged) return this.transitionForChangedBase(previous, options);
673
675
  const stackNumber = previous.stackNumber ?? options.lookups.stackNumberForPullRequest(previous.changes[0].pullRequest);
674
676
  if (stackNumber !== void 0) return {
675
677
  kind: "append",
@@ -688,16 +690,21 @@ var Stack = class Stack {
688
690
  const firstCurrentIndex = previousIds.indexOf(currentIds[0]);
689
691
  const isPreviousSlice = firstCurrentIndex >= 0 && currentIds.every((id, index) => previousIds[firstCurrentIndex + index] === id);
690
692
  if (options.preserveHigherChanges && added.length === 0 && isPreviousSlice && firstCurrentIndex + currentIds.length < previousIds.length) {
691
- if (previous.changes.slice(0, firstCurrentIndex).every((change) => options.lookups.pullRequestState(change.pullRequest) === "MERGED")) return {
692
- kind: "partial",
693
- previousOffset: firstCurrentIndex
694
- };
693
+ if (previous.changes.slice(0, firstCurrentIndex).every((change) => options.lookups.pullRequestState(change.pullRequest) === "MERGED")) {
694
+ if (baseChanged) throw new Error("Cannot change the stack base while preserving higher pull requests from a detached checkout");
695
+ return {
696
+ kind: "partial",
697
+ previousOffset: firstCurrentIndex
698
+ };
699
+ }
695
700
  }
696
701
  const removedPrefixWasMerged = removed.every((change, index) => previous.changes[index] === change) && removed.every((change) => options.lookups.pullRequestState(change.pullRequest) === "MERGED");
697
702
  const survivingIds = previousIds.slice(removed.length);
698
- const onlyAppendedAfterMergedPrefix = removedPrefixWasMerged && survivingIds.every((id, index) => currentIds[index] === id) && currentIds.slice(survivingIds.length).every((id) => !previousIdSet.has(id));
699
- if (removedPrefixWasMerged && added.length === 0) return { kind: "skip" };
703
+ const survivingOrderIsUnchanged = survivingIds.every((id, index) => currentIds[index] === id);
704
+ const onlyAppendedAfterMergedPrefix = removedPrefixWasMerged && survivingOrderIsUnchanged && currentIds.slice(survivingIds.length).every((id) => !previousIdSet.has(id));
705
+ if (removedPrefixWasMerged && added.length === 0 && survivingOrderIsUnchanged) return baseChanged ? this.transitionForChangedBase(previous, options) : { kind: "skip" };
700
706
  if (onlyAppendedAfterMergedPrefix) {
707
+ if (baseChanged) return this.transitionForChangedBase(previous, options);
701
708
  if (previous.stackNumber === void 0) throw new Error("Cannot append after a merge because the native GitHub stack number is missing from local state");
702
709
  return {
703
710
  kind: "append",
@@ -714,23 +721,40 @@ var Stack = class Stack {
714
721
  return {
715
722
  kind: "rebuild",
716
723
  stackNumber,
717
- action: added.length === 0 ? "remove" : "update"
724
+ action: added.length === 0 && removedPrefixWasMerged ? "reorder" : added.length === 0 ? "remove" : "update"
725
+ };
726
+ }
727
+ transitionForChangedBase(previous, options) {
728
+ if (this.changes.length === 1) return { kind: "retarget" };
729
+ const stackNumber = previous.stackNumber ?? options.lookups.stackNumberForPullRequest(previous.changes[0].pullRequest);
730
+ return stackNumber === void 0 ? { kind: "full" } : {
731
+ kind: "rebuild",
732
+ stackNumber,
733
+ action: "change-base"
718
734
  };
719
735
  }
720
736
  };
721
737
  //#endregion
722
738
  //#region src/sync-transition.ts
723
- function prepareStackTransition(transition, github, previous, base, remote, reporter) {
739
+ function prepareStackTransition(transition, github, previous, base, reporter) {
724
740
  if (transition.kind !== "rebuild" || transition.action !== "reorder") return;
725
741
  reporter.progress(`Preparing stack #${transition.stackNumber} for reordered branches`);
726
742
  github.unstack(transition.stackNumber);
727
743
  try {
728
- for (const change of previous.changes) github.editPullRequestBase(github.pullRequest(change.pullRequest), base);
744
+ for (const change of previous.changes) {
745
+ const pullRequest = github.pullRequest(change.pullRequest);
746
+ if (pullRequest.state === "OPEN") github.editPullRequestBase(pullRequest, base);
747
+ }
729
748
  } catch (error) {
730
- restorePreviousStack(github, previous, base, remote, reporter, error);
749
+ restorePreviousStack(github, previous, reporter, error);
731
750
  }
732
751
  }
733
752
  function applyStackTransition(transition, github, previous, changes, pullRequests, base, remote, draft, reporter) {
753
+ if (transition.kind === "retarget") {
754
+ reporter.progress(`Updating the pull request base to ${base}`);
755
+ github.editPullRequestBase(pullRequests[0], base);
756
+ return;
757
+ }
734
758
  if (changes.length === 1) {
735
759
  if (transition.kind === "partial") reporter.progress("Updating this down-stack prefix while preserving higher pull requests");
736
760
  if (transition.kind === "collapse") {
@@ -739,7 +763,7 @@ function applyStackTransition(transition, github, previous, changes, pullRequest
739
763
  try {
740
764
  github.editPullRequestBase(pullRequests[0], base);
741
765
  } catch (error) {
742
- restorePreviousStack(github, previous, base, remote, reporter, error);
766
+ restorePreviousStack(github, previous, reporter, error);
743
767
  }
744
768
  }
745
769
  return;
@@ -750,12 +774,13 @@ function applyStackTransition(transition, github, previous, changes, pullRequest
750
774
  return;
751
775
  }
752
776
  if (transition.kind === "rebuild") {
753
- reporter.progress(`Rebuilding stack #${transition.stackNumber} to ${transition.action} pull requests`);
777
+ const reason = transition.action === "change-base" ? `against ${base}` : `to ${transition.action} pull requests`;
778
+ reporter.progress(`Rebuilding stack #${transition.stackNumber} ${reason}`);
754
779
  if (transition.action !== "reorder") github.unstack(transition.stackNumber);
755
780
  try {
756
781
  github.linkStack(pullRequests.map((pullRequest) => pullRequest.number), base, remote, draft);
757
782
  } catch (error) {
758
- restorePreviousStack(github, previous, base, remote, reporter, error);
783
+ restorePreviousStack(github, previous, reporter, error);
759
784
  }
760
785
  return;
761
786
  }
@@ -774,11 +799,13 @@ function applyStackTransition(transition, github, previous, changes, pullRequest
774
799
  }
775
800
  reporter.progress("The native GitHub stack already has the correct members");
776
801
  }
777
- function restorePreviousStack(github, previous, base, remote, reporter, rebuildError) {
802
+ function restorePreviousStack(github, previous, reporter, rebuildError) {
778
803
  const rebuildMessage = rebuildError instanceof Error ? rebuildError.message : String(rebuildError);
779
804
  reporter.progress("Rebuild failed; restoring the previous native GitHub stack");
780
805
  try {
781
- github.linkStack(previous.changes.map((change) => change.pullRequest), base, remote, true);
806
+ const pullRequests = previous.changes.map((change) => github.pullRequest(change.pullRequest)).filter((pullRequest) => pullRequest.state === "OPEN");
807
+ if (pullRequests.length === 1) github.editPullRequestBase(pullRequests[0], previous.base);
808
+ else if (pullRequests.length > 1) github.linkStack(pullRequests.map((pullRequest) => pullRequest.number), previous.base, previous.remote, true);
782
809
  } catch (rollbackError) {
783
810
  const rollbackMessage = rollbackError instanceof Error ? rollbackError.message : String(rollbackError);
784
811
  throw new Error(`Stack rebuild failed: ${rebuildMessage}\nRestoring the previous stack also failed: ${rollbackMessage}`);
@@ -822,13 +849,14 @@ function syncStack(dependencies, options) {
822
849
  const state = stateStore.read();
823
850
  const previous = stack.findPrevious(state);
824
851
  const transition = stack.transitionFrom(previous, {
852
+ base,
825
853
  preserveHigherChanges: repository.currentBranch() === void 0,
826
854
  lookups: {
827
855
  pullRequestState: (pullRequest) => github.pullRequest(pullRequest).state,
828
856
  stackNumberForPullRequest: (pullRequest) => github.stackNumberForPullRequest(pullRequest)
829
857
  }
830
858
  });
831
- prepareStackTransition(transition, github, previous, base, remote, reporter);
859
+ prepareStackTransition(transition, github, previous, base, reporter);
832
860
  const isReorder = transition.kind === "rebuild" && transition.action === "reorder";
833
861
  let pushedBranches = /* @__PURE__ */ new Set();
834
862
  try {
@@ -839,7 +867,7 @@ function syncStack(dependencies, options) {
839
867
  reportPushResult(reporter, pushResult);
840
868
  pushedBranches = new Set(pushResult.updated);
841
869
  } catch (error) {
842
- if (isReorder) restorePreviousStack(github, previous, base, remote, reporter, error);
870
+ if (isReorder) restorePreviousStack(github, previous, reporter, error);
843
871
  throw error;
844
872
  }
845
873
  reporter.progress("Looking up existing pull requests");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bstack",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Create native GitHub stacked pull requests from a linear series of commits",
5
5
  "license": "MIT",
6
6
  "repository": {