@@ -2,7 +2,7 @@ module.exports = function(octokit, opts) {
22 return new Promise ( async ( resolve , reject ) => {
33 // Up front validation
44 try {
5- for ( let req of [ "owner" , "repo" , "branch" ] ) {
5+ for ( const req of [ "owner" , "repo" , "branch" ] ) {
66 if ( ! opts [ req ] ) {
77 return reject ( `'${ req } ' is a required parameter` ) ;
88 }
@@ -19,7 +19,7 @@ module.exports = function(octokit, opts) {
1919 base,
2020 branch : branchName ,
2121 createBranch,
22- changes
22+ changes,
2323 } = opts ;
2424
2525 let branchAlreadyExists = true ;
@@ -43,7 +43,7 @@ module.exports = function(octokit, opts) {
4343 base = (
4444 await octokit . repos . get ( {
4545 owner,
46- repo
46+ repo,
4747 } )
4848 ) . data . default_branch ;
4949 }
@@ -56,70 +56,106 @@ module.exports = function(octokit, opts) {
5656 }
5757
5858 // Create blobs
59- for ( let change of changes ) {
60- let message = change . message ;
59+ for ( const change of changes ) {
60+ const message = change . message ;
6161 if ( ! message ) {
6262 return reject ( `changes[].message is a required parameter` ) ;
6363 }
64- if ( ! change . files || Object . keys ( change . files ) . length === 0 ) {
65- return reject ( `changes[].files is a required parameter` ) ;
64+
65+ const hasFiles = change . files && Object . keys ( change . files ) . length > 0 ;
66+
67+ const hasFilesToDelete =
68+ Array . isArray ( change . filesToDelete ) &&
69+ change . filesToDelete . length > 0 ;
70+
71+ if ( ! hasFiles && ! hasFilesToDelete ) {
72+ return reject (
73+ `either changes[].files or changes[].filesToDelete are required`
74+ ) ;
6675 }
6776
6877 const treeItems = [ ] ;
69- for ( let fileName in change . files ) {
70- let properties = change . files [ fileName ] || "" ;
78+ // Handle file deletions
79+ if ( hasFilesToDelete ) {
80+ for ( const fileName of change . filesToDelete ) {
81+ const exists = await fileExistsInRepo (
82+ octokit ,
83+ owner ,
84+ repo ,
85+ fileName ,
86+ baseTree
87+ ) ;
88+
89+ // If it doesn't exist, and we're not ignoring missing files
90+ // reject the promise
91+ if ( ! exists && ! change . ignoreDeletionFailures ) {
92+ return reject (
93+ `The file ${ fileName } could not be found in the repo`
94+ ) ;
95+ }
96+
97+ // At this point it either exists, or we're ignoring failures
98+ if ( exists ) {
99+ treeItems . push ( {
100+ path : fileName ,
101+ sha : null , // sha as null implies that the file should be deleted
102+ mode : "100644" ,
103+ type : "commit" ,
104+ } ) ;
105+ }
106+ }
107+ }
108+
109+ for ( const fileName in change . files ) {
110+ const properties = change . files [ fileName ] || "" ;
71111
72- let contents = properties . contents || properties ;
73- let mode = properties . mode || "100644" ;
74- let type = properties . type || "blob" ;
112+ const contents = properties . contents || properties ;
113+ const mode = properties . mode || "100644" ;
114+ const type = properties . type || "blob" ;
75115
76116 if ( ! contents ) {
77117 return reject ( `No file contents provided for ${ fileName } ` ) ;
78118 }
79119
80- let fileSha ;
81- if ( type == "commit" ) {
82- fileSha = contents ;
83- } else {
84- let file = (
85- await octokit . git . createBlob ( {
86- owner,
87- repo,
88- content : Buffer . from ( contents ) . toString ( "base64" ) ,
89- encoding : "base64"
90- } )
91- ) . data ;
92- fileSha = file . sha ;
93- }
120+ const fileSha = await createBlob (
121+ octokit ,
122+ owner ,
123+ repo ,
124+ contents ,
125+ type
126+ ) ;
94127
95128 treeItems . push ( {
96129 path : fileName ,
97130 sha : fileSha ,
98131 mode : mode ,
99- type : type
132+ type : type ,
100133 } ) ;
101134 }
102135
136+ // no need to issue further requests if there are no updates, creations and deletions
137+ if ( treeItems . length === 0 ) {
138+ continue ;
139+ }
140+
103141 // Add those blobs to a tree
104- let tree = (
105- await octokit . git . createTree ( {
106- owner,
107- repo,
108- tree : treeItems ,
109- base_tree : baseTree
110- } )
111- ) . data ;
142+ const tree = await createTree (
143+ octokit ,
144+ owner ,
145+ repo ,
146+ treeItems ,
147+ baseTree
148+ ) ;
112149
113150 // Create a commit that points to that tree
114- let commit = (
115- await octokit . git . createCommit ( {
116- owner,
117- repo,
118- message,
119- tree : tree . sha ,
120- parents : [ baseTree ]
121- } )
122- ) . data ;
151+ const commit = await createCommit (
152+ octokit ,
153+ owner ,
154+ repo ,
155+ message ,
156+ tree ,
157+ baseTree
158+ ) ;
123159
124160 // Update the base tree if we have another commit to make
125161 baseTree = commit . sha ;
@@ -135,15 +171,13 @@ module.exports = function(octokit, opts) {
135171 updateRefBase = "" ;
136172 }
137173
138- const branch = (
139- await octokit . git [ action ] ( {
140- owner,
141- repo,
142- force : true ,
143- ref : `${ updateRefBase } heads/${ branchName } ` ,
144- sha : baseTree
145- } )
146- ) . data ;
174+ await octokit . git [ action ] ( {
175+ owner,
176+ repo,
177+ force : true ,
178+ ref : `${ updateRefBase } heads/${ branchName } ` ,
179+ sha : baseTree ,
180+ } ) ;
147181
148182 // Return the new branch name so that we can use it later
149183 // e.g. to create a pull request
@@ -154,16 +188,69 @@ module.exports = function(octokit, opts) {
154188 } ) ;
155189} ;
156190
157- async function loadRef ( octokit , owner , repo , ref ) {
191+ async function fileExistsInRepo ( octokit , owner , repo , path , branch ) {
158192 try {
159- return (
160- await octokit . git . getRef ( {
193+ await octokit . repos . getContent ( {
194+ method : "HEAD" ,
195+ owner,
196+ repo,
197+ path,
198+ ref : branch ,
199+ } ) ;
200+ return true ;
201+ } catch ( e ) {
202+ return false ;
203+ }
204+ }
205+
206+ async function createCommit ( octokit , owner , repo , message , tree , baseTree ) {
207+ return (
208+ await octokit . git . createCommit ( {
209+ owner,
210+ repo,
211+ message,
212+ tree : tree . sha ,
213+ parents : [ baseTree ] ,
214+ } )
215+ ) . data ;
216+ }
217+
218+ async function createTree ( octokit , owner , repo , treeItems , baseTree ) {
219+ return (
220+ await octokit . git . createTree ( {
221+ owner,
222+ repo,
223+ tree : treeItems ,
224+ base_tree : baseTree ,
225+ } )
226+ ) . data ;
227+ }
228+
229+ async function createBlob ( octokit , owner , repo , contents , type ) {
230+ if ( type === "commit" ) {
231+ return contents ;
232+ } else {
233+ const file = (
234+ await octokit . git . createBlob ( {
161235 owner,
162236 repo,
163- ref : `heads/${ ref } `
237+ content : Buffer . from ( contents ) . toString ( "base64" ) ,
238+ encoding : "base64" ,
164239 } )
165- ) . data . object . sha ;
240+ ) . data ;
241+ return file . sha ;
242+ }
243+ }
244+
245+ async function loadRef ( octokit , owner , repo , ref ) {
246+ try {
247+ const x = await octokit . git . getRef ( {
248+ owner,
249+ repo,
250+ ref : `heads/${ ref } ` ,
251+ } ) ;
252+ return x . data . object . sha ;
166253 } catch ( e ) {
167- //console.log(e);
254+ // console.log(e);
168255 }
169256}
0 commit comments