77 createRefMutation ,
88 getRepositoryMetadata ,
99 GitHubClient ,
10+ updateRefMutation ,
1011} from "./github/graphql/queries.js" ;
1112import type {
1213 CreateCommitOnBranchMutationVariables ,
@@ -38,6 +39,11 @@ export type CommitFilesFromBase64Args = {
3839 * The current branch, tag or commit that the new branch should be based on.
3940 */
4041 base : GitBase ;
42+ /**
43+ * Push the commit even if the branch exists and does not match what was
44+ * specified as the base.
45+ */
46+ force ?: boolean ;
4147 /**
4248 * The commit message
4349 */
@@ -58,7 +64,8 @@ const getBaseRef = (base: GitBase): string => {
5864
5965const getOidFromRef = (
6066 base : GitBase ,
61- ref : ( GetRepositoryMetadataQuery [ "repository" ] & Record < never , never > ) [ "ref" ] ,
67+ ref : ( GetRepositoryMetadataQuery [ "repository" ] &
68+ Record < never , never > ) [ "baseRef" ] ,
6269) => {
6370 if ( "commit" in base ) {
6471 return base . commit ;
@@ -81,26 +88,29 @@ export const commitFilesFromBase64 = async ({
8188 repository,
8289 branch,
8390 base,
91+ force = false ,
8492 message,
8593 fileChanges,
8694 log,
8795} : CommitFilesFromBase64Args ) : Promise < CommitFilesResult > => {
8896 const repositoryNameWithOwner = `${ owner } /${ repository } ` ;
8997 const baseRef = getBaseRef ( base ) ;
98+ const targetRef = `refs/heads/${ branch } ` ;
9099
91100 log ?. debug ( `Getting repo info ${ repositoryNameWithOwner } ` ) ;
92101 const info = await getRepositoryMetadata ( octokit , {
93102 owner,
94103 name : repository ,
95- ref : baseRef ,
104+ baseRef,
105+ targetRef,
96106 } ) ;
97107 log ?. debug ( `Repo info: ${ JSON . stringify ( info , null , 2 ) } ` ) ;
98108
99109 if ( ! info ) {
100110 throw new Error ( `Repository ${ repositoryNameWithOwner } not found` ) ;
101111 }
102112
103- if ( ! info . ref ) {
113+ if ( ! info . baseRef ) {
104114 throw new Error ( `Ref ${ baseRef } not found` ) ;
105115 }
106116
@@ -109,39 +119,77 @@ export const commitFilesFromBase64 = async ({
109119 * The commit oid to base the new commit on.
110120 *
111121 * Used both to create / update the new branch (if necessary),
112- * and th ensure no changes have been made as we push the new commit.
122+ * and to ensure no changes have been made as we push the new commit.
113123 */
114- const baseOid = getOidFromRef ( base , info . ref ) ;
124+ const baseOid = getOidFromRef ( base , info . baseRef ) ;
115125
116126 let refId : string ;
117127
118128 if ( "branch" in base && base . branch === branch ) {
119129 log ?. debug ( `Committing to the same branch as base: ${ branch } (${ baseOid } )` ) ;
120130 // Get existing branch refId
121- refId = info . ref . id ;
131+ refId = info . baseRef . id ;
122132 } else {
123- // Create branch as not committing to same branch
124- // TODO: detect if branch already exists, and overwrite if so
125- log ?. debug ( `Creating branch ${ branch } from commit ${ baseOid } }` ) ;
126- const refIdCreation = await createRefMutation ( octokit , {
127- input : {
128- repositoryId,
129- name : `refs/heads/${ branch } ` ,
130- oid : baseOid ,
131- } ,
132- } ) ;
133-
134- log ?. debug (
135- `Created branch with refId ${ JSON . stringify ( refIdCreation , null , 2 ) } ` ,
136- ) ;
137-
138- const refIdStr = refIdCreation . createRef ?. ref ?. id ;
139-
140- if ( ! refIdStr ) {
141- throw new Error ( `Failed to create branch ${ branch } ` ) ;
133+ // Determine if the branch needs to be created or not
134+ if ( info . targetBranch ?. target ?. oid ) {
135+ // Branch already exists, check if it matches the base
136+ if ( info . targetBranch . target . oid !== baseOid ) {
137+ if ( force ) {
138+ log ?. debug (
139+ `Branch ${ branch } exists but does not match base ${ baseOid } , forcing update to base` ,
140+ ) ;
141+ const refIdUpdate = await updateRefMutation ( octokit , {
142+ input : {
143+ refId : info . targetBranch . id ,
144+ oid : baseOid ,
145+ } ,
146+ } ) ;
147+
148+ log ?. debug (
149+ `Updated branch with refId ${ JSON . stringify ( refIdUpdate , null , 2 ) } ` ,
150+ ) ;
151+
152+ const refIdStr = refIdUpdate . updateRef ?. ref ?. id ;
153+
154+ if ( ! refIdStr ) {
155+ throw new Error ( `Failed to create branch ${ branch } ` ) ;
156+ }
157+
158+ refId = refIdStr ;
159+ } else {
160+ throw new Error (
161+ `Branch ${ branch } exists already and does not match base ${ baseOid } , force is set to false` ,
162+ ) ;
163+ }
164+ } else {
165+ log ?. debug (
166+ `Branch ${ branch } already exists and matches base ${ baseOid } ` ,
167+ ) ;
168+ refId = info . targetBranch . id ;
169+ }
170+ } else {
171+ // Create branch as it does not exist yet
172+ log ?. debug ( `Creating branch ${ branch } from commit ${ baseOid } }` ) ;
173+ const refIdCreation = await createRefMutation ( octokit , {
174+ input : {
175+ repositoryId,
176+ name : `refs/heads/${ branch } ` ,
177+ oid : baseOid ,
178+ } ,
179+ } ) ;
180+
181+ log ?. debug (
182+ `Created branch with refId ${ JSON . stringify ( refIdCreation , null , 2 ) } ` ,
183+ ) ;
184+
185+ const refIdStr = refIdCreation . createRef ?. ref ?. id ;
186+
187+ if ( ! refIdStr ) {
188+ throw new Error ( `Failed to create branch ${ branch } ` ) ;
189+ }
190+
191+ refId = refIdStr ;
142192 }
143-
144- refId = refIdStr ;
145193 }
146194
147195 await log ?. debug ( `Creating commit on branch ${ branch } ` ) ;
0 commit comments