@ -1,18 +1,14 @@
import * as crypto from 'crypto' ;
import * as fs from 'fs' ;
import * as yaml from 'js-yaml' ;
import * as core from '@actions/core' ;
import * as exec from '@actions/exec' ;
import * as actionsToolkit from '@docker/actions-toolkit' ;
import { Buildx } from '@docker/actions-toolkit/lib/buildx/buildx' ;
import { Builder } from '@docker/actions-toolkit/lib/buildx/builder' ;
import { Docker } from '@docker/actions-toolkit/lib/docker/docker' ;
import { Exec } from '@docker/actions-toolkit/lib/exec' ;
import { Toolkit } from '@docker/actions-toolkit/lib/toolkit' ;
import { Util } from '@docker/actions-toolkit/lib/util' ;
import { Node } from '@docker/actions-toolkit/lib/types/buildx/builder' ;
import { ContextInfo } from '@docker/actions-toolkit/lib/types/docker/docker' ;
import { Node } from '@docker/actions-toolkit/lib/types/builder' ;
import * as context from './context' ;
import * as stateHelper from './state-helper' ;
@ -22,18 +18,11 @@ actionsToolkit.run(
async ( ) = > {
const inputs : context.Inputs = await context . getInputs ( ) ;
stateHelper . setCleanup ( inputs . cleanup ) ;
const version = context . getVersion ( inputs ) ;
const toolkit = new Toolkit ( ) ;
const standalone = await toolkit . buildx . isStandalone ( ) ;
stateHelper . setStandalone ( standalone ) ;
if ( inputs . keepState && inputs . driver !== 'docker-container' ) {
// https://docs.docker.com/reference/cli/docker/buildx/rm/#keep-state
throw new Error ( ` Cannot use keep-state with ${ inputs . driver } driver ` ) ;
}
stateHelper . setKeepState ( inputs . keepState ) ;
await core . group ( ` Docker info ` , async ( ) = > {
try {
await Docker . printVersion ( ) ;
@ -44,16 +33,16 @@ actionsToolkit.run(
} ) ;
let toolPath ;
if ( Util . isValidRef ( version) ) {
if ( Util . isValidRef ( inputs. version) ) {
if ( standalone ) {
throw new Error ( ` Cannot build from source without the Docker CLI ` ) ;
}
await core . group ( ` Build buildx from source ` , async ( ) = > {
toolPath = await toolkit . buildxInstall . build ( version, ! inputs . cacheBinary ) ;
toolPath = await toolkit . buildxInstall . build ( inputs. version, ! inputs . cacheBinary ) ;
} ) ;
} else if ( ! ( await toolkit . buildx . isAvailable ( ) ) || version) {
} else if ( ! ( await toolkit . buildx . isAvailable ( ) ) || inputs. version) {
await core . group ( ` Download buildx from GitHub Releases ` , async ( ) = > {
toolPath = await toolkit . buildxInstall . download ( version || 'latest' , ! inputs . cacheBinary ) ;
toolPath = await toolkit . buildxInstall . download ( inputs. version || 'latest' , ! inputs . cacheBinary ) ;
} ) ;
}
if ( toolPath ) {
@ -77,56 +66,8 @@ actionsToolkit.run(
fs . mkdirSync ( Buildx . certsDir , { recursive : true } ) ;
stateHelper . setCertsDir ( Buildx . certsDir ) ;
// if the default context has TLS data loaded and endpoint is not set, then
// we create a temporary docker context only if driver is docker-container
// https://github.com/docker/buildx/blob/b96ad59f64d40873e4959336d294b648bb3937fe/builder/builder.go#L489
// https://github.com/docker/setup-buildx-action/issues/105
if ( ! standalone && inputs . driver == 'docker-container' && ( await Docker . context ( ) ) == 'default' && inputs . endpoint . length == 0 ) {
let defaultContextWithTLS : boolean = false ;
await core . group ( ` Inspecting default docker context ` , async ( ) = > {
await Docker . getExecOutput ( [ 'context' , 'inspect' , '--format=json' , 'default' ] , {
ignoreReturnCode : true ,
silent : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
core . info ( ` Cannot inspect default docker context: ${ res . stderr . trim ( ) } ` ) ;
} else {
try {
const contextInfo = ( < Array < ContextInfo > > JSON . parse ( res . stdout . trim ( ) ) ) [ 0 ] ;
core . info ( JSON . stringify ( JSON . parse ( res . stdout . trim ( ) ) , undefined , 2 ) ) ;
const hasTLSData = Object . keys ( contextInfo . Endpoints ) . length > 0 && Object . values ( contextInfo . Endpoints ) [ 0 ] . TLSData !== undefined ;
const hasTLSMaterial = Object . keys ( contextInfo . TLSMaterial ) . length > 0 && Object . values ( contextInfo . TLSMaterial ) [ 0 ] . length > 0 ;
defaultContextWithTLS = hasTLSData || hasTLSMaterial ;
} catch ( e ) {
core . info ( ` Unable to parse default docker context info: ${ e } ` ) ;
core . info ( res . stdout . trim ( ) ) ;
}
}
} ) ;
} ) ;
if ( defaultContextWithTLS ) {
const tmpDockerContext = ` buildx- ${ crypto . randomUUID ( ) } ` ;
await core . group ( ` Creating temp docker context (TLS data loaded in default one) ` , async ( ) = > {
await Docker . getExecOutput ( [ 'context' , 'create' , tmpDockerContext ] , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
core . warning ( ` Cannot create docker context ${ tmpDockerContext } : ${ res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' } ` ) ;
} else {
core . info ( ` Setting builder endpoint to ${ tmpDockerContext } context ` ) ;
inputs . endpoint = tmpDockerContext ;
stateHelper . setTmpDockerContext ( tmpDockerContext ) ;
}
} ) ;
} ) ;
}
}
if ( inputs . driver !== 'docker' ) {
await core . group ( ` Creating a new builder instance ` , async ( ) = > {
if ( await toolkit . builder . exists ( inputs . name ) ) {
core . info ( ` Builder ${ inputs . name } already exists, skipping creation ` ) ;
} else {
const certsDriverOpts = Buildx . resolveCertsDriverOpts ( inputs . driver , inputs . endpoint , {
cacert : process.env [ ` ${ context . builderNodeEnvPrefix } _0_AUTH_TLS_CACERT ` ] ,
cert : process.env [ ` ${ context . builderNodeEnvPrefix } _0_AUTH_TLS_CERT ` ] ,
@ -136,14 +77,7 @@ actionsToolkit.run(
inputs . driverOpts = [ . . . inputs . driverOpts , . . . certsDriverOpts ] ;
}
const createCmd = await toolkit . buildx . getCommand ( await context . getCreateArgs ( inputs , toolkit ) ) ;
await Exec . getExecOutput ( createCmd . command , createCmd . args , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
throw new Error ( res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' ) ;
}
} ) ;
}
await exec . exec ( createCmd . command , createCmd . args ) ;
} ) ;
}
@ -161,13 +95,7 @@ actionsToolkit.run(
node [ 'driver-opts' ] = [ . . . ( node [ 'driver-opts' ] || [ ] ) , . . . certsDriverOpts ] ;
}
const appendCmd = await toolkit . buildx . getCommand ( await context . getAppendArgs ( inputs , node , toolkit ) ) ;
await Exec . getExecOutput ( appendCmd . command , appendCmd . args , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
throw new Error ( ` Failed to append node ${ node . name } : ${ res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' } ` ) ;
}
} ) ;
await exec . exec ( appendCmd . command , appendCmd . args ) ;
nodeIndex ++ ;
}
} ) ;
@ -175,13 +103,7 @@ actionsToolkit.run(
await core . group ( ` Booting builder ` , async ( ) = > {
const inspectCmd = await toolkit . buildx . getCommand ( await context . getInspectArgs ( inputs , toolkit ) ) ;
await Exec . getExecOutput ( inspectCmd . command , inspectCmd . args , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
throw new Error ( res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' ) ;
}
} ) ;
await exec . exec ( inspectCmd . command , inspectCmd . args ) ;
} ) ;
if ( inputs . install ) {
@ -189,15 +111,8 @@ actionsToolkit.run(
throw new Error ( ` Cannot set buildx as default builder without the Docker CLI ` ) ;
}
await core . group ( ` Setting buildx as default builder ` , async ( ) = > {
stateHelper . setBuildxIsDefaultBuilder ( true ) ;
const installCmd = await toolkit . buildx . getCommand ( [ 'install' ] ) ;
await Exec . getExecOutput ( installCmd . command , installCmd . args , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
throw new Error ( res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' ) ;
}
} ) ;
await exec . exec ( installCmd . command , installCmd . args ) ;
} ) ;
}
@ -240,11 +155,13 @@ actionsToolkit.run(
async ( ) = > {
if ( stateHelper . IsDebug && stateHelper . containerName . length > 0 ) {
await core . group ( ` BuildKit container logs ` , async ( ) = > {
await Docker . getExecOutput ( [ 'logs' , ` ${ stateHelper . containerName } ` ] , {
await exec
. getExecOutput ( 'docker' , [ 'logs' , ` ${ stateHelper . containerName } ` ] , {
ignoreReturnCode : true
} ) . then ( res = > {
} )
. then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
core . warning ( res . stderr . match( /(.*)\s*$/ ) ? . [ 0 ] ? . trim( ) ? ? 'unknown error' ) ;
core . warning ( res . stderr . trim( ) ) ;
}
} ) ;
} ) ;
@ -259,12 +176,14 @@ actionsToolkit.run(
const buildx = new Buildx ( { standalone : stateHelper.standalone } ) ;
const builder = new Builder ( { buildx : buildx } ) ;
if ( await builder . exists ( stateHelper . builderName ) ) {
const rmCmd = await buildx . getCommand ( [ 'rm' , stateHelper . builderName , . . . ( stateHelper . keepState ? [ '--keep-state' ] : [ ] ) ] ) ;
await Exec . getExecOutput ( rmCmd . command , rmCmd . args , {
const rmCmd = await buildx . getCommand ( [ 'rm' , stateHelper . builderName ] ) ;
await exec
. getExecOutput ( rmCmd . command , rmCmd . args , {
ignoreReturnCode : true
} ) . then ( res = > {
} )
. then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
core . warning ( res . stderr . match( /(.*)\s*$/ ) ? . [ 0 ] ? . trim( ) ? ? 'unknown error' ) ;
core . warning ( res . stderr . trim( ) ) ;
}
} ) ;
} else {
@ -273,34 +192,10 @@ actionsToolkit.run(
} ) ;
}
if ( stateHelper . tmpDockerContext ) {
await core . group ( ` Removing temp docker context ` , async ( ) = > {
await Exec . getExecOutput ( 'docker' , [ 'context' , 'rm' , '-f' , stateHelper . tmpDockerContext ] , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
core . warning ( ` ${ res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' } ` ) ;
}
} ) ;
} ) ;
}
if ( stateHelper . certsDir . length > 0 && fs . existsSync ( stateHelper . certsDir ) ) {
await core . group ( ` Cleaning up certificates ` , async ( ) = > {
fs . rmSync ( stateHelper . certsDir , { recursive : true } ) ;
} ) ;
}
if ( stateHelper . buildxIsDefaultBuilder ) {
await core . group ( ` Restoring default builder ` , async ( ) = > {
await Exec . getExecOutput ( 'docker' , [ 'buildx' , 'uninstall' ] , {
ignoreReturnCode : true
} ) . then ( res = > {
if ( res . stderr . length > 0 && res . exitCode != 0 ) {
core . warning ( ` ${ res . stderr . match ( /(.*)\s*$/ ) ? . [ 0 ] ? . trim ( ) ? ? 'unknown error' } ` ) ;
}
} ) ;
} ) ;
}
}
) ;