11/* eslint no-console: 0 */
22/* eslint max-len: 0 */
3+ import fs from 'fs' ;
34import path from 'path' ;
4- import GitHubApi from 'github ' ;
5+ import Octokit from '@octokit/rest ' ;
56import program from 'commander' ;
7+ import * as LinkHeader from 'http-link-header' ;
8+ import * as mime from 'mime-types' ;
69import minimatch from 'minimatch' ;
10+ import parse from 'url-parse' ;
711import pkg from '../package.json' ;
812
13+ const octokit = new Octokit ( ) ;
14+
915program
1016 . version ( pkg . version )
1117 . usage ( '<command> [<args>]' )
@@ -32,115 +38,31 @@ program.parse(process.argv);
3238
3339const [ command , ...args ] = program . args ;
3440
35- const github = new GitHubApi ( {
36- version : '3.0.0' ,
37- timeout : 5000 ,
38- headers : {
39- 'user-agent' : 'GitHub-Release-App'
40- }
41- } ) ;
42-
43- github . authenticate ( {
44- type : 'oauth' ,
45- token : program . token || process . env . GITHUB_TOKEN
46- } ) ;
47-
48- const getReleaseByTag = ( options ) => {
49- return new Promise ( async ( resolve , reject ) => {
50- try {
51- let page = 1 ;
52- let lastPage = 1 ;
53- let foundRelease = false ;
54-
55- do {
56- const releases = await getReleases ( {
57- owner : options . owner ,
58- repo : options . repo ,
59- page : page ,
60- per_page : 30
61- } ) ;
62-
63- const searchedReleases = releases . filter ( r => ( r . tag_name === options . tag ) || ( r . name === options . tag ) ) ;
64- if ( searchedReleases . length ) {
65- resolve ( releases [ 0 ] ) ;
66- foundRelease = true ;
67- break ;
68- }
69-
70- const pagination = ( releases . meta . link || '' ) . split ( ',' )
71- . reduce ( ( acc , link ) => {
72- const r = link . match ( / \? p a g e = ( \d ) + .* r e l = " ( \w + ) " / ) ;
73- if ( r && r [ 1 ] && r [ 2 ] ) {
74- const key = r [ 2 ] ;
75- const value = Number ( r [ 1 ] ) || 0 ;
76- acc [ key ] = value ;
77- }
78- return acc ;
79- } , { } ) ;
80-
81- if ( pagination . last > 0 ) {
82- lastPage = pagination . last ;
83- }
84-
85- ++ page ;
86- } while ( page <= lastPage ) ;
87-
88- if ( ! foundRelease ) {
89- reject ( 'Cannot find release' ) ;
90- }
91- } catch ( err ) {
92- reject ( err ) ;
93- }
41+ if ( ! command !== 'list' ) {
42+ octokit . authenticate ( {
43+ type : 'oauth' ,
44+ token : program . token || process . env . GITHUB_TOKEN
9445 } ) ;
95- } ;
46+ }
9647
97- const getReleases = ( options ) => {
98- return new Promise ( ( resolve , reject ) => {
99- github . repos . getReleases ( options , ( err , res ) => {
100- err ? reject ( err ) : resolve ( res ) ;
101- } ) ;
102- } ) ;
103- } ;
104-
105- const createRelease = ( options ) => {
106- return new Promise ( ( resolve , reject ) => {
107- github . repos . createRelease ( options , ( err , res ) => {
108- err ? reject ( err ) : resolve ( res ) ;
109- } ) ;
110- } ) ;
111- } ;
112-
113- const editRelease = ( options ) => {
114- return new Promise ( ( resolve , reject ) => {
115- github . repos . editRelease ( options , ( err , res ) => {
116- err ? reject ( err ) : resolve ( res ) ;
117- } ) ;
118- } ) ;
119- } ;
48+ function next ( response ) {
49+ if ( ! response . headers || ! response . headers . link ) {
50+ return false ;
51+ }
12052
121- const getAssets = ( options ) => {
122- return new Promise ( ( resolve , reject ) => {
123- github . repos . getAssets ( options , ( err , res ) => {
124- err ? reject ( err ) : resolve ( res ) ;
125- } ) ;
126- } ) ;
127- } ;
53+ let link = LinkHeader . parse ( response . headers . link ) . rel ( 'next' ) ;
54+ if ( ! link ) {
55+ return false ;
56+ }
12857
129- const deleteAsset = ( options ) => {
130- return new Promise ( ( resolve , reject ) => {
131- github . repos . deleteAsset ( options , ( err , res ) => {
132- err ? reject ( err ) : resolve ( res ) ;
133- } ) ;
134- } ) ;
135- } ;
58+ const url = parse ( link [ 0 ] . uri , null , true ) ;
59+ if ( ! url . query ) {
60+ return false ;
61+ }
13662
137- const uploadAsset = ( options ) => {
138- return new Promise ( ( resolve , reject ) => {
139- github . repos . uploadAsset ( options , ( err , res ) => {
140- err ? reject ( err ) : resolve ( res ) ;
141- } ) ;
142- } ) ;
143- } ;
63+ const nextPage = parseInt ( url . query . page ) ;
64+ return nextPage ;
65+ }
14466
14567const fn = {
14668 'upload' : async ( ) => {
@@ -149,60 +71,58 @@ const fn = {
14971 let release ;
15072
15173 try {
152- console . log ( '> releases# getReleaseByTag' ) ;
153- release = await getReleaseByTag ( {
74+ console . log ( `> getReleaseByTag: owner= ${ owner } , repo= ${ repo } , tag= ${ tag } ` ) ;
75+ const res = await octokit . repos . getReleaseByTag ( {
15476 owner : owner ,
15577 repo : repo ,
156- tag : tag
78+ tag : tag ,
15779 } ) ;
80+ release = res . data ;
15881 } catch ( err ) {
15982 // Ignore
16083 }
16184
16285 try {
16386 if ( ! release ) {
164- console . log ( '> releases# createRelease' ) ;
165- release = await createRelease ( {
166- owner : owner ,
167- repo : repo ,
87+ console . log ( `> createRelease: tag_name= ${ tag } , name= ${ name || tag } , draft= ${ ! ! draft } , prerelease= ${ ! ! prerelease } ` ) ;
88+ const res = await octokit . repos . createRelease ( {
89+ owner,
90+ repo,
16891 tag_name : tag ,
16992 name : name || tag ,
17093 body : body || '' ,
17194 draft : ! ! draft ,
172- prerelease : ! ! prerelease
95+ prerelease : ! ! prerelease ,
17396 } ) ;
97+ release = res . data ;
17498 } else {
175- console . log ( '> releases#editRelease' ) ;
176- let releaseOptions = {
177- owner : owner ,
178- repo : repo ,
179- id : release . id ,
99+ console . log ( `> updateRelease: release_id= ${ release . id } , tag_name= ${ tag } , name= ${ name || tag } ` ) ;
100+ const res = await octokit . repos . updateRelease ( {
101+ owner,
102+ repo,
103+ release_id : release . id ,
180104 tag_name : tag ,
181105 name : name || tag ,
182- body : ( body === undefined )
183- ? release . body || ''
184- : body || '' ,
185- draft : ( draft === undefined )
186- ? ! ! release . draft
187- : false ,
188- prerelease : ( prerelease === undefined )
189- ? ! ! release . prerelease
190- : false
191- } ;
192- release = await editRelease ( releaseOptions ) ;
106+ body : ( body === undefined ) ? release . body || '' : body || '' ,
107+ draft : ( draft === undefined ) ? ! ! release . draft : false ,
108+ prerelease : ( prerelease === undefined ) ? ! ! release . prerelease : false ,
109+ } ) ;
110+ release = res . data ;
193111 }
194112
195113 if ( files . length > 0 ) {
196- console . log ( '> releases#uploadAsset' ) ;
114+ console . log ( `> uploadReleaseAsset: assets_url= ${ release . assets_url } ` ) ;
197115 for ( let i = 0 ; i < files . length ; ++ i ) {
198116 const file = files [ i ] ;
199- console . log ( '#%d name="%s" filePath="%s"' , i + 1 , path . basename ( file ) , file ) ;
200- await uploadAsset ( {
201- owner : owner ,
202- repo : repo ,
203- id : release . id ,
204- filePath : file ,
205- name : path . basename ( file )
117+ console . log ( ` #${ i + 1 } : name="${ path . basename ( file ) } " filePath="${ file } "` ) ;
118+ await octokit . repos . uploadReleaseAsset ( {
119+ url : release . upload_url ,
120+ file : fs . createReadStream ( file ) ,
121+ headers : {
122+ 'Content-Type' : mime . lookup ( file ) || 'application/octet-stream' ,
123+ 'Content-Length' : fs . statSync ( file ) . size ,
124+ } ,
125+ name : path . basename ( file ) ,
206126 } ) ;
207127 }
208128 }
@@ -216,54 +136,77 @@ const fn = {
216136 let release ;
217137
218138 try {
219- console . log ( '> releases# getReleaseByTag' ) ;
220- release = await getReleaseByTag ( {
139+ console . log ( `> getReleaseByTag: owner= ${ owner } , repo= ${ repo } , tag= ${ tag } ` ) ;
140+ const res = await octokit . repos . getReleaseByTag ( {
221141 owner : owner ,
222142 repo : repo ,
223- tag : tag
143+ tag : tag ,
224144 } ) ;
145+ release = res . data ;
225146 } catch ( err ) {
226147 console . error ( err ) ;
227148 return ;
228149 }
229150
230151 try {
231- console . log ( '> releases#getAssets' ) ;
232- const assets = await getAssets ( {
233- owner : owner ,
234- repo : repo ,
235- id : release . id
236- } ) ;
152+ const release_id = release . id ;
153+ console . log ( `> listAssetsForRelease: release_id=${ release_id } ` ) ;
154+
155+ let assets = [ ] ;
156+ let page = 1 ;
157+ do {
158+ const res = await octokit . repos . listAssetsForRelease ( { owner, repo, release_id, page } ) ;
159+ assets = assets . concat ( res . data ) ;
160+ page = next ( res ) ;
161+ } while ( page )
162+
237163 const deleteAssets = assets . filter ( asset => {
238164 return patterns . some ( pattern => minimatch ( asset . name , pattern ) ) ;
239165 } ) ;
240- console . log ( 'assets=%d, deleteAssets=%d' , assets . length , deleteAssets . length ) ;
166+ console . log ( ` assets= ${ assets . length } , deleteAssets= ${ deleteAssets . length } ` ) ;
241167
242168 if ( deleteAssets . length > 0 ) {
243- console . log ( '> releases#deleteAsset ' ) ;
169+ console . log ( '> deleteReleaseAsset: ' ) ;
244170 for ( let i = 0 ; i < deleteAssets . length ; ++ i ) {
245171 const asset = deleteAssets [ i ] ;
246- console . log ( '#%d' , i + 1 , {
172+ console . log ( ` # ${ i + 1 } :` , {
247173 id : asset . id ,
248174 name : asset . name ,
249175 label : asset . label ,
250176 state : asset . state ,
251177 size : asset . size ,
252178 download_count : asset . download_count ,
253179 created_at : asset . created_at ,
254- updated_at : asset . updated_at
255- } ) ;
256- await deleteAsset ( {
257- owner : owner ,
258- repo : repo ,
259- id : asset . id
180+ updated_at : asset . updated_at ,
260181 } ) ;
182+ await octokit . repos . deleteReleaseAsset ( { owner, repo, asset_id : asset . id } ) ;
261183 }
262184 }
263185 } catch ( err ) {
264186 console . error ( err ) ;
265187 }
266- }
188+ } ,
189+ 'list' : async ( ) => {
190+ const releases = await octokit . repos . listReleases ( {
191+ owner : program . owner ,
192+ repo : program . repo ,
193+ page : 1 ,
194+ } ) ;
195+ for ( const release of releases . data ) {
196+ console . log ( `${ release . name } (${ release . tag_name } )` ) ;
197+ }
198+ } ,
267199} [ command ] ;
268200
269- typeof fn === 'function' && fn ( ) ;
201+ async function main ( ) {
202+ try {
203+ typeof fn === 'function' && await fn ( ) ;
204+ } catch ( err ) {
205+ // message has token in the response
206+ const message = err . message . replace ( / h t t p s ? : [ ^ \s ] * / g, ( match ) => match . replace ( / \? .* / , '' ) ) ;
207+ console . log ( message ) ;
208+ process . exit ( 1 ) ;
209+ }
210+ }
211+
212+ main ( )
0 commit comments