@@ -119,123 +119,152 @@ if (!fs.existsSync(path.resolve(`${filename}`))) {
119119}
120120const file = fs . readFileSync ( path . resolve ( `${ filename } ` ) , 'utf8' )
121121let yamlObject = YAML . parse ( file )
122- if ( yamlObject . include ) {
123- parseIncludes ( yamlObject ) . then ( result => {
124- yamlObject = result
125- if ( cmdOPS == 'CREATE' ) {
126- if ( ! optCMD ) {
127- index = readlineSync . keyInSelect ( yamlObject . stages , `Select a stage to execute ?` , {
128- cancel : `${ CBRIGHT } None${ CRESET } - (Escape)`
129- } )
130- optCMD = yamlObject . stages [ index ]
131- } else {
132- index = yamlObject . stages . indexOf ( optCMD )
122+ function getVolumeName ( projectName ) {
123+ return projectName . replace ( / [ & \/ \\ # , + ( ) $ ~ % . ' " : * ? < > { } ] / g, '' )
124+ }
125+ const yamlProcessor = function ( result ) {
126+ yamlObject = result
127+ if ( cmdOPS == 'CREATE' ) {
128+ if ( ! optCMD ) {
129+ index = readlineSync . keyInSelect ( yamlObject . stages , `Select a stage to execute ?` , {
130+ cancel : `${ CBRIGHT } None${ CRESET } - (Escape)`
131+ } )
132+ optCMD = yamlObject . stages [ index ]
133+ } else {
134+ index = yamlObject . stages . indexOf ( optCMD )
135+ }
136+ let dockerfileContent = [ 'FROM scratch' ]
137+ if ( index >= 0 ) {
138+ const executedStage = yamlObject . stages [ index ]
139+ let dockerComposeContent = { version : '3.8' , services : { } , volumes : { } }
140+ dockerComposeContent . volumes [ `${ getVolumeName ( projectName ) } ` ] = { external : true }
141+ let stageExecutionChains = [ ]
142+ let dockerCacheVolumes = [ ]
143+ let dockerBaseContent = [ `FROM ${ yamlObject . image } ` , 'WORKDIR /source' , 'VOLUME /data' , 'COPY . /source' , 'CMD ls -la /source' ]
144+ let dockerBasePath = `${ projectName } /Dockerfile`
145+ const baseImage = `base-${ yamlObject . image . split ( ':' ) [ 0 ] } `
146+ const baseDirName = path . dirname ( path . resolve ( dockerBasePath ) )
147+ if ( ! fs . existsSync ( baseDirName ) ) {
148+ fs . mkdirSync ( baseDirName , { recursive : true } )
133149 }
134- let dockerfileContent = [ 'FROM scratch' ]
135- if ( index >= 0 ) {
136- const executedStage = yamlObject . stages [ index ]
137- let dockerComposeContent = { version : '3.8' , services : { } , volumes : { } }
138- dockerComposeContent . volumes [ `shared` ] = {
139- "driver" : "local" ,
140- "driver_opts" : {
141- "type" : "none" ,
142- "device" : "$PWD" ,
143- "o" : "bind"
144- }
145- }
146- let stageExecutionChains = [ ]
147- let dockerCacheVolumes = [ ]
148- let dockerBaseContent = [ `FROM ${ yamlObject . image } ` , 'WORKDIR /source' , 'VOLUME /source' , 'COPY . /source' ]
149- let dockerBasePath = `${ projectName } /Dockerfile`
150- const baseImage = `base-${ yamlObject . image . split ( ':' ) [ 0 ] } `
151- const baseDirName = path . dirname ( path . resolve ( dockerBasePath ) )
152- if ( ! fs . existsSync ( baseDirName ) ) {
153- fs . mkdirSync ( baseDirName , { recursive : true } )
154- }
155- if ( yamlObject . cache && yamlObject . cache . paths && yamlObject . cache . paths . length ) {
156- dockerCacheVolumes . push ( )
157- }
158- fs . writeFileSync ( dockerBasePath , dockerBaseContent . join ( '\n' ) )
159- dockerComposeContent . services [ baseImage ] = { build : { context : `../` , dockerfile : `${ projectName } /Dockerfile` , args : { } } }
160-
161- const variables = simplify . getContentArgs ( yamlObject . variables , { ...process . env } )
162- Object . keys ( yamlObject ) . map ( ( key , idx ) => {
163- if ( yamlObject [ key ] . stage === executedStage ) {
164- const stageName = `${ idx } -${ executedStage } .${ key } `
165- dockerComposeContent . services [ key ] = { build : { context : `../` , dockerfile : `${ projectName } /${ stageName } .Dockerfile` , args : { } } , volumes : [ `shared:/source` ] }
166- stageExecutionChains . push ( `${ stageName } ` )
167- dockerfileContent = [ `FROM ${ projectName . replace ( / \. / g, '' ) } _${ baseImage } ` , 'WORKDIR /source' ]
168- let dockerCommands = [ ]
169- let dockerBeforeCommands = [ ]
150+ if ( yamlObject . cache && yamlObject . cache . paths && yamlObject . cache . paths . length ) {
151+ dockerCacheVolumes . push ( )
152+ }
153+ fs . writeFileSync ( dockerBasePath , dockerBaseContent . join ( '\n' ) )
154+ dockerComposeContent . services [ baseImage ] = { build : { context : `../` , dockerfile : `${ projectName } /Dockerfile` , args : { } } }
155+ fs . writeFileSync ( `${ projectName } /docker-compose.yml` , YAML . stringify ( dockerComposeContent ) )
170156
171- yamlObject [ key ] . before_script . map ( script => {
172- let scriptContent = script . startsWith ( 'set ' ) ? script : simplify . getContentArgs ( script , { ...process . env } , { ...variables } )
173- if ( scriptContent . startsWith ( 'export ' ) || scriptContent . startsWith ( 'set ' ) ) {
174- let dockerOpts = scriptContent . startsWith ( 'set ' ) ? 'ARG' : 'ENV'
175- scriptContent = scriptContent . replace ( 'export ' , '' ) . replace ( 'set ' , '' )
176- const argKeyValue = scriptContent . split ( '=' )
177- dockerComposeContent . services [ key ] . build . args [ `${ argKeyValue [ 0 ] . trim ( ) } ` ] = `${ argKeyValue [ 1 ] . trim ( ) } `
178- scriptContent = `${ argKeyValue [ 0 ] . trim ( ) } ="${ argKeyValue [ 1 ] . trim ( ) } "`
179- dockerfileContent . push ( `${ dockerOpts } ${ scriptContent } ` )
180- } else {
181- dockerBeforeCommands . push ( `${ scriptContent } ` )
182- }
183- } )
157+ dockerComposeContent . services = { } /** reset docker-compose services section */
158+ delete dockerComposeContent . volumes /** remove docker-compose volumes section */
159+ const variables = simplify . getContentArgs ( yamlObject . variables || { } , { ...process . env } )
160+ Object . keys ( yamlObject ) . map ( ( key , idx ) => {
161+ if ( yamlObject [ key ] . stage === executedStage ) {
162+ const stageName = `${ idx } -${ executedStage } .${ key } `
163+ dockerComposeContent . services [ key ] = { build : { context : `../` , dockerfile : `${ projectName } /${ stageName } .Dockerfile` , args : { } } , volumes : [ `${ getVolumeName ( projectName ) } :/data` ] }
164+ stageExecutionChains . push ( `${ stageName } ` )
165+ dockerfileContent = [ `FROM ${ projectName . replace ( / \. / g, '' ) } _${ baseImage } ` , 'WORKDIR /source' ]
166+ yamlObject [ key ] . dependencies && yamlObject [ key ] . dependencies . map ( deps => {
167+ dockerfileContent . push ( `FROM ${ projectName . replace ( / \. / g, '' ) } _${ deps } ` )
168+ } )
169+ let dockerCommands = [ ]
170+ let dockerBeforeCommands = [ ]
171+ let dockerAfterCommands = [ ]
172+ yamlObject [ key ] . before_script && yamlObject [ key ] . before_script . map ( script => {
173+ let scriptContent = script . startsWith ( 'set ' ) ? script : simplify . getContentArgs ( script , { ...process . env } , { ...variables } )
174+ if ( scriptContent . startsWith ( 'export ' ) || scriptContent . startsWith ( 'set ' ) ) {
175+ let dockerOpts = scriptContent . startsWith ( 'set ' ) ? 'ARG' : 'ENV'
176+ scriptContent = scriptContent . replace ( 'export ' , '' ) . replace ( 'set ' , '' )
177+ const argKeyValue = scriptContent . split ( '=' )
178+ dockerComposeContent . services [ key ] . build . args [ `${ argKeyValue [ 0 ] . trim ( ) } ` ] = `${ argKeyValue [ 1 ] . trim ( ) } `
179+ scriptContent = `${ argKeyValue [ 0 ] . trim ( ) } ="${ argKeyValue [ 1 ] . trim ( ) } "`
180+ dockerfileContent . push ( `${ dockerOpts } ${ scriptContent } ` )
181+ } else {
182+ dockerBeforeCommands . push ( `${ scriptContent } ` )
183+ }
184+ } )
184185
185- yamlObject [ key ] . script . map ( script => {
186- let scriptContent = script . startsWith ( 'set ' ) ? script : simplify . getContentArgs ( script , { ...process . env } , { ...variables } )
187- if ( scriptContent . startsWith ( 'export ' ) || scriptContent . startsWith ( 'set ' ) ) {
188- let dockerOpts = scriptContent . startsWith ( 'set ' ) ? 'ARG' : 'ENV'
189- scriptContent = scriptContent . replace ( 'export ' , '' ) . replace ( 'set ' , '' )
190- const argKeyValue = scriptContent . split ( '=' )
191- dockerComposeContent . services [ key ] . build . args [ `${ argKeyValue [ 0 ] . trim ( ) } ` ] = `${ argKeyValue [ 1 ] . trim ( ) } `
192- scriptContent = `${ argKeyValue [ 0 ] . trim ( ) } ="${ argKeyValue [ 1 ] . trim ( ) } "`
193- dockerfileContent . push ( `${ dockerOpts } ${ scriptContent } ` )
194- } else {
195- dockerCommands . push ( `${ scriptContent } ` )
196- }
197- } )
198- dockerfileContent . push ( `RUN ${ dockerBeforeCommands . join ( ' && ' ) } ` )
199- dockerfileContent . push ( `RUN ${ dockerCommands . join ( ' && ' ) } ` )
200- let dockerfilePath = `${ projectName } /${ stageName } .Dockerfile`
201- const pathDirName = path . dirname ( path . resolve ( dockerfilePath ) )
202- if ( ! fs . existsSync ( pathDirName ) ) {
203- fs . mkdirSync ( pathDirName , { recursive : true } )
186+ yamlObject [ key ] . script && yamlObject [ key ] . script . map ( script => {
187+ let scriptContent = script . startsWith ( 'set ' ) ? script : simplify . getContentArgs ( script , { ...process . env } , { ...variables } )
188+ if ( scriptContent . startsWith ( 'export ' ) || scriptContent . startsWith ( 'set ' ) ) {
189+ let dockerOpts = scriptContent . startsWith ( 'set ' ) ? 'ARG' : 'ENV'
190+ scriptContent = scriptContent . replace ( 'export ' , '' ) . replace ( 'set ' , '' )
191+ const argKeyValue = scriptContent . split ( '=' )
192+ dockerComposeContent . services [ key ] . build . args [ `${ argKeyValue [ 0 ] . trim ( ) } ` ] = `${ argKeyValue [ 1 ] . trim ( ) } `
193+ scriptContent = `${ argKeyValue [ 0 ] . trim ( ) } ="${ argKeyValue [ 1 ] . trim ( ) } "`
194+ dockerfileContent . push ( `${ dockerOpts } ${ scriptContent } ` )
195+ } else {
196+ dockerCommands . push ( `${ scriptContent } ` )
204197 }
205- fs . writeFileSync ( dockerfilePath , dockerfileContent . join ( '\n' ) )
206- }
207- } )
208- let dockerComposePath = `${ projectName } /docker-compose.${ executedStage } .yml`
209- fs . writeFileSync ( dockerComposePath , YAML . stringify ( dockerComposeContent ) )
210- console . log ( `Created ${ projectName } docker-compose for stage '${ optCMD } ' cached to '${ projectName } ' volume` )
211- fs . writeFileSync ( `pipeline.sh` , [
212- '#!/bin/bash' ,
213- `cd ${ projectName } ` ,
214- `docker volume rm ${ projectName . replace ( / \. / g, '' ) } _shared > /dev/null` ,
215- `docker-compose -f docker-compose.$1.yml --project-name ${ projectName } up --force-recreate`
216- ] . join ( '\n' ) )
217- }
218- } else if ( cmdOPS == 'LIST' ) {
219- if ( ! optCMD ) {
220- yamlObject . stages . map ( ( cmd , idx ) => {
221- console . log ( `\t- ${ CPROMPT } ${ cmd . toLowerCase ( ) } ${ CRESET } ` )
222- } )
223- } else {
224- Object . keys ( yamlObject ) . map ( ( key , idx ) => {
225- if ( yamlObject [ key ] . stage === optCMD ) {
226- const stageName = `[${ optCMD } ] ${ key } `
227- console . log ( `\t- ${ CPROMPT } ${ stageName . toLowerCase ( ) } ${ CRESET } ` )
198+ } )
199+ yamlObject [ key ] . after_script && yamlObject [ key ] . after_script . map ( script => {
200+ let scriptContent = script . startsWith ( 'set ' ) ? script : simplify . getContentArgs ( script , { ...process . env } , { ...variables } )
201+ if ( scriptContent . startsWith ( 'export ' ) || scriptContent . startsWith ( 'set ' ) ) {
202+ let dockerOpts = scriptContent . startsWith ( 'set ' ) ? 'ARG' : 'ENV'
203+ scriptContent = scriptContent . replace ( 'export ' , '' ) . replace ( 'set ' , '' )
204+ const argKeyValue = scriptContent . split ( '=' )
205+ dockerComposeContent . services [ key ] . build . args [ `${ argKeyValue [ 0 ] . trim ( ) } ` ] = `${ argKeyValue [ 1 ] . trim ( ) } `
206+ scriptContent = `${ argKeyValue [ 0 ] . trim ( ) } ="${ argKeyValue [ 1 ] . trim ( ) } "`
207+ dockerfileContent . push ( `${ dockerOpts } ${ scriptContent } ` )
208+ } else {
209+ dockerAfterCommands . push ( `${ scriptContent } ` )
210+ }
211+ } )
212+
213+ dockerBeforeCommands . length && dockerfileContent . push ( `RUN ${ dockerBeforeCommands . join ( ' && ' ) } ` )
214+ dockerCommands . length && dockerfileContent . push ( `RUN ${ dockerCommands . join ( ' && ' ) } ` )
215+ dockerAfterCommands . length && dockerfileContent . push ( `RUN ${ dockerAfterCommands . join ( ' && ' ) } ` )
216+ let dockerfilePath = `${ projectName } /${ stageName } .Dockerfile`
217+ const pathDirName = path . dirname ( path . resolve ( dockerfilePath ) )
218+ if ( ! fs . existsSync ( pathDirName ) ) {
219+ fs . mkdirSync ( pathDirName , { recursive : true } )
228220 }
229- } )
230- }
221+ fs . writeFileSync ( dockerfilePath , dockerfileContent . join ( '\n' ) )
222+ }
223+ } )
224+ let dockerComposePath = `${ projectName } /docker-compose.${ executedStage } .yml`
225+ fs . writeFileSync ( dockerComposePath , YAML . stringify ( dockerComposeContent ) )
226+ console . log ( `Created ${ projectName } docker-compose for stage '${ optCMD } ' cached to '${ projectName } ' volume` )
227+ fs . writeFileSync ( `pipeline.sh` , [
228+ '#!/bin/bash' ,
229+ `cd ${ projectName } ` ,
230+ `DOCKER_VOLUME=$(docker volume ls | grep -w "${ getVolumeName ( projectName ) } ")` ,
231+ 'if [ -z "${DOCKER_VOLUME}" ]; then' ,
232+ ` echo "Creating new volume: ${ getVolumeName ( projectName ) } "` ,
233+ ` docker volume create --driver local --opt type=none --opt device=$PWD --opt o=bind ${ getVolumeName ( projectName ) } ;` ,
234+ `fi` ,
235+ `if [ $? -eq 0 ]; then` ,
236+ ` if [ -z "$1" ]; then echo "Missing argument: require stage argument to run - ex bash pipeline.sh build";` ,
237+ ` else docker-compose -f docker-compose.yml -f docker-compose.$1.yml --project-name ${ projectName } build; fi` ,
238+ `fi`
239+ ] . join ( '\n' ) )
240+ }
241+ } else if ( cmdOPS == 'LIST' ) {
242+ if ( ! optCMD ) {
243+ yamlObject . stages . map ( ( cmd , idx ) => {
244+ console . log ( `\t- ${ CPROMPT } ${ cmd . toLowerCase ( ) } ${ CRESET } ` )
245+ } )
231246 } else {
232- yargs . showHelp ( )
233- console . log ( `\n` , ` * ${ CBRIGHT } Supported command list${ CRESET } :` , '\n' )
234- OPT_COMMANDS . map ( ( cmd , idx ) => {
235- console . log ( `\t- ${ CPROMPT } ${ cmd . name . toLowerCase ( ) } ${ CRESET } : ${ cmd . desc } ` )
247+ Object . keys ( yamlObject ) . map ( ( key , idx ) => {
248+ if ( yamlObject [ key ] . stage === optCMD ) {
249+ const stageName = `[${ optCMD } ] ${ key } `
250+ console . log ( `\t- ${ CPROMPT } ${ stageName . toLowerCase ( ) } ${ CRESET } ` )
251+ }
236252 } )
237- console . log ( `\n` )
238- process . exit ( 0 )
239253 }
240- } )
254+ } else {
255+ yargs . showHelp ( )
256+ console . log ( `\n` , ` * ${ CBRIGHT } Supported command list${ CRESET } :` , '\n' )
257+ OPT_COMMANDS . map ( ( cmd , idx ) => {
258+ console . log ( `\t- ${ CPROMPT } ${ cmd . name . toLowerCase ( ) } ${ CRESET } : ${ cmd . desc } ` )
259+ } )
260+ console . log ( `\n` )
261+ process . exit ( 0 )
262+ }
241263}
264+ if ( yamlObject . include ) {
265+ parseIncludes ( yamlObject ) . then ( result => {
266+ yamlProcessor ( result )
267+ } )
268+ } else {
269+ yamlProcessor ( yamlObject )
270+ }
0 commit comments