Skip to content

Commit c1edd0b

Browse files
committed
buildx: improve vspec fingerprint for caching
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
1 parent 70c0e12 commit c1edd0b

File tree

1 file changed

+45
-20
lines changed

1 file changed

+45
-20
lines changed

‎src/buildx/install.ts‎

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import crypto from 'crypto';
1718
import fs from 'fs';
1819
import os from 'os';
1920
import path from 'path';
@@ -29,6 +30,7 @@ import {Context} from '../context';
2930
import {Exec} from '../exec';
3031
import {Docker} from '../docker/docker';
3132
import {Git} from '../git';
33+
import {Util} from '../util';
3234

3335
import {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-9a-fA-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-9a-fA-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

Comments
 (0)