@@ -6,7 +6,7 @@ import process from 'node:process';
66import { spawnSync } from 'node:child_process' ;
77import { fileURLToPath } from 'node:url' ;
88import { ensureCleanWorkingTree , getRepoRoot , run } from './lib/branch-utils.mjs' ;
9- import { ensureGhCli , resolveUpstream } from './lib/remote-utils.mjs' ;
9+ import { ensureGhCli , resolveUpstream , tryResolveRemote } from './lib/remote-utils.mjs' ;
1010import {
1111 DEFAULT_RELEASE_ROLLBACK_POLICY_PATH ,
1212 loadReleaseRollbackPolicy ,
@@ -220,6 +220,45 @@ function resolveRepositorySlug(explicitRepo, repoRoot) {
220220 return `${ upstream . owner } /${ upstream . repo } ` ;
221221}
222222
223+ function toRepositorySlug ( parsedRemote ) {
224+ if ( ! parsedRemote ?. owner || ! parsedRemote ?. repo ) {
225+ return null ;
226+ }
227+ return `${ parsedRemote . owner } /${ parsedRemote . repo } ` . toLowerCase ( ) ;
228+ }
229+
230+ export function resolveRollbackRemoteName ( {
231+ repoRoot,
232+ preferredRemote,
233+ repository,
234+ tryResolveRemoteFn = tryResolveRemote
235+ } ) {
236+ const configuredRemote = String ( preferredRemote || 'upstream' ) . trim ( ) || 'upstream' ;
237+ const configured = tryResolveRemoteFn ( repoRoot , configuredRemote ) ;
238+ if ( configured ?. parsed ) {
239+ return {
240+ configuredRemote,
241+ effectiveRemote : configuredRemote ,
242+ fallbackReason : null
243+ } ;
244+ }
245+
246+ const repositorySlug = String ( repository || '' ) . trim ( ) . toLowerCase ( ) ;
247+ const origin = configuredRemote === 'origin' ? configured : tryResolveRemoteFn ( repoRoot , 'origin' ) ;
248+ const originSlug = toRepositorySlug ( origin ?. parsed ) ;
249+ if ( originSlug && repositorySlug && originSlug === repositorySlug ) {
250+ return {
251+ configuredRemote,
252+ effectiveRemote : 'origin' ,
253+ fallbackReason : `Configured rollback remote '${ configuredRemote } ' is missing; using origin because it matches ${ repository } .`
254+ } ;
255+ }
256+
257+ throw new Error (
258+ `Rollback remote '${ configuredRemote } ' is not configured and origin does not match repository '${ repository || '<unknown>' } '.`
259+ ) ;
260+ }
261+
223262function fetchReleaseRecords ( repoRoot , repository , maxReleases ) {
224263 const perPage = Math . min ( 100 , Math . max ( 2 , maxReleases ) ) ;
225264 const payload = runGhApiJson (
@@ -352,7 +391,15 @@ export async function runRollback(options, dependencies = {}) {
352391 const policy = dependencies . policy || loadReleaseRollbackPolicy ( options . policyPath ) ;
353392 const streamPolicy = getReleaseRollbackStreamPolicy ( policy , options . stream ) ;
354393 const repository = resolveRepositorySlug ( options . repo , repoRoot ) ;
355- const rollbackRemote = options . remote || policy . rollback . remote || 'upstream' ;
394+ const remoteResolver =
395+ dependencies . remoteResolver ||
396+ ( ( args ) => resolveRollbackRemoteName ( { ...args , tryResolveRemoteFn : dependencies . tryResolveRemote || tryResolveRemote } ) ) ;
397+ const rollbackRemoteResolution = remoteResolver ( {
398+ repoRoot,
399+ preferredRemote : options . remote || policy . rollback . remote || 'upstream' ,
400+ repository
401+ } ) ;
402+ const rollbackRemote = rollbackRemoteResolution . effectiveRemote ;
356403 const targetBranches = [ options . mainBranch , options . developBranch ] ;
357404
358405 const failures = [ ] ;
@@ -368,28 +415,33 @@ export async function runRollback(options, dependencies = {}) {
368415 targetTag : options . targetTag
369416 } ) ;
370417
371- fetchRemoteRefs ( repoRoot , rollbackRemote , targetBranches ) ;
372- const targetCommit = resolveTagCommit ( repoRoot , pointer . target . tag ) ;
418+ const fetchRemoteRefsFn = dependencies . fetchRemoteRefs || fetchRemoteRefs ;
419+ const resolveTagCommitFn = dependencies . resolveTagCommit || resolveTagCommit ;
420+ const tryResolveRefFn = dependencies . tryResolveRef || tryResolveRef ;
421+ const forcePushBranchFn = dependencies . forcePushBranch || forcePushBranch ;
422+
423+ fetchRemoteRefsFn ( repoRoot , rollbackRemote , targetBranches ) ;
424+ const targetCommit = resolveTagCommitFn ( repoRoot , pointer . target . tag ) ;
373425
374426 const branches = targetBranches . map ( ( name ) => ( {
375427 name,
376428 remote : rollbackRemote ,
377- before : tryResolveRef ( repoRoot , `${ rollbackRemote } /${ name } ` ) ,
429+ before : tryResolveRefFn ( repoRoot , `${ rollbackRemote } /${ name } ` ) ,
378430 after : null ,
379431 pushed : false ,
380432 matchesTarget : false
381433 } ) ) ;
382434
383435 if ( options . apply ) {
384436 for ( const branch of branches ) {
385- forcePushBranch ( repoRoot , rollbackRemote , branch . name , targetCommit , branch . before ) ;
437+ forcePushBranchFn ( repoRoot , rollbackRemote , branch . name , targetCommit , branch . before ) ;
386438 branch . pushed = true ;
387439 }
388- fetchRemoteRefs ( repoRoot , rollbackRemote , targetBranches ) ;
440+ fetchRemoteRefsFn ( repoRoot , rollbackRemote , targetBranches ) ;
389441 }
390442
391443 for ( const branch of branches ) {
392- branch . after = tryResolveRef ( repoRoot , `${ rollbackRemote } /${ branch . name } ` ) ;
444+ branch . after = tryResolveRefFn ( repoRoot , `${ rollbackRemote } /${ branch . name } ` ) ;
393445 branch . matchesTarget = options . apply ? branch . after === targetCommit : false ;
394446 }
395447
@@ -398,7 +450,7 @@ export async function runRollback(options, dependencies = {}) {
398450 const originBranches = targetBranches . map ( ( name ) => ( {
399451 name,
400452 remote : 'origin' ,
401- before : tryResolveRef ( repoRoot , `origin/${ name } ` ) ,
453+ before : tryResolveRefFn ( repoRoot , `origin/${ name } ` ) ,
402454 after : null ,
403455 pushed : false ,
404456 matchesTarget : false
@@ -408,12 +460,12 @@ export async function runRollback(options, dependencies = {}) {
408460 addFailure ( failures , 'origin-branch-missing' , `origin/${ branch . name } does not exist for sync-origin.` ) ;
409461 continue ;
410462 }
411- forcePushBranch ( repoRoot , 'origin' , branch . name , targetCommit , branch . before ) ;
463+ forcePushBranchFn ( repoRoot , 'origin' , branch . name , targetCommit , branch . before ) ;
412464 branch . pushed = true ;
413465 }
414- fetchRemoteRefs ( repoRoot , 'origin' , targetBranches ) ;
466+ fetchRemoteRefsFn ( repoRoot , 'origin' , targetBranches ) ;
415467 for ( const branch of originBranches ) {
416- branch . after = tryResolveRef ( repoRoot , `origin/${ branch . name } ` ) ;
468+ branch . after = tryResolveRefFn ( repoRoot , `origin/${ branch . name } ` ) ;
417469 branch . matchesTarget = branch . after === targetCommit ;
418470 }
419471 originSync = originBranches ;
@@ -461,7 +513,9 @@ export async function runRollback(options, dependencies = {}) {
461513 policy : {
462514 path : options . policyPath ,
463515 schema : policy . schema ,
516+ configuredRemote : rollbackRemoteResolution . configuredRemote ,
464517 remote : rollbackRemote ,
518+ remoteFallbackReason : rollbackRemoteResolution . fallbackReason ,
465519 targetBranches,
466520 minimumHistory : streamPolicy . minimumHistory
467521 } ,
@@ -559,4 +613,3 @@ if (invokedPath && invokedPath === modulePath) {
559613 process . exitCode = 1 ;
560614 } ) ;
561615}
562-
0 commit comments