11import fs from 'fs-extra'
22import shell from 'shelljs'
3- import { dirname , basename } from 'path'
3+ import { dirname , basename , extname } from 'path'
44import fetch from 'node-fetch'
55import { extension } from 'mime-types'
66
@@ -12,7 +12,7 @@ const retryDelayRateLimit = 6 * 60
1212const retryDelayOthers = 6
1313
1414const { USERNAME , TOKEN } = process . env
15- const FOLDER = '/usr/src/backup'
15+ const folder = '/usr/src/backup'
1616
1717function delay ( seconds ) {
1818 return new Promise ( resolve => {
@@ -31,10 +31,11 @@ function request(path, options = {}) {
3131 let resp
3232 try {
3333 resp = await fetch ( `${ baseUrl } ${ path } ` , {
34+ ...options ,
3435 headers : {
35- Authorization : `Token ${ TOKEN } `
36- } ,
37- ... options
36+ Authorization : `Token ${ TOKEN } ` ,
37+ ... options . headers || { }
38+ }
3839 } )
3940 } catch {
4041 console . log ( `... failed at #${ n } attempt` )
@@ -113,9 +114,12 @@ async function requestAllWithRetry(path, options) {
113114
114115function downloadFile ( sourceFileUrl , targetFilePath ) {
115116 return new Promise ( async ( resolve , reject ) => {
116- const response = await request ( sourceFileUrl )
117- const ext = extension ( [ ...response . headers ] . filter ( obj => obj [ 0 ] === 'content-type' ) [ 0 ] [ 1 ] )
118- targetFilePath = targetFilePath + ( ext ? '.' + ext : '' )
117+ const response = await request ( sourceFileUrl , { headers : { Accept : 'application/octet-stream' } } )
118+ if ( ! extname ( targetFilePath ) ) {
119+ const ext = extension ( [ ...response . headers ] . filter ( obj => obj [ 0 ] === 'content-type' ) [ 0 ] [ 1 ] )
120+ targetFilePath = targetFilePath + ( ext ? '.' + ext : '' )
121+ }
122+ fs . ensureDirSync ( dirname ( targetFilePath ) )
119123 const fileStream = fs . createWriteStream ( targetFilePath )
120124 response . body . pipe ( fileStream )
121125 response . body . on ( 'error' , ( ) => { return reject ( ) } )
@@ -125,18 +129,18 @@ function downloadFile(sourceFileUrl, targetFilePath) {
125129 } )
126130}
127131
128- function downloadAssets ( body , FOLDER , filename ) {
132+ function downloadImages ( body , folder , filename ) {
129133 return new Promise ( async ( resolve , reject ) => {
130134 try {
131- const assets = body ?. match ( / [ " ( ] h t t p s : \/ \/ g i t h u b \. c o m \/ ( .+ ) \/ a s s e t s \/ ( .+ ) [ ) " ] / g) || [ ]
132- for ( let n = 0 ; n < assets . length ; n ++ ) {
133- const targetFilename = filename . replace ( '{id}' , ( n + 1 ) . toString ( ) . padStart ( assets . length . toString ( ) . length , '0' ) )
134- const targetPath = FOLDER + '/' + targetFilename
135- const sourceUrl = assets [ n ] . replace ( / ^ [ " ( ] ( .+ ) [ ) " ] $ / , '$1' )
136- fs . ensureDirSync ( FOLDER )
135+ const images = body ?. match ( / [ " ( ] h t t p s : \/ \/ g i t h u b \. c o m \/ ( .+ ) \/ a s s e t s \/ ( .+ ) [ ) " ] / g) || [ ]
136+ for ( let n = 0 ; n < images . length ; n ++ ) {
137+ const targetFilename = filename . replace ( '{id}' , ( n + 1 ) . toString ( ) . padStart ( images . length . toString ( ) . length , '0' ) )
138+ const targetPath = folder + '/' + targetFilename
139+ const sourceUrl = images [ n ] . replace ( / ^ [ " ( ] ( .+ ) [ ) " ] $ / , '$1' )
140+ fs . ensureDirSync ( folder )
137141 const realTargetFilename = basename ( await downloadFile ( sourceUrl , targetPath ) )
138- body = body . replace ( `"${ sourceUrl } "` , '"./assets /' + realTargetFilename + '"' )
139- body = body . replace ( `(${ sourceUrl } )` , '(./assets /' + realTargetFilename + ')' )
142+ body = body . replace ( `"${ sourceUrl } "` , '"./images /' + realTargetFilename + '"' )
143+ body = body . replace ( `(${ sourceUrl } )` , '(./images /' + realTargetFilename + ')' )
140144 }
141145 return resolve ( body )
142146 } catch ( err ) {
@@ -153,14 +157,14 @@ function writeJSON(path, json) {
153157async function backup ( ) {
154158 try {
155159
156- // Reset the backup FOLDER
157- fs . emptyDirSync ( FOLDER )
160+ // Reset the backup folder
161+ fs . emptyDirSync ( folder )
158162
159163 // Get repositories
160164 const repositories = await requestAllWithRetry ( '/user/repos' )
161165
162166 // Save repositories
163- writeJSON ( `${ FOLDER } /repositories.json` , repositories )
167+ writeJSON ( `${ folder } /repositories.json` , repositories )
164168
165169 // Loop repositories
166170 for ( const repository of repositories . filter ( rep => rep . name === 'test' ) ) {
@@ -171,10 +175,10 @@ async function backup() {
171175 // Loop issues
172176 for ( const issue of issues ) {
173177
174- // Download issue assets
175- issue . body = await downloadAssets (
178+ // Download issue images
179+ issue . body = await downloadImages (
176180 issue . body ,
177- `${ FOLDER } /repositories/${ repository . name } /assets ` ,
181+ `${ folder } /repositories/${ repository . name } /images ` ,
178182 `issue_${ issue . id } _{id}`
179183 )
180184
@@ -187,10 +191,10 @@ async function backup() {
187191 // Loop issue comments
188192 for ( const comment of comments ) {
189193
190- // Download issue assets
191- comment . body = await downloadAssets (
194+ // Download issue comment images
195+ comment . body = await downloadImages (
192196 comment . body ,
193- `${ FOLDER } /repositories/${ repository . name } /assets ` ,
197+ `${ folder } /repositories/${ repository . name } /images ` ,
194198 `issue_${ issue . id } _comment_${ comment . id } _{id}`
195199 )
196200
@@ -199,20 +203,49 @@ async function backup() {
199203 }
200204
201205 // Save issues
202- writeJSON ( `${ FOLDER } /repositories/${ repository . name } /issues.json` , issues )
206+ writeJSON ( `${ folder } /repositories/${ repository . name } /issues.json` , issues )
207+
208+ // Get releases
209+ const releases = await requestAllWithRetry ( `/repos/${ USERNAME } /${ repository . name } /releases` )
210+
211+ // Loop releases
212+ for ( const release of releases ) {
213+
214+ // Download release text images
215+ release . body = await downloadImages (
216+ release . body ,
217+ `${ folder } /repositories/${ repository . name } /images` ,
218+ `release_${ release . id } _{id}`
219+ )
220+
221+ // Loop release assets
222+ for ( const asset of release . assets ) {
223+
224+ // Download release assets
225+ downloadFile (
226+ asset . url ,
227+ `${ folder } /repositories/${ repository . name } /releases/${ release . tag_name } /${ asset . name } `
228+ )
229+
230+ }
231+
232+ }
233+
234+ // Save releases
235+ writeJSON ( `${ folder } /repositories/${ repository . name } /releases.json` , releases )
203236
204237 // Clone repository
205- shell . exec ( `git clone https://${ TOKEN } @github.com/${ USERNAME } /${ repository . name } .git ${ FOLDER } /repositories/${ repository . name } /repository` )
238+ shell . exec ( `git clone https://${ TOKEN } @github.com/${ USERNAME } /${ repository . name } .git ${ folder } /repositories/${ repository . name } /repository` )
206239
207240 }
208241
209242 // Get user details
210243 const user = await requestJson ( '/user' )
211- writeJSON ( `${ FOLDER } /user/user.json` , user )
244+ writeJSON ( `${ folder } /user/user.json` , user )
212245
213246 // Get starred repositories
214247 const starred = await requestAllWithRetry ( '/user/starred' )
215- writeJSON ( `${ FOLDER } /user/starred.json` , starred )
248+ writeJSON ( `${ folder } /user/starred.json` , starred )
216249
217250 // Complete script
218251 console . log ( 'Backup completed!' )
0 commit comments