diff --git a/__tests__/docker/install.test.e2e.ts b/__tests__/docker/install.test.e2e.ts index dcde65c..f6713ca 100644 --- a/__tests__/docker/install.test.e2e.ts +++ b/__tests__/docker/install.test.e2e.ts @@ -25,7 +25,7 @@ const tmpDir = path.join(process.env.TEMP || '/tmp', 'docker-install-jest'); describe('install', () => { // prettier-ignore - test.each(['23.0.0'])( + test.each(['v23.0.0'])( 'install docker %s', async (version) => { await expect((async () => { const install = new Install({ diff --git a/__tests__/docker/install.test.ts b/__tests__/docker/install.test.ts index 4b89959..bbdc7a7 100644 --- a/__tests__/docker/install.test.ts +++ b/__tests__/docker/install.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import {describe, expect, jest, test, beforeEach, afterEach} from '@jest/globals'; +import {describe, expect, jest, test, beforeEach, afterEach, it} from '@jest/globals'; import * as fs from 'fs'; import * as path from 'path'; import * as rimraf from 'rimraf'; @@ -36,10 +36,10 @@ afterEach(function () { describe('download', () => { // prettier-ignore test.each([ - ['19.03.6', 'linux'], - ['20.10.22', 'linux'], - ['20.10.22', 'darwin'], - ['20.10.22', 'win32'], + ['v19.03.14', 'linux'], + ['v20.10.22', 'linux'], + ['v20.10.22', 'darwin'], + ['v20.10.22', 'win32'], ])( 'acquires %p of docker (%s)', async (version, platformOS) => { jest.spyOn(osm, 'platform').mockImplementation(() => platformOS); @@ -51,3 +51,23 @@ describe('download', () => { expect(fs.existsSync(toolPath)).toBe(true); }, 100000); }); + +describe('getRelease', () => { + it('returns latest docker GitHub release', async () => { + const release = await Install.getRelease('latest'); + expect(release).not.toBeNull(); + expect(release?.tag_name).not.toEqual(''); + }); + + it('returns v23.0.0 buildx GitHub release', async () => { + const release = await Install.getRelease('v23.0.0'); + expect(release).not.toBeNull(); + expect(release?.id).toEqual(91109643); + expect(release?.tag_name).toEqual('v23.0.0'); + expect(release?.html_url).toEqual('https://github.com/moby/moby/releases/tag/v23.0.0'); + }); + + it('unknown release', async () => { + await expect(Install.getRelease('foo')).rejects.toThrowError(new Error('Cannot find Docker release foo in https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/docker-releases.json')); + }); +}); diff --git a/src/docker/install.ts b/src/docker/install.ts index f46a654..b961dcc 100644 --- a/src/docker/install.ts +++ b/src/docker/install.ts @@ -22,6 +22,7 @@ import retry from 'async-retry'; import * as handlebars from 'handlebars'; import * as util from 'util'; import * as core from '@actions/core'; +import * as httpm from '@actions/http-client'; import * as io from '@actions/io'; import * as tc from '@actions/tool-cache'; @@ -29,25 +30,27 @@ import {Context} from '../context'; import {Exec} from '../exec'; import {Util} from '../util'; import {colimaYamlData, dockerServiceLogsPs1, setupDockerLinuxSh, setupDockerWinPs1} from './assets'; +import {GitHubRelease} from '../types/github'; export interface InstallOpts { - version: string; + version?: string; channel?: string; runDir: string; contextName?: string; } export class Install { + private readonly runDir: string; private readonly version: string; private readonly channel: string; - private readonly runDir: string; private readonly contextName: string; + private _version: string | undefined; private _toolDir: string | undefined; constructor(opts: InstallOpts) { - this.version = opts.version; - this.channel = opts.channel || 'stable'; this.runDir = opts.runDir; + this.version = opts.version || 'latest'; + this.channel = opts.channel || 'stable'; this.contextName = opts.contextName || 'setup-docker-action'; } @@ -56,9 +59,13 @@ export class Install { } public async download(): Promise { - const downloadURL = this.downloadURL(this.version, this.channel); + const release: GitHubRelease = await Install.getRelease(this.version); + this._version = release.tag_name.replace(/^v+|v+$/g, ''); + core.debug(`docker.Install.download version: ${this._version}`); + const downloadURL = this.downloadURL(this._version, this.channel); core.info(`Downloading ${downloadURL}`); + const downloadPath = await tc.downloadTool(downloadURL); core.debug(`docker.Install.download downloadPath: ${downloadPath}`); @@ -84,7 +91,7 @@ export class Install { }); }); - const tooldir = await tc.cacheDir(extractFolder, `docker-${this.channel}`, this.version.replace(/(0+)([1-9]+)/, '$2')); + const tooldir = await tc.cacheDir(extractFolder, `docker-${this.channel}`, this._version.replace(/(0+)([1-9]+)/, '$2')); core.addPath(tooldir); core.info('Added Docker to PATH'); @@ -132,7 +139,7 @@ export class Install { await core.group('Creating colima config', async () => { const colimaCfg = handlebars.compile(colimaYamlData)({ hostArch: Install.platformArch(), - dockerVersion: this.version, + dockerVersion: this._version, dockerChannel: this.channel }); core.info(`Writing colima config to ${path.join(colimaDir, 'colima.yaml')}`); @@ -360,4 +367,20 @@ export class Install { return false; }); } + + public static async getRelease(version: string): Promise { + const url = `https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/docker-releases.json`; + const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit'); + const resp: httpm.HttpClientResponse = await http.get(url); + const body = await resp.readBody(); + const statusCode = resp.message.statusCode || 500; + if (statusCode >= 400) { + throw new Error(`Failed to get Docker release ${version} from ${url} with status code ${statusCode}: ${body}`); + } + const releases = >JSON.parse(body); + if (!releases[version]) { + throw new Error(`Cannot find Docker release ${version} in ${url}`); + } + return releases[version]; + } }