@@ -2,7 +2,7 @@ module.exports = function(octokit, opts) {
2
2
return new Promise ( async ( resolve , reject ) => {
3
3
// Up front validation
4
4
try {
5
- for ( let req of [ "owner" , "repo" , "branch" ] ) {
5
+ for ( const req of [ "owner" , "repo" , "branch" ] ) {
6
6
if ( ! opts [ req ] ) {
7
7
return reject ( `'${ req } ' is a required parameter` ) ;
8
8
}
@@ -19,7 +19,7 @@ module.exports = function(octokit, opts) {
19
19
base,
20
20
branch : branchName ,
21
21
createBranch,
22
- changes
22
+ changes,
23
23
} = opts ;
24
24
25
25
let branchAlreadyExists = true ;
@@ -43,7 +43,7 @@ module.exports = function(octokit, opts) {
43
43
base = (
44
44
await octokit . repos . get ( {
45
45
owner,
46
- repo
46
+ repo,
47
47
} )
48
48
) . data . default_branch ;
49
49
}
@@ -56,70 +56,106 @@ module.exports = function(octokit, opts) {
56
56
}
57
57
58
58
// Create blobs
59
- for ( let change of changes ) {
60
- let message = change . message ;
59
+ for ( const change of changes ) {
60
+ const message = change . message ;
61
61
if ( ! message ) {
62
62
return reject ( `changes[].message is a required parameter` ) ;
63
63
}
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
+ ) ;
66
75
}
67
76
68
77
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 ] || "" ;
71
111
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" ;
75
115
76
116
if ( ! contents ) {
77
117
return reject ( `No file contents provided for ${ fileName } ` ) ;
78
118
}
79
119
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
+ ) ;
94
127
95
128
treeItems . push ( {
96
129
path : fileName ,
97
130
sha : fileSha ,
98
131
mode : mode ,
99
- type : type
132
+ type : type ,
100
133
} ) ;
101
134
}
102
135
136
+ // no need to issue further requests if there are no updates, creations and deletions
137
+ if ( treeItems . length === 0 ) {
138
+ continue ;
139
+ }
140
+
103
141
// 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
+ ) ;
112
149
113
150
// 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
+ ) ;
123
159
124
160
// Update the base tree if we have another commit to make
125
161
baseTree = commit . sha ;
@@ -135,15 +171,13 @@ module.exports = function(octokit, opts) {
135
171
updateRefBase = "" ;
136
172
}
137
173
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
+ } ) ;
147
181
148
182
// Return the new branch name so that we can use it later
149
183
// e.g. to create a pull request
@@ -154,16 +188,69 @@ module.exports = function(octokit, opts) {
154
188
} ) ;
155
189
} ;
156
190
157
- async function loadRef ( octokit , owner , repo , ref ) {
191
+ async function fileExistsInRepo ( octokit , owner , repo , path , branch ) {
158
192
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 ( {
161
235
owner,
162
236
repo,
163
- ref : `heads/${ ref } `
237
+ content : Buffer . from ( contents ) . toString ( "base64" ) ,
238
+ encoding : "base64" ,
164
239
} )
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 ;
166
253
} catch ( e ) {
167
- //console.log(e);
254
+ // console.log(e);
168
255
}
169
256
}
0 commit comments