1414 * limitations under the License.
1515 */
1616
17+ import crypto from 'crypto' ;
1718import fs from 'fs' ;
1819import os from 'os' ;
1920import path from 'path' ;
@@ -29,6 +30,7 @@ import {Context} from '../context';
2930import { Exec } from '../exec' ;
3031import { Docker } from '../docker/docker' ;
3132import { Git } from '../git' ;
33+ import { Util } from '../util' ;
3234
3335import { GitHubRelease } from '../types/github' ;
3436
@@ -50,23 +52,25 @@ export class Install {
5052 */
5153 public async download ( version : string ) : Promise < string > {
5254 const release : GitHubRelease = await Install . getRelease ( version ) ;
53- const fversion = release . tag_name . replace ( / ^ v + | v + $ / g, '' ) ;
54- core . debug ( `Install.download version: ${ fversion } ` ) ;
55+ core . debug ( `Install.download release tag name: ${ release . tag_name } ` ) ;
5556
56- const c = semver . clean ( fversion ) || '' ;
57+ const vspec = await this . vspec ( release . tag_name ) ;
58+ core . debug ( `Install.download vspec: ${ vspec } ` ) ;
59+
60+ const c = semver . clean ( vspec ) || '' ;
5761 if ( ! semver . valid ( c ) ) {
58- throw new Error ( `Invalid Buildx version "${ fversion } ".` ) ;
62+ throw new Error ( `Invalid Buildx version "${ vspec } ".` ) ;
5963 }
6064
61- const installCache = new InstallCache ( 'buildx-dl-bin' , fversion ) ;
65+ const installCache = new InstallCache ( 'buildx-dl-bin' , vspec ) ;
6266
6367 const cacheFoundPath = await installCache . find ( ) ;
6468 if ( cacheFoundPath ) {
6569 core . info ( `Buildx binary found in ${ cacheFoundPath } ` ) ;
6670 return cacheFoundPath ;
6771 }
6872
69- const downloadURL = util . format ( 'https://github.com/docker/buildx/releases/download/v%s/%s' , fversion , this . filename ( fversion ) ) ;
73+ const downloadURL = util . format ( 'https://github.com/docker/buildx/releases/download/v%s/%s' , vspec , this . filename ( vspec ) ) ;
7074 core . info ( `Downloading ${ downloadURL } ` ) ;
7175
7276 const htcDownloadPath = await tc . downloadTool ( downloadURL ) ;
@@ -83,20 +87,8 @@ export class Install {
8387 * @returns path to the buildx binary
8488 */
8589 public async build ( gitContext : string ) : Promise < string > {
86- // eslint-disable-next-line prefer-const
87- let [ repo , ref ] = gitContext . split ( '#' ) ;
88- if ( ref . length == 0 ) {
89- ref = 'master' ;
90- }
91-
92- let vspec : string ;
93- // TODO: include full ref as fingerprint. Use commit sha as best-effort in the meantime.
94- if ( ref . match ( / ^ [ 0 - 9 a - f A - F ] { 40 } $ / ) ) {
95- vspec = ref ;
96- } else {
97- vspec = await Git . remoteSha ( repo , ref , process . env . GIT_AUTH_TOKEN ) ;
98- }
99- core . debug ( `Install.build: tool version spec ${ vspec } ` ) ;
90+ const vspec = await this . vspec ( gitContext ) ;
91+ core . debug ( `Install.build vspec: ${ vspec } ` ) ;
10092
10193 const installCache = new InstallCache ( 'buildx-build-bin' , vspec ) ;
10294
@@ -228,6 +220,39 @@ export class Install {
228220 return util . format ( 'buildx-v%s.%s-%s%s' , version , platform , arch , ext ) ;
229221 }
230222
223+ /*
224+ * Get version spec (fingerprint) for cache key. If versionOrRef is a valid
225+ * Git context, then return the SHA of the ref along the repo and owner and
226+ * create a hash of it. Otherwise, return the versionOrRef (semver) as is
227+ * without the 'v' prefix.
228+ */
229+ private async vspec ( versionOrRef : string ) : Promise < string > {
230+ if ( ! Util . isValidRef ( versionOrRef ) ) {
231+ const v = versionOrRef . replace ( / ^ v + | v + $ / g, '' ) ;
232+ core . info ( `Use ${ v } version spec cache key for ${ versionOrRef } ` ) ;
233+ return v ;
234+ }
235+
236+ // eslint-disable-next-line prefer-const
237+ let [ baseURL , ref ] = versionOrRef . split ( '#' ) ;
238+ if ( ref . length == 0 ) {
239+ ref = 'master' ;
240+ }
241+
242+ let sha : string ;
243+ if ( ref . match ( / ^ [ 0 - 9 a - f A - F ] { 40 } $ / ) ) {
244+ sha = ref ;
245+ } else {
246+ sha = await Git . remoteSha ( baseURL , ref , process . env . GIT_AUTH_TOKEN ) ;
247+ }
248+
249+ const [ owner , repo ] = baseURL . substring ( 'https://github.com/' . length ) . split ( '/' ) ;
250+ const key = `${ owner } /${ Util . trimSuffix ( repo , '.git' ) } /${ sha } ` ;
251+ const hash = crypto . createHash ( 'sha256' ) . update ( key ) . digest ( 'hex' ) ;
252+ core . info ( `Use ${ hash } version spec cache key for ${ key } ` ) ;
253+ return hash ;
254+ }
255+
231256 public static async getRelease ( version : string ) : Promise < GitHubRelease > {
232257 const url = `https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json` ;
233258 const http : httpm . HttpClient = new httpm . HttpClient ( 'docker-actions-toolkit' ) ;
0 commit comments