Allow to download staging releases of buildx

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2021-06-30 19:54:54 +02:00
parent a1c666d855
commit 3b5c478cc4
No known key found for this signature in database
GPG key ID: 3248E46B6BB8C7F7
10 changed files with 8527 additions and 40 deletions

View file

@ -72,15 +72,15 @@ describe('inspect', () => {
);
});
describe('install', () => {
describe('downloadRelease', () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
it('acquires v0.4.1 version of buildx', async () => {
const buildxBin = await buildx.install('v0.4.1', tmpDir);
const buildxBin = await buildx.downloadRelease('v0.4.1', tmpDir);
console.log(buildxBin);
expect(fs.existsSync(buildxBin)).toBe(true);
}, 100000);
it('acquires latest version of buildx', async () => {
const buildxBin = await buildx.install('latest', tmpDir);
const buildxBin = await buildx.downloadRelease('latest', tmpDir);
console.log(buildxBin);
expect(fs.existsSync(buildxBin)).toBe(true);
}, 100000);

View file

@ -1,6 +1,16 @@
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import * as context from '../src/context';
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
const tmpDir = path.join('/tmp/.docker-setup-buildx-jest').split(path.sep).join(path.posix.sep);
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
describe('getInputList', () => {
it('handles single line correctly', async () => {
await setInput('foo', 'bar');

View file

@ -35,6 +35,10 @@ inputs:
config:
description: 'BuildKit config file'
required: false
github-token:
description: 'GitHub Token as provided by secrets'
default: ${{ github.token }}
required: true
outputs:
name:

8276
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

View file

@ -29,6 +29,7 @@
"dependencies": {
"@actions/core": "^1.4.0",
"@actions/exec": "^1.1.0",
"@actions/github": "^5.0.0",
"@actions/http-client": "^1.0.11",
"@actions/tool-cache": "^1.7.1",
"semver": "^7.3.5",

View file

@ -106,7 +106,29 @@ export async function inspect(name: string): Promise<Builder> {
});
}
export async function install(inputVersion: string, dockerConfigHome: string): Promise<string> {
export async function downloadArtifact(
inputVersion: string,
inputToken: string,
dockerConfigHome: string
): Promise<string> {
const [type, value] = inputVersion.split('-');
let runID: number;
if (type == 'pr') {
runID = await github.getPullRunID(parseInt(value), inputToken);
} else {
runID = parseInt(value);
}
let toolPath: string;
toolPath = tc.find('buildx', runID.toString());
if (!toolPath) {
toolPath = await github.downloadArtifact(runID, inputToken);
}
return installPlugin(toolPath, dockerConfigHome);
}
export async function downloadRelease(inputVersion: string, dockerConfigHome: string): Promise<string> {
const release: github.GitHubRelease | null = await github.getRelease(inputVersion);
if (!release) {
throw new Error(`Cannot find buildx ${inputVersion} release`);
@ -124,6 +146,10 @@ export async function install(inputVersion: string, dockerConfigHome: string): P
toolPath = await download(version);
}
return installPlugin(toolPath, dockerConfigHome);
}
async function installPlugin(toolPath: string, dockerConfigHome: string): Promise<string> {
const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins');
core.debug(`Plugins dir is ${pluginsDir}`);
if (!fs.existsSync(pluginsDir)) {
@ -146,7 +172,7 @@ async function download(version: string): Promise<string> {
const downloadUrl = util.format(
'https://github.com/docker/buildx/releases/download/v%s/%s',
version,
await filename(version)
filename(version)
);
let downloadPath: string;
@ -161,7 +187,7 @@ async function download(version: string): Promise<string> {
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version);
}
async function filename(version: string): Promise<string> {
export function filename(version: string): string {
let arch: string;
switch (context.osArch) {
case 'x64': {

View file

@ -1,7 +1,10 @@
import * as os from 'os';
import * as core from '@actions/core';
import {issueCommand} from '@actions/core/lib/command';
import fs from 'fs';
import path from 'path';
let _tmpDir: string;
export const osPlat: string = os.platform();
export const osArch: string = os.arch();
@ -14,6 +17,14 @@ export interface Inputs {
use: boolean;
endpoint: string;
config: string;
githubToken: string;
}
export function tmpDir(): string {
if (!_tmpDir) {
_tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep);
}
return _tmpDir;
}
export async function getInputs(): Promise<Inputs> {
@ -27,7 +38,8 @@ export async function getInputs(): Promise<Inputs> {
install: core.getBooleanInput('install'),
use: core.getBooleanInput('use'),
endpoint: core.getInput('endpoint'),
config: core.getInput('config')
config: core.getInput('config'),
githubToken: core.getInput('github-token')
};
}

View file

@ -1,12 +1,109 @@
import * as fs from 'fs';
import * as glob from 'glob';
import * as path from 'path';
import * as buildx from './buildx';
import * as context from './context';
import * as github from '@actions/github';
import * as httpm from '@actions/http-client';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
export interface GitHubRelease {
id: number;
tag_name: string;
}
const buildxRepo = {owner: 'docker', repo: 'buildx'};
const buildxWorkflow = 'build.yml';
const buildxArtifactName = 'buildx';
export const getRelease = async (version: string): Promise<GitHubRelease | null> => {
const url: string = `https://github.com/docker/buildx/releases/${version}`;
const http: httpm.HttpClient = new httpm.HttpClient('setup-buildx');
return (await http.getJson<GitHubRelease>(url)).result;
};
export const getPullRunID = async (prNumber: number, token: string): Promise<number> => {
const octokit = github.getOctokit(token);
return octokit.rest.pulls
.get({
...buildxRepo,
pull_number: prNumber
})
.then(response => {
return octokit
.paginate(octokit.rest.actions.listWorkflowRuns, {
...buildxRepo,
workflow_id: buildxWorkflow,
status: 'completed'
})
.then(runs => {
return runs.filter(run => run.head_sha === response.data.head.sha)[0].run_number;
})
.catch(error => {
throw new Error(
`Cannot find a completed workflow run for https://github.com/${buildxRepo.owner}/${buildxRepo.repo}/pull/${prNumber}: ${error.message}`
);
});
});
};
export const downloadArtifact = async (runID: number, token: string): Promise<string> => {
const octokit = github.getOctokit(token);
return octokit
.paginate(octokit.rest.actions.listWorkflowRunArtifacts, {
...buildxRepo,
run_id: runID
})
.then(artifacts => {
const artifact = artifacts.find(artifact => artifact.name == buildxArtifactName);
if (!artifact) {
throw new Error(
`Cannot find ${buildxArtifactName} artifact in https://github.com/${buildxRepo.owner}/${buildxRepo.repo}/actions/runs/${runID} workflow`
);
}
core.info(
`Downloading ${artifact.id} artifact in https://github.com/${buildxRepo.owner}/${buildxRepo.repo}/actions/runs/${runID} workflow`
);
return octokit.rest.actions
.downloadArtifact({
...buildxRepo,
artifact_id: artifact.id,
archive_format: 'zip'
})
.then(downloadArtifact => {
const archivePath = path.join(context.tmpDir(), 'buildx.zip').split(path.sep).join(path.posix.sep);
fs.writeFileSync(archivePath, Buffer.from(downloadArtifact.data as ArrayBuffer), 'binary');
core.info(`Extracting ${archivePath}`);
return tc.extractZip(archivePath).then(extPath => {
const binSuffixName = buildx.filename(runID.toString()).split(',').pop();
return glob(
`*${binSuffixName}`,
{
root: extPath,
absolute: true
},
(err, binFiles) => {
if (err) {
throw new Error(`Cannot find buildx binary *${binSuffixName}: ${err}`);
}
return tc.cacheFile(
binFiles[0],
context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx',
'buildx',
runID.toString()
);
}
);
});
})
.catch(error => {
throw new Error(`Cannot download ${artifact.id} artifact: ${error.message}`);
});
})
.catch(error => {
throw new Error(
`Cannot find ${buildxArtifactName} artifact in https://github.com/${buildxRepo.owner}/${buildxRepo.repo}/actions/runs/${runID} workflow: ${error.message}`
);
});
};

View file

@ -19,7 +19,11 @@ async function run(): Promise<void> {
if (!(await buildx.isAvailable()) || inputs.version) {
core.startGroup(`Installing buildx`);
await buildx.install(inputs.version || 'latest', dockerConfigHome);
if (inputs.version.startsWith('pr-') || inputs.version.startsWith('runid-')) {
await buildx.downloadArtifact(inputs.version, inputs.githubToken, dockerConfigHome);
} else {
await buildx.downloadRelease(inputs.version || 'latest', dockerConfigHome);
}
core.endGroup();
}

121
yarn.lock
View file

@ -14,6 +14,16 @@
dependencies:
"@actions/io" "^1.0.1"
"@actions/github@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@actions/github/-/github-5.0.0.tgz#1754127976c50bd88b2e905f10d204d76d1472f8"
integrity sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==
dependencies:
"@actions/http-client" "^1.0.11"
"@octokit/core" "^3.4.0"
"@octokit/plugin-paginate-rest" "^2.13.3"
"@octokit/plugin-rest-endpoint-methods" "^5.1.1"
"@actions/http-client@^1.0.11", "@actions/http-client@^1.0.8":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.11.tgz#c58b12e9aa8b159ee39e7dd6cbd0e91d905633c0"
@ -526,6 +536,92 @@
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@octokit/auth-token@^2.4.4":
version "2.4.5"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
dependencies:
"@octokit/types" "^6.0.3"
"@octokit/core@^3.4.0":
version "3.5.1"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b"
integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.6.0"
"@octokit/request-error" "^2.0.5"
"@octokit/types" "^6.0.3"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^6.0.1":
version "6.0.12"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"
integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==
dependencies:
"@octokit/types" "^6.0.3"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^4.5.8":
version "4.6.4"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.4.tgz#0c3f5bed440822182e972317122acb65d311a5ed"
integrity sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg==
dependencies:
"@octokit/request" "^5.6.0"
"@octokit/types" "^6.0.3"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^8.1.3":
version "8.1.3"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-8.1.3.tgz#45fbb4b0e5a5d61b21aeef7f33d345e05766236b"
integrity sha512-iK7SfjjkGdIiopuKEMAzPxSagZtIzWjwfYFBFxLKIS4Q4S8rSLQk7EnlTok2/bNAz1BvxnGKPKe+auSiCIU5QQ==
"@octokit/plugin-paginate-rest@^2.13.3":
version "2.13.6"
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.6.tgz#03633839b0ec57a108d2ca1c4b1f64b749d3506c"
integrity sha512-ai7TNKLi8tGkDvLM7fm0X1fbIP9u1nfXnN49ZAw2PgSoQou9yixKn5c3m0awuLacbuX2aXEvJpv1gKm3jboabg==
dependencies:
"@octokit/types" "^6.17.3"
"@octokit/plugin-rest-endpoint-methods@^5.1.1":
version "5.3.6"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.3.6.tgz#1cc2106e73f44432e6dad9e464a33db7b5930a03"
integrity sha512-uJi23hKKzFS+ACePgKYthSPyYkRgQgB36h07AZAS0H98x2AyjZy2ppr9Q36Faq4eoHRgrPnmf1suquMmymkN/Q==
dependencies:
"@octokit/types" "^6.17.3"
deprecation "^2.3.1"
"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677"
integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==
dependencies:
"@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.0.tgz#6084861b6e4fa21dc40c8e2a739ec5eff597e672"
integrity sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.1.0"
"@octokit/types" "^6.16.1"
is-plain-object "^5.0.0"
node-fetch "^2.6.1"
universal-user-agent "^6.0.0"
"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.17.3":
version "6.17.3"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.17.3.tgz#af5aaae50bd9230ac502d288a937c0d8e9f2181a"
integrity sha512-l3JiWbtK95CTsHTuF8WpE0Raq9efWUUU88CiWiCxRgTsauUkIRmVYZoDZTwAHn1xAnPz0aezQynIo6igS9EqQA==
dependencies:
"@octokit/openapi-types" "^8.1.3"
"@sinonjs/commons@^1.7.0":
version "1.8.3"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"
@ -852,6 +948,11 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
before-after-hook@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -1214,6 +1315,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
@ -1784,6 +1890,11 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4:
dependencies:
isobject "^3.0.1"
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-potential-custom-element-name@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
@ -2558,6 +2669,11 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@ -3389,6 +3505,11 @@ union-value@^1.0.0:
is-extendable "^0.1.1"
set-value "^2.0.1"
universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
universalify@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"