1- import { exec } from '@actions/exec' ;
21import { getInput , info } from '@actions/core' ;
2+ import {
3+ S3Client ,
4+ ListObjectsV2Command ,
5+ GetObjectCommand ,
6+ PutObjectCommand
7+ } from '@aws-sdk/client-s3' ;
38import {
49 BASE_IMAGE_NAME ,
510 BASE_IMAGES_DIRECTORY ,
@@ -8,62 +13,172 @@ import {
813} from 'shared' ;
914import { map } from 'bluebird' ;
1015import * as path from 'path' ;
16+ import * as fs from 'fs' ;
17+ import { promises as fsPromises } from 'fs' ;
18+ import { glob } from 'glob' ;
19+ import { Readable } from 'stream' ;
20+
21+ const s3Client = new S3Client ( ) ;
22+
23+ async function checkS3PrefixExists (
24+ bucketName : string ,
25+ prefix : string
26+ ) : Promise < boolean > {
27+ try {
28+ const command = new ListObjectsV2Command ( {
29+ Bucket : bucketName ,
30+ Prefix : prefix ,
31+ MaxKeys : 1
32+ } ) ;
33+ const response = await s3Client . send ( command ) ;
34+ return ( response . Contents ?. length ?? 0 ) > 0 ;
35+ } catch {
36+ return false ;
37+ }
38+ }
39+
40+ async function downloadS3Directory (
41+ bucketName : string ,
42+ s3Prefix : string ,
43+ localDir : string
44+ ) : Promise < void > {
45+ const command = new ListObjectsV2Command ( {
46+ Bucket : bucketName ,
47+ Prefix : s3Prefix
48+ } ) ;
49+
50+ const response = await s3Client . send ( command ) ;
51+ const objects = response . Contents ?? [ ] ;
52+
53+ await map ( objects , async object => {
54+ if ( ! object . Key ) return ;
55+
56+ const relativePath = object . Key . substring ( s3Prefix . length ) ;
57+ const localFilePath = path . join ( localDir , relativePath ) ;
58+
59+ await fsPromises . mkdir ( path . dirname ( localFilePath ) , { recursive : true } ) ;
60+
61+ const getCommand = new GetObjectCommand ( {
62+ Bucket : bucketName ,
63+ Key : object . Key
64+ } ) ;
65+
66+ const { Body } = await s3Client . send ( getCommand ) ;
67+ if ( Body instanceof Readable ) {
68+ const writeStream = fs . createWriteStream ( localFilePath ) ;
69+ await new Promise ( ( resolve , reject ) => {
70+ Body . pipe ( writeStream ) . on ( 'finish' , resolve ) . on ( 'error' , reject ) ;
71+ } ) ;
72+ }
73+ } ) ;
74+ }
75+
76+ async function uploadLocalDirectory (
77+ localDir : string ,
78+ bucketName : string ,
79+ s3Prefix : string
80+ ) : Promise < void > {
81+ const files = await glob ( '**/*' , {
82+ cwd : localDir ,
83+ nodir : true ,
84+ absolute : false
85+ } ) ;
86+
87+ await map ( files , async file => {
88+ const localFilePath = path . join ( localDir , file ) ;
89+ const s3Key = path . join ( s3Prefix , file ) ;
90+
91+ const fileContent = await fsPromises . readFile ( localFilePath ) ;
92+
93+ const command = new PutObjectCommand ( {
94+ Bucket : bucketName ,
95+ Key : s3Key ,
96+ Body : fileContent
97+ } ) ;
98+
99+ await s3Client . send ( command ) ;
100+ } ) ;
101+ }
102+
103+ async function uploadSingleFile (
104+ localFilePath : string ,
105+ bucketName : string ,
106+ s3Key : string
107+ ) : Promise < void > {
108+ const fileContent = await fsPromises . readFile ( localFilePath ) ;
109+
110+ const command = new PutObjectCommand ( {
111+ Bucket : bucketName ,
112+ Key : s3Key ,
113+ Body : fileContent
114+ } ) ;
115+
116+ await s3Client . send ( command ) ;
117+ }
11118
12119export const downloadBaseImages = async ( ) => {
13120 const bucketName = getInput ( 'bucket-name' , { required : true } ) ;
14121 const screenshotsDirectory = getInput ( 'screenshots-directory' ) ;
15- const baseImageExitCode = await exec (
16- `aws s3 ls s3:// ${ bucketName } / ${ BASE_IMAGES_DIRECTORY } /` ,
17- [ ] ,
18- { ignoreReturnCode : true }
122+
123+ const prefixExists = await checkS3PrefixExists (
124+ bucketName ,
125+ ` ${ BASE_IMAGES_DIRECTORY } /`
19126 ) ;
20- if ( baseImageExitCode !== 0 ) {
127+
128+ if ( ! prefixExists ) {
21129 info (
22130 `Base images directory does not exist in bucket ${ bucketName } . Skipping download.`
23131 ) ;
24- await exec ( ` mkdir -p ${ screenshotsDirectory } ` ) ;
132+ await fsPromises . mkdir ( screenshotsDirectory , { recursive : true } ) ;
25133 return ;
26134 }
27135
28136 const packagePaths = getInput ( 'package-paths' ) ?. split ( ',' ) ;
29137 if ( packagePaths ) {
30138 return Promise . all (
31139 packagePaths . map ( packagePath =>
32- exec (
33- `aws s3 cp s3://${ bucketName } /${ BASE_IMAGES_DIRECTORY } /${ packagePath } ${ screenshotsDirectory } /${ packagePath } --recursive`
140+ downloadS3Directory (
141+ bucketName ,
142+ `${ BASE_IMAGES_DIRECTORY } /${ packagePath } /` ,
143+ path . join ( screenshotsDirectory , packagePath )
34144 )
35145 )
36146 ) ;
37147 }
38148
39- return exec (
40- `aws s3 cp s3://${ bucketName } /${ BASE_IMAGES_DIRECTORY } ${ screenshotsDirectory } --recursive`
149+ return downloadS3Directory (
150+ bucketName ,
151+ `${ BASE_IMAGES_DIRECTORY } /` ,
152+ screenshotsDirectory
41153 ) ;
42154} ;
43155
44156export const uploadAllImages = async ( hash : string ) => {
45157 const bucketName = getInput ( 'bucket-name' , { required : true } ) ;
46158 const screenshotsDirectory = getInput ( 'screenshots-directory' ) ;
47159 const packagePaths = getInput ( 'package-paths' ) ?. split ( ',' ) ;
160+
48161 if ( packagePaths ) {
49162 return map ( packagePaths , packagePath =>
50- exec (
51- `aws s3 cp ${ screenshotsDirectory } /${ packagePath } s3://${ bucketName } /${ NEW_IMAGES_DIRECTORY } /${ hash } /${ packagePath } --recursive`
163+ uploadLocalDirectory (
164+ path . join ( screenshotsDirectory , packagePath ) ,
165+ bucketName ,
166+ `${ NEW_IMAGES_DIRECTORY } /${ hash } /${ packagePath } /`
52167 )
53168 ) ;
54169 }
55170
56- return exec (
57- `aws s3 cp ${ screenshotsDirectory } s3://${ bucketName } /${ NEW_IMAGES_DIRECTORY } /${ hash } --recursive`
171+ return uploadLocalDirectory (
172+ screenshotsDirectory ,
173+ bucketName ,
174+ `${ NEW_IMAGES_DIRECTORY } /${ hash } /`
58175 ) ;
59176} ;
60177
61178export const uploadBaseImages = async ( newFilePaths : string [ ] ) => {
62179 const bucketName = getInput ( 'bucket-name' , { required : true } ) ;
63180 return map ( newFilePaths , newFilePath =>
64- exec (
65- `aws s3 cp ${ newFilePath } s3://${ bucketName } /${ buildBaseImagePath ( newFilePath ) } `
66- )
181+ uploadSingleFile ( newFilePath , bucketName , buildBaseImagePath ( newFilePath ) )
67182 ) ;
68183} ;
69184
0 commit comments