1
1
import { Base64 } from 'js-base64' ;
2
- import initial from 'lodash/initial' ;
3
- import last from 'lodash/last' ;
4
- import partial from 'lodash/partial' ;
5
- import result from 'lodash/result' ;
6
- import trim from 'lodash/trim' ;
2
+ import { trimStart , trim , result , partial , last , initial } from 'lodash' ;
7
3
8
4
import {
9
5
APIError ,
@@ -22,12 +18,12 @@ import type { ApiRequest, FetchError } from '@staticcms/core/lib/util';
22
18
import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy' ;
23
19
import type { Semaphore } from 'semaphore' ;
24
20
import type {
21
+ FilesResponse ,
25
22
GitGetBlobResponse ,
26
23
GitGetTreeResponse ,
27
24
GiteaUser ,
28
25
ReposGetResponse ,
29
26
ReposListCommitsResponse ,
30
- ContentsResponse ,
31
27
} from './types' ;
32
28
33
29
export const API_NAME = 'Gitea' ;
@@ -40,6 +36,20 @@ export interface Config {
40
36
originRepo ?: string ;
41
37
}
42
38
39
+ enum FileOperation {
40
+ CREATE = 'create' ,
41
+ DELETE = 'delete' ,
42
+ UPDATE = 'update' ,
43
+ }
44
+
45
+ export interface ChangeFileOperation {
46
+ content ?: string ;
47
+ from_path ?: string ;
48
+ path : string ;
49
+ operation : FileOperation ;
50
+ sha ?: string ;
51
+ }
52
+
43
53
interface MetaDataObjects {
44
54
entry : { path : string ; sha : string } ;
45
55
files : MediaFile [ ] ;
@@ -76,13 +86,6 @@ type MediaFile = {
76
86
path : string ;
77
87
} ;
78
88
79
- export type Diff = {
80
- path : string ;
81
- newFile : boolean ;
82
- sha : string ;
83
- binary : boolean ;
84
- } ;
85
-
86
89
export default class API {
87
90
apiRoot : string ;
88
91
token : string ;
@@ -120,7 +123,7 @@ export default class API {
120
123
121
124
static DEFAULT_COMMIT_MESSAGE = 'Automatically generated by Static CMS' ;
122
125
123
- user ( ) : Promise < { full_name : string ; login : string } > {
126
+ user ( ) : Promise < { full_name : string ; login : string ; avatar_url : string } > {
124
127
if ( ! this . _userPromise ) {
125
128
this . _userPromise = this . getUser ( ) ;
126
129
}
@@ -365,50 +368,53 @@ export default class API {
365
368
async persistFiles ( dataFiles : DataFile [ ] , mediaFiles : AssetProxy [ ] , options : PersistOptions ) {
366
369
// eslint-disable-next-line @typescript-eslint/no-explicit-any
367
370
const files : ( DataFile | AssetProxy ) [ ] = mediaFiles . concat ( dataFiles as any ) ;
368
- for ( const file of files ) {
369
- const item : { raw ?: string ; sha ?: string ; toBase64 ?: ( ) => Promise < string > } = file ;
370
- const contentBase64 = await result (
371
- item ,
372
- 'toBase64' ,
373
- partial ( this . toBase64 , item . raw as string ) ,
374
- ) ;
375
- try {
376
- const oldSha = await this . getFileSha ( file . path ) ;
377
- await this . updateBlob ( contentBase64 , file , options , oldSha ! ) ;
378
- } catch {
379
- await this . createBlob ( contentBase64 , file , options ) ;
380
- }
381
- }
371
+ const operations = await this . getChangeFileOperations ( files , this . branch ) ;
372
+ return this . changeFiles ( operations , options ) ;
382
373
}
383
374
384
- async updateBlob (
385
- contentBase64 : string ,
386
- file : AssetProxy | DataFile ,
387
- options : PersistOptions ,
388
- oldSha : string ,
389
- ) {
390
- await this . request ( `${ this . repoURL } /contents/${ file . path } ` , {
391
- method : 'PUT' ,
375
+ async changeFiles ( operations : ChangeFileOperation [ ] , options : PersistOptions ) {
376
+ return ( await this . request ( `${ this . repoURL } /contents` , {
377
+ method : 'POST' ,
392
378
body : JSON . stringify ( {
393
379
branch : this . branch ,
394
- content : contentBase64 ,
380
+ files : operations ,
395
381
message : options . commitMessage ,
396
- sha : oldSha ,
397
- signoff : false ,
398
382
} ) ,
399
- } ) ;
383
+ } ) ) as FilesResponse ;
400
384
}
401
385
402
- async createBlob ( contentBase64 : string , file : AssetProxy | DataFile , options : PersistOptions ) {
403
- await this . request ( `${ this . repoURL } /contents/${ file . path } ` , {
404
- method : 'POST' ,
405
- body : JSON . stringify ( {
406
- branch : this . branch ,
407
- content : contentBase64 ,
408
- message : options . commitMessage ,
409
- signoff : false ,
386
+ async getChangeFileOperations ( files : { path : string ; newPath ?: string } [ ] , branch : string ) {
387
+ const items : ChangeFileOperation [ ] = await Promise . all (
388
+ files . map ( async file => {
389
+ const content = await result (
390
+ file ,
391
+ 'toBase64' ,
392
+ partial ( this . toBase64 , ( file as DataFile ) . raw ) ,
393
+ ) ;
394
+ let sha ;
395
+ let operation ;
396
+ let from_path ;
397
+ let path = trimStart ( file . path , '/' ) ;
398
+ try {
399
+ sha = await this . getFileSha ( file . path , { branch } ) ;
400
+ operation = FileOperation . UPDATE ;
401
+ from_path = file . newPath && path ;
402
+ path = file . newPath ? trimStart ( file . newPath , '/' ) : path ;
403
+ } catch {
404
+ sha = undefined ;
405
+ operation = FileOperation . CREATE ;
406
+ }
407
+
408
+ return {
409
+ operation,
410
+ content,
411
+ path,
412
+ from_path,
413
+ sha,
414
+ } as ChangeFileOperation ;
410
415
} ) ,
411
- } ) ;
416
+ ) ;
417
+ return items ;
412
418
}
413
419
414
420
async getFileSha ( path : string , { repoURL = this . repoURL , branch = this . branch } = { } ) {
@@ -434,15 +440,18 @@ export default class API {
434
440
}
435
441
436
442
async deleteFiles ( paths : string [ ] , message : string ) {
437
- for ( const file of paths ) {
438
- const meta : ContentsResponse = await this . request ( `${ this . repoURL } /contents/${ file } ` , {
439
- method : 'GET' ,
440
- } ) ;
441
- await this . request ( `${ this . repoURL } /contents/${ file } ` , {
442
- method : 'DELETE' ,
443
- body : JSON . stringify ( { branch : this . branch , message, sha : meta . sha , signoff : false } ) ,
444
- } ) ;
445
- }
443
+ const operations : ChangeFileOperation [ ] = await Promise . all (
444
+ paths . map ( async path => {
445
+ const sha = await this . getFileSha ( path ) ;
446
+
447
+ return {
448
+ operation : FileOperation . DELETE ,
449
+ path,
450
+ sha,
451
+ } as ChangeFileOperation ;
452
+ } ) ,
453
+ ) ;
454
+ return this . changeFiles ( operations , { commitMessage : message } ) ;
446
455
}
447
456
448
457
toBase64 ( str : string ) {
0 commit comments