@teambit/ci 1.0.505 → 1.0.508
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/dist/ci.main.runtime.d.ts +3 -2
- package/dist/ci.main.runtime.js +5 -6
- package/dist/ci.main.runtime.js.map +1 -1
- package/dist/{preview-1787074471717.js → preview-1787160027560.js} +1 -1
- package/dist/sync/git-host-provider.d.ts +9 -0
- package/dist/sync/git-host-provider.js.map +1 -1
- package/dist/sync/github-client.d.ts +28 -0
- package/dist/sync/github-client.js +81 -3
- package/dist/sync/github-client.js.map +1 -1
- package/dist/sync/github-client.spec.js +249 -0
- package/dist/sync/github-client.spec.js.map +1 -1
- package/dist/sync/lane-sync-executor.d.ts +47 -3
- package/dist/sync/lane-sync-executor.js +191 -39
- package/dist/sync/lane-sync-executor.js.map +1 -1
- package/dist/sync/lane-sync-executor.spec.js +336 -0
- package/dist/sync/lane-sync-executor.spec.js.map +1 -1
- package/dist/sync/sync-planner.d.ts +12 -2
- package/dist/sync/sync-planner.js +17 -8
- package/dist/sync/sync-planner.js.map +1 -1
- package/dist/sync/sync-planner.spec.js +64 -0
- package/dist/sync/sync-planner.spec.js.map +1 -1
- package/dist/sync/sync-state.d.ts +34 -3
- package/dist/sync/sync-state.js +61 -3
- package/dist/sync/sync-state.js.map +1 -1
- package/dist/sync/sync-state.spec.js +54 -0
- package/dist/sync/sync-state.spec.js.map +1 -1
- package/package.json +15 -15
- package/sync/git-host-provider.ts +8 -0
- package/sync/github-client.spec.ts +160 -0
- package/sync/github-client.ts +90 -3
- package/sync/lane-sync-executor.spec.ts +291 -0
- package/sync/lane-sync-executor.ts +233 -50
- package/sync/sync-planner.spec.ts +41 -0
- package/sync/sync-planner.ts +31 -10
- package/sync/sync-state.spec.ts +48 -0
- package/sync/sync-state.ts +104 -4
|
@@ -566,6 +566,10 @@ describe('executeExportBranch reports the ledger-race wording when only the ledg
|
|
|
566
566
|
executor.lastNonSyncCommitMessage = async () => 'feat: some change';
|
|
567
567
|
executor.checkoutFromRemote = async () => {};
|
|
568
568
|
executor.restoreWorkspace = async () => {};
|
|
569
|
+
executor.materializeLane = async () => undefined;
|
|
570
|
+
executor.deps.ci = {
|
|
571
|
+
hasUnsyncedWorkChanges: async () => true
|
|
572
|
+
};
|
|
569
573
|
// The export half already succeeded; only the ledger commit that follows raced.
|
|
570
574
|
executor.snapAndExportOntoLane = async () => ({
|
|
571
575
|
status: 'exported'
|
|
@@ -587,6 +591,157 @@ describe('executeExportBranch reports the ledger-race wording when only the ledg
|
|
|
587
591
|
});
|
|
588
592
|
});
|
|
589
593
|
|
|
594
|
+
// The probe's "clean" answer means converged only against the lane the PLAN read. A lane that moved
|
|
595
|
+
// in between must re-plan — comparing the branch's files with the newer lane would misread the
|
|
596
|
+
// lane's own advance as branch work and export a revert over a concurrent developer's export.
|
|
597
|
+
describe('executeExportBranch bails when the lane moved since planning', () => {
|
|
598
|
+
function stubExport(currentLaneComponents, plannedLaneComponents) {
|
|
599
|
+
const {
|
|
600
|
+
executor
|
|
601
|
+
} = stubExecutor();
|
|
602
|
+
const touched = [];
|
|
603
|
+
executor.checkoutFromRemote = async () => {};
|
|
604
|
+
executor.restoreWorkspace = async () => {};
|
|
605
|
+
executor.materializeLane = async () => undefined;
|
|
606
|
+
executor.lastNonSyncCommitMessage = async () => 'feat: some change';
|
|
607
|
+
executor.getRemoteLane = async () => ({
|
|
608
|
+
components: currentLaneComponents
|
|
609
|
+
});
|
|
610
|
+
executor.deps.ci = {
|
|
611
|
+
hasUnsyncedWorkChanges: async () => {
|
|
612
|
+
touched.push('status');
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
executor.snapAndExportOntoLane = async () => {
|
|
617
|
+
touched.push('snap');
|
|
618
|
+
return {
|
|
619
|
+
status: 'exported'
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
const run = () => executor.executeExportBranch({
|
|
623
|
+
target: {
|
|
624
|
+
hostScope: 'acme.shop',
|
|
625
|
+
name: 'my-lane'
|
|
626
|
+
},
|
|
627
|
+
laneIdStr: 'acme.shop/my-lane',
|
|
628
|
+
branch: 'my-lane',
|
|
629
|
+
defaultBranch: 'main',
|
|
630
|
+
preExportLane: {
|
|
631
|
+
components: plannedLaneComponents
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
return {
|
|
635
|
+
run,
|
|
636
|
+
touched
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
const L1 = [comp('acme.shop/comp1', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')];
|
|
640
|
+
const L2 = [comp('acme.shop/comp1', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2')];
|
|
641
|
+
it('a moved lane returns a re-plan noop before the status read or any snap', async () => {
|
|
642
|
+
const {
|
|
643
|
+
run,
|
|
644
|
+
touched
|
|
645
|
+
} = stubExport(L2, L1);
|
|
646
|
+
const summary = await run();
|
|
647
|
+
(0, _chai().expect)(summary).to.include('my-lane -> noop');
|
|
648
|
+
(0, _chai().expect)(summary).to.include('moved');
|
|
649
|
+
(0, _chai().expect)(touched).to.deep.equal([]);
|
|
650
|
+
});
|
|
651
|
+
it('an unmoved lane proceeds to the probe', async () => {
|
|
652
|
+
const {
|
|
653
|
+
run,
|
|
654
|
+
touched
|
|
655
|
+
} = stubExport(L1, L1);
|
|
656
|
+
const summary = await run();
|
|
657
|
+
(0, _chai().expect)(summary).to.include('my-lane -> noop (converged)');
|
|
658
|
+
(0, _chai().expect)(touched).to.deep.equal(['status']);
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
// The merge path snaps whatever the merge produced — which can be nothing new, now routinely: a
|
|
663
|
+
// source-bundling tip plus a moved lane plans merge-diverged, and a branch with nothing of its own
|
|
664
|
+
// merges clean and leaves the snap a noop. The summary must say so, and the run-summary comment
|
|
665
|
+
// belongs only to runs that actually exported.
|
|
666
|
+
describe('executeMergeDiverged distinguishes an exporting merge from a nothing-new merge', () => {
|
|
667
|
+
function stubMerge(snapStatus, currentLaneComponents = []) {
|
|
668
|
+
const {
|
|
669
|
+
executor
|
|
670
|
+
} = stubExecutor();
|
|
671
|
+
const summaryCalls = [];
|
|
672
|
+
executor.checkoutFromRemote = async () => {};
|
|
673
|
+
executor.restoreWorkspace = async () => {};
|
|
674
|
+
executor.getRemoteLane = async () => ({
|
|
675
|
+
components: currentLaneComponents
|
|
676
|
+
});
|
|
677
|
+
executor.mergeLaneIntoBranchWorkingTree = async () => ({
|
|
678
|
+
conflicts: [],
|
|
679
|
+
conflictedFileCount: 0
|
|
680
|
+
});
|
|
681
|
+
executor.snapAndExportOntoLane = async () => ({
|
|
682
|
+
status: snapStatus
|
|
683
|
+
});
|
|
684
|
+
executor.recordLaneHeadOnBranch = async () => ({
|
|
685
|
+
status: 'ok',
|
|
686
|
+
laneHead: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1',
|
|
687
|
+
remoteLane: {
|
|
688
|
+
components: []
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
executor.postRunSummaryComment = async args => summaryCalls.push(args);
|
|
692
|
+
const run = () => executor.executeMergeDiverged({
|
|
693
|
+
target: {
|
|
694
|
+
hostScope: 'acme.shop',
|
|
695
|
+
name: 'my-lane'
|
|
696
|
+
},
|
|
697
|
+
laneIdStr: 'acme.shop/my-lane',
|
|
698
|
+
branch: 'my-lane',
|
|
699
|
+
defaultBranch: 'main',
|
|
700
|
+
preExportLane: {
|
|
701
|
+
components: []
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
return {
|
|
705
|
+
run,
|
|
706
|
+
summaryCalls
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
it('a nothing-new merge says so, and posts no run summary', async () => {
|
|
710
|
+
const {
|
|
711
|
+
run,
|
|
712
|
+
summaryCalls
|
|
713
|
+
} = stubMerge('noop');
|
|
714
|
+
const summary = await run();
|
|
715
|
+
(0, _chai().expect)(summary).to.include('my-lane -> merge-diverged');
|
|
716
|
+
(0, _chai().expect)(summary).to.include('nothing new to export');
|
|
717
|
+
(0, _chai().expect)(summary).to.not.include('then exported');
|
|
718
|
+
(0, _chai().expect)(summaryCalls).to.have.lengthOf(0);
|
|
719
|
+
});
|
|
720
|
+
it('an exporting merge keeps the exported wording and posts the run summary', async () => {
|
|
721
|
+
const {
|
|
722
|
+
run,
|
|
723
|
+
summaryCalls
|
|
724
|
+
} = stubMerge('exported');
|
|
725
|
+
const summary = await run();
|
|
726
|
+
(0, _chai().expect)(summary).to.include('then exported');
|
|
727
|
+
(0, _chai().expect)(summaryCalls).to.have.lengthOf(1);
|
|
728
|
+
(0, _chai().expect)(summaryCalls[0].laneHead).to.equal('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1');
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// Same freshness rule as the export probe: the plan's inputs must still describe the world.
|
|
732
|
+
it('a lane that moved since planning bails to a re-plan before merging anything', async () => {
|
|
733
|
+
const moved = [comp('acme.shop/comp1', 'ccccccccccccccccccccccccccccccccccccccc3')];
|
|
734
|
+
const {
|
|
735
|
+
run,
|
|
736
|
+
summaryCalls
|
|
737
|
+
} = stubMerge('exported', moved);
|
|
738
|
+
const summary = await run();
|
|
739
|
+
(0, _chai().expect)(summary).to.include('my-lane -> noop');
|
|
740
|
+
(0, _chai().expect)(summary).to.include('moved');
|
|
741
|
+
(0, _chai().expect)(summaryCalls).to.have.lengthOf(0);
|
|
742
|
+
});
|
|
743
|
+
});
|
|
744
|
+
|
|
590
745
|
// Adoption never snaps or exports, so its raced line must NOT claim the lane was updated — the lane
|
|
591
746
|
// is untouched and only the branch's pointer commit lost the race.
|
|
592
747
|
describe('executeAdoptBranch reports a lane-untouched race when its ledger push races', () => {
|
|
@@ -634,5 +789,186 @@ describe('isProtectedBranch', () => {
|
|
|
634
789
|
(0, _chai().expect)((0, _laneSyncExecutor().isProtectedBranch)('my-lane', 'develop', 'bit-sync/main')).to.equal(false);
|
|
635
790
|
});
|
|
636
791
|
});
|
|
792
|
+
describe('laneSummaryComponents', () => {
|
|
793
|
+
it('includes hidden updateDependents — a cascade export must not read as "nothing changed"', () => {
|
|
794
|
+
const lane = {
|
|
795
|
+
components: [comp('acme.shop/comp1', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')],
|
|
796
|
+
updateDependents: [comp('acme.shop/dep1', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2')]
|
|
797
|
+
};
|
|
798
|
+
(0, _chai().expect)((0, _laneSyncExecutor().laneSummaryComponents)(lane).map(c => c.id.toStringWithoutVersion())).to.deep.equal(['acme.shop/comp1', 'acme.shop/dep1']);
|
|
799
|
+
});
|
|
800
|
+
it('an absent lane lists nothing', () => {
|
|
801
|
+
(0, _chai().expect)((0, _laneSyncExecutor().laneSummaryComponents)(undefined)).to.deep.equal([]);
|
|
802
|
+
});
|
|
803
|
+
});
|
|
804
|
+
describe('changedLaneComponents', () => {
|
|
805
|
+
it('includes a component new to the lane, and one whose head moved', () => {
|
|
806
|
+
const before = [comp('acme.shop/comp1', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')];
|
|
807
|
+
const after = [comp('acme.shop/comp1', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2'), comp('acme.shop/comp2', 'ccccccccccccccccccccccccccccccccccccccc3')];
|
|
808
|
+
const changed = (0, _laneSyncExecutor().changedLaneComponents)(before, after);
|
|
809
|
+
(0, _chai().expect)(changed.map(c => c.id.toStringWithoutVersion())).to.deep.equal(['acme.shop/comp1', 'acme.shop/comp2']);
|
|
810
|
+
});
|
|
811
|
+
it('excludes a component whose head did not move', () => {
|
|
812
|
+
const stable = comp('acme.shop/comp1', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1');
|
|
813
|
+
(0, _chai().expect)((0, _laneSyncExecutor().changedLaneComponents)([stable], [stable])).to.deep.equal([]);
|
|
814
|
+
});
|
|
815
|
+
it('treats an undefined "before" (never seen this lane) as everything being new', () => {
|
|
816
|
+
const after = [comp('acme.shop/comp1', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')];
|
|
817
|
+
(0, _chai().expect)((0, _laneSyncExecutor().changedLaneComponents)(undefined, after)).to.deep.equal(after);
|
|
818
|
+
});
|
|
819
|
+
});
|
|
820
|
+
describe('runSummaryCommentBody', () => {
|
|
821
|
+
it('carries the marker, the changed components, and the branch/lane anchors', () => {
|
|
822
|
+
const body = (0, _laneSyncExecutor().runSummaryCommentBody)({
|
|
823
|
+
laneIdStr: 'acme.shop/my-lane',
|
|
824
|
+
laneUrl: 'https://bit.cloud/acme/shop/~lane/my-lane',
|
|
825
|
+
branch: 'my-lane',
|
|
826
|
+
branchTipSha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1',
|
|
827
|
+
laneHead: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2',
|
|
828
|
+
changed: [comp('acme.shop/comp1', 'ccccccccccccccccccccccccccccccccccccccc3')]
|
|
829
|
+
});
|
|
830
|
+
(0, _chai().expect)(body).to.include(_laneSyncExecutor().RUN_SUMMARY_MARKER);
|
|
831
|
+
(0, _chai().expect)(body).to.include('acme.shop/comp1` @ `ccccccccc');
|
|
832
|
+
(0, _chai().expect)(body).to.include('branch: `my-lane` @ `aaaaaaaaa`');
|
|
833
|
+
// the lane anchor is a LINK — the reader lands on the lane, not on a name to copy-paste
|
|
834
|
+
(0, _chai().expect)(body).to.include('lane: [`acme.shop/my-lane`](https://bit.cloud/acme/shop/~lane/my-lane) @ `bbbbbbbbb`');
|
|
835
|
+
});
|
|
836
|
+
it('says plainly that nothing changed, rather than an empty list', () => {
|
|
837
|
+
const body = (0, _laneSyncExecutor().runSummaryCommentBody)({
|
|
838
|
+
laneIdStr: 'acme.shop/my-lane',
|
|
839
|
+
laneUrl: 'https://bit.cloud/acme/shop/~lane/my-lane',
|
|
840
|
+
branch: 'my-lane',
|
|
841
|
+
branchTipSha: undefined,
|
|
842
|
+
laneHead: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2',
|
|
843
|
+
changed: []
|
|
844
|
+
});
|
|
845
|
+
(0, _chai().expect)(body).to.include('none — nothing on the lane changed this run');
|
|
846
|
+
(0, _chai().expect)(body).to.not.include('@ `undefined');
|
|
847
|
+
});
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// The comment is a pure surface effect: it must never gate the run's own outcome, and must degrade
|
|
851
|
+
// silently through every "nothing to comment on" state a real host, PR or branch can be in.
|
|
852
|
+
describe('postRunSummaryComment', () => {
|
|
853
|
+
const BEFORE = [comp('acme.shop/comp1', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')];
|
|
854
|
+
const AFTER = [comp('acme.shop/comp1', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2')];
|
|
855
|
+
function executorWith(gitHost, warnings = []) {
|
|
856
|
+
const executor = new (_laneSyncExecutor().LaneSyncExecutor)({
|
|
857
|
+
lanes: {},
|
|
858
|
+
ci: {},
|
|
859
|
+
logger: {
|
|
860
|
+
console: () => {},
|
|
861
|
+
consoleWarning: msg => warnings.push(msg),
|
|
862
|
+
error: () => {}
|
|
863
|
+
},
|
|
864
|
+
gitHost,
|
|
865
|
+
cfg: (0, _syncConfig().resolveSyncConfig)({}),
|
|
866
|
+
defaultScope: 'acme.shop'
|
|
867
|
+
});
|
|
868
|
+
executor.currentBranchTip = async () => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1';
|
|
869
|
+
return executor;
|
|
870
|
+
}
|
|
871
|
+
const call = executor => executor.postRunSummaryComment({
|
|
872
|
+
target: {
|
|
873
|
+
hostScope: 'acme.shop',
|
|
874
|
+
name: 'my-lane'
|
|
875
|
+
},
|
|
876
|
+
laneIdStr: 'acme.shop/my-lane',
|
|
877
|
+
branch: 'my-lane',
|
|
878
|
+
laneHead: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2',
|
|
879
|
+
branchTipSha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1',
|
|
880
|
+
preComponents: BEFORE,
|
|
881
|
+
postComponents: AFTER
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
// The anchor is the ledger sha THIS run pushed — passed in, never refetched: a concurrent developer
|
|
885
|
+
// push must not be presented as the synced tip, and no remote read exists to fail the path.
|
|
886
|
+
it('anchors the body on the given pushed sha without any branch refetch', async () => {
|
|
887
|
+
const upserts = [];
|
|
888
|
+
const gitHost = {
|
|
889
|
+
findPrByBranch: async () => ({
|
|
890
|
+
number: 7,
|
|
891
|
+
htmlUrl: 'https://example.test/pr/7',
|
|
892
|
+
labels: []
|
|
893
|
+
}),
|
|
894
|
+
upsertComment: async (_n, _m, body) => upserts.push(body)
|
|
895
|
+
};
|
|
896
|
+
const executor = executorWith(gitHost);
|
|
897
|
+
executor.currentBranchTip = async () => {
|
|
898
|
+
throw new Error('must not be called');
|
|
899
|
+
};
|
|
900
|
+
await call(executor);
|
|
901
|
+
(0, _chai().expect)(upserts).to.have.lengthOf(1);
|
|
902
|
+
(0, _chai().expect)(upserts[0]).to.include('branch: `my-lane` @ `aaaaaaaaa`');
|
|
903
|
+
});
|
|
904
|
+
it('upserts the marked comment on the open PR when the host supports it', async () => {
|
|
905
|
+
const calls = [];
|
|
906
|
+
const gitHost = {
|
|
907
|
+
findPrByBranch: async () => ({
|
|
908
|
+
number: 7,
|
|
909
|
+
htmlUrl: 'https://example.test/pr/7',
|
|
910
|
+
labels: []
|
|
911
|
+
}),
|
|
912
|
+
upsertComment: async (prNumber, marker, body) => {
|
|
913
|
+
calls.push({
|
|
914
|
+
prNumber,
|
|
915
|
+
marker,
|
|
916
|
+
body
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
await call(executorWith(gitHost));
|
|
921
|
+
(0, _chai().expect)(calls).to.have.lengthOf(1);
|
|
922
|
+
(0, _chai().expect)(calls[0].prNumber).to.equal(7);
|
|
923
|
+
(0, _chai().expect)(calls[0].marker).to.equal(_laneSyncExecutor().RUN_SUMMARY_MARKER);
|
|
924
|
+
(0, _chai().expect)(calls[0].body).to.include('acme.shop/comp1` @ `bbbbbbbbb');
|
|
925
|
+
});
|
|
926
|
+
it('is a no-op with no configured git host', async () => {
|
|
927
|
+
await call(executorWith(undefined)); // would throw on any host call; nothing to assert but "did not throw"
|
|
928
|
+
});
|
|
929
|
+
it('is a no-op when the host does not implement upsertComment', async () => {
|
|
930
|
+
const calls = [];
|
|
931
|
+
const gitHost = {
|
|
932
|
+
findPrByBranch: async () => {
|
|
933
|
+
calls.push('findPrByBranch');
|
|
934
|
+
return {
|
|
935
|
+
number: 7,
|
|
936
|
+
htmlUrl: 'https://example.test/pr/7',
|
|
937
|
+
labels: []
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
await call(executorWith(gitHost));
|
|
942
|
+
// upsertComment is feature-tested BEFORE the PR lookup — an unsupported host must not even look up the PR.
|
|
943
|
+
(0, _chai().expect)(calls).to.deep.equal([]);
|
|
944
|
+
});
|
|
945
|
+
it('is a no-op when the branch has no open PR yet', async () => {
|
|
946
|
+
const calls = [];
|
|
947
|
+
const gitHost = {
|
|
948
|
+
findPrByBranch: async () => undefined,
|
|
949
|
+
upsertComment: async () => {
|
|
950
|
+
calls.push('upsertComment');
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
await call(executorWith(gitHost));
|
|
954
|
+
(0, _chai().expect)(calls).to.deep.equal([]);
|
|
955
|
+
});
|
|
956
|
+
it('warns and does not throw when the comment API call fails', async () => {
|
|
957
|
+
const warnings = [];
|
|
958
|
+
const gitHost = {
|
|
959
|
+
findPrByBranch: async () => ({
|
|
960
|
+
number: 7,
|
|
961
|
+
htmlUrl: 'https://example.test/pr/7',
|
|
962
|
+
labels: []
|
|
963
|
+
}),
|
|
964
|
+
upsertComment: async () => {
|
|
965
|
+
throw new Error('rate limited');
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
await call(executorWith(gitHost, warnings));
|
|
969
|
+
(0, _chai().expect)(warnings.join('\n')).to.contain('Could not post the run-summary comment');
|
|
970
|
+
(0, _chai().expect)(warnings.join('\n')).to.contain('rate limited');
|
|
971
|
+
});
|
|
972
|
+
});
|
|
637
973
|
|
|
638
974
|
//# sourceMappingURL=lane-sync-executor.spec.js.map
|