diff --git a/.eslintrc.json b/.eslintrc.json index ba2a82b..b46613b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,7 +2,7 @@ "env": { "node": true, "es2021": true, - "jest/globals": true + "jest": true }, "extends": [ "eslint:recommended", diff --git a/.gitignore b/.gitignore index 581f4fa..aa82f5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ node_modules lib -# Jetbrains -/.idea -/*.iml - # Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore # Logs logs diff --git a/__mocks__/@actions/github.ts b/__mocks__/@actions/github.ts new file mode 100644 index 0000000..254a5df --- /dev/null +++ b/__mocks__/@actions/github.ts @@ -0,0 +1,207 @@ +import {jest} from '@jest/globals'; + +export const context = { + repo: { + owner: 'docker', + repo: 'build-push-action' + }, + ref: 'refs/heads/master', + runId: 123456789, + payload: { + after: '860c1904a1ce19322e91ac35af1ab07466440c37', + base_ref: null, + before: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a', + commits: [ + { + author: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + committer: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + distinct: true, + id: '860c1904a1ce19322e91ac35af1ab07466440c37', + message: 'hello dev', + timestamp: '2022-04-19T11:27:24+02:00', + tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820', + url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37' + } + ], + compare: 'https://github.com/docker/test-docker-action/compare/5f3331d7f704...860c1904a1ce', + created: false, + deleted: false, + forced: false, + head_commit: { + author: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + committer: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + distinct: true, + id: '860c1904a1ce19322e91ac35af1ab07466440c37', + message: 'hello dev', + timestamp: '2022-04-19T11:27:24+02:00', + tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820', + url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37' + }, + organization: { + avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4', + description: 'Docker helps developers bring their ideas to life by conquering the complexity of app development.', + events_url: 'https://api.github.com/orgs/docker/events', + hooks_url: 'https://api.github.com/orgs/docker/hooks', + id: 5429470, + issues_url: 'https://api.github.com/orgs/docker/issues', + login: 'docker', + members_url: 'https://api.github.com/orgs/docker/members{/member}', + node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=', + public_members_url: 'https://api.github.com/orgs/docker/public_members{/member}', + repos_url: 'https://api.github.com/orgs/docker/repos', + url: 'https://api.github.com/orgs/docker' + }, + pusher: { + email: 'github@crazymax.dev', + name: 'crazy-max' + }, + ref: 'refs/heads/dev', + repository: { + allow_forking: true, + archive_url: 'https://api.github.com/repos/docker/test-docker-action/{archive_format}{/ref}', + archived: false, + assignees_url: 'https://api.github.com/repos/docker/test-docker-action/assignees{/user}', + blobs_url: 'https://api.github.com/repos/docker/test-docker-action/git/blobs{/sha}', + branches_url: 'https://api.github.com/repos/docker/test-docker-action/branches{/branch}', + clone_url: 'https://github.com/docker/test-docker-action.git', + collaborators_url: 'https://api.github.com/repos/docker/test-docker-action/collaborators{/collaborator}', + comments_url: 'https://api.github.com/repos/docker/test-docker-action/comments{/number}', + commits_url: 'https://api.github.com/repos/docker/test-docker-action/commits{/sha}', + compare_url: 'https://api.github.com/repos/docker/test-docker-action/compare/{base}...{head}', + contents_url: 'https://api.github.com/repos/docker/test-docker-action/contents/{+path}', + contributors_url: 'https://api.github.com/repos/docker/test-docker-action/contributors', + created_at: 1596792180, + default_branch: 'master', + deployments_url: 'https://api.github.com/repos/docker/test-docker-action/deployments', + description: 'Test "Docker" Actions', + disabled: false, + downloads_url: 'https://api.github.com/repos/docker/test-docker-action/downloads', + events_url: 'https://api.github.com/repos/docker/test-docker-action/events', + fork: false, + forks: 1, + forks_count: 1, + forks_url: 'https://api.github.com/repos/docker/test-docker-action/forks', + full_name: 'docker/test-docker-action', + git_commits_url: 'https://api.github.com/repos/docker/test-docker-action/git/commits{/sha}', + git_refs_url: 'https://api.github.com/repos/docker/test-docker-action/git/refs{/sha}', + git_tags_url: 'https://api.github.com/repos/docker/test-docker-action/git/tags{/sha}', + git_url: 'git://github.com/docker/test-docker-action.git', + has_downloads: true, + has_issues: true, + has_pages: false, + has_projects: true, + has_wiki: true, + homepage: '', + hooks_url: 'https://api.github.com/repos/docker/test-docker-action/hooks', + html_url: 'https://github.com/docker/test-docker-action', + id: 285789493, + is_template: false, + issue_comment_url: 'https://api.github.com/repos/docker/test-docker-action/issues/comments{/number}', + issue_events_url: 'https://api.github.com/repos/docker/test-docker-action/issues/events{/number}', + issues_url: 'https://api.github.com/repos/docker/test-docker-action/issues{/number}', + keys_url: 'https://api.github.com/repos/docker/test-docker-action/keys{/key_id}', + labels_url: 'https://api.github.com/repos/docker/test-docker-action/labels{/name}', + language: 'JavaScript', + languages_url: 'https://api.github.com/repos/docker/test-docker-action/languages', + license: { + key: 'mit', + name: 'MIT License', + node_id: 'MDc6TGljZW5zZTEz', + spdx_id: 'MIT', + url: 'https://api.github.com/licenses/mit' + }, + master_branch: 'master', + merges_url: 'https://api.github.com/repos/docker/test-docker-action/merges', + milestones_url: 'https://api.github.com/repos/docker/test-docker-action/milestones{/number}', + mirror_url: null, + name: 'test-docker-action', + node_id: 'MDEwOlJlcG9zaXRvcnkyODU3ODk0OTM=', + notifications_url: 'https://api.github.com/repos/docker/test-docker-action/notifications{?since,all,participating}', + open_issues: 6, + open_issues_count: 6, + organization: 'docker', + owner: { + avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4', + email: 'info@docker.com', + events_url: 'https://api.github.com/users/docker/events{/privacy}', + followers_url: 'https://api.github.com/users/docker/followers', + following_url: 'https://api.github.com/users/docker/following{/other_user}', + gists_url: 'https://api.github.com/users/docker/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/docker', + id: 5429470, + login: 'docker', + name: 'docker', + node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=', + organizations_url: 'https://api.github.com/users/docker/orgs', + received_events_url: 'https://api.github.com/users/docker/received_events', + repos_url: 'https://api.github.com/users/docker/repos', + site_admin: false, + starred_url: 'https://api.github.com/users/docker/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/docker/subscriptions', + type: 'Organization', + url: 'https://api.github.com/users/docker' + }, + private: true, + pulls_url: 'https://api.github.com/repos/docker/test-docker-action/pulls{/number}', + pushed_at: 1650360446, + releases_url: 'https://api.github.com/repos/docker/test-docker-action/releases{/id}', + size: 796, + ssh_url: 'git@github.com:docker/test-docker-action.git', + stargazers: 0, + stargazers_count: 0, + stargazers_url: 'https://api.github.com/repos/docker/test-docker-action/stargazers', + statuses_url: 'https://api.github.com/repos/docker/test-docker-action/statuses/{sha}', + subscribers_url: 'https://api.github.com/repos/docker/test-docker-action/subscribers', + subscription_url: 'https://api.github.com/repos/docker/test-docker-action/subscription', + svn_url: 'https://github.com/docker/test-docker-action', + tags_url: 'https://api.github.com/repos/docker/test-docker-action/tags', + teams_url: 'https://api.github.com/repos/docker/test-docker-action/teams', + topics: [], + trees_url: 'https://api.github.com/repos/docker/test-docker-action/git/trees{/sha}', + updated_at: '2022-04-19T09:05:09Z', + url: 'https://github.com/docker/test-docker-action', + visibility: 'private', + watchers: 0, + watchers_count: 0 + }, + sender: { + avatar_url: 'https://avatars.githubusercontent.com/u/1951866?v=4', + events_url: 'https://api.github.com/users/crazy-max/events{/privacy}', + followers_url: 'https://api.github.com/users/crazy-max/followers', + following_url: 'https://api.github.com/users/crazy-max/following{/other_user}', + gists_url: 'https://api.github.com/users/crazy-max/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/crazy-max', + id: 1951866, + login: 'crazy-max', + node_id: 'MDQ6VXNlcjE5NTE4NjY=', + organizations_url: 'https://api.github.com/users/crazy-max/orgs', + received_events_url: 'https://api.github.com/users/crazy-max/received_events', + repos_url: 'https://api.github.com/users/crazy-max/repos', + site_admin: false, + starred_url: 'https://api.github.com/users/crazy-max/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/crazy-max/subscriptions', + type: 'User', + url: 'https://api.github.com/users/crazy-max' + } + } +}; + +export const getOctokit = jest.fn(); diff --git a/__tests__/buildx.test.ts b/__tests__/buildx.test.ts deleted file mode 100644 index 81b7aba..0000000 --- a/__tests__/buildx.test.ts +++ /dev/null @@ -1,146 +0,0 @@ -import {describe, expect, it, jest, test} from '@jest/globals'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as semver from 'semver'; -import * as exec from '@actions/exec'; -import * as buildx from '../src/buildx'; -import * as context from '../src/context'; - -const tmpNameSync = path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep); -const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9'; -const metadata = `{ - "containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd", - "containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c" -}`; - -jest.spyOn(context, 'tmpDir').mockImplementation((): string => { - const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep); - if (!fs.existsSync(tmpDir)) { - fs.mkdirSync(tmpDir, {recursive: true}); - } - return tmpDir; -}); - -jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => { - return tmpNameSync; -}); - -describe('getImageID', () => { - it('matches', async () => { - const imageIDFile = await buildx.getImageIDFile(); - await fs.writeFileSync(imageIDFile, imageID); - const expected = await buildx.getImageID(); - expect(expected).toEqual(imageID); - }); -}); - -describe('getMetadata', () => { - it('matches', async () => { - const metadataFile = await buildx.getMetadataFile(); - await fs.writeFileSync(metadataFile, metadata); - const expected = await buildx.getMetadata(); - expect(expected).toEqual(metadata); - }); -}); - -describe('getDigest', () => { - it('matches', async () => { - const metadataFile = await buildx.getMetadataFile(); - await fs.writeFileSync(metadataFile, metadata); - const expected = await buildx.getDigest(metadata); - expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c'); - }); -}); - -describe('isLocalOrTarExporter', () => { - test.each([ - [['type=registry,ref=user/app'], false], - [['type=docker'], false], - [['type=local,dest=./release-out'], true], - [['type=tar,dest=/tmp/image.tar'], true], - [['type=docker', 'type=tar,dest=/tmp/image.tar'], true], - [['"type=tar","dest=/tmp/image.tar"'], true], - [['" type= local" , dest=./release-out'], true], - [['.'], true] - ])('given %p returns %p', async (outputs: Array, expected: boolean) => { - expect(buildx.isLocalOrTarExporter(outputs)).toEqual(expected); - }); -}); - -describe('isAvailable', () => { - const execSpy = jest.spyOn(exec, 'getExecOutput'); - buildx.isAvailable(); - - // eslint-disable-next-line jest/no-standalone-expect - expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], { - silent: true, - ignoreReturnCode: true - }); -}); - -describe('isAvailable standalone', () => { - const execSpy = jest.spyOn(exec, 'getExecOutput'); - buildx.isAvailable(true); - - // eslint-disable-next-line jest/no-standalone-expect - expect(execSpy).toHaveBeenCalledWith(`buildx`, [], { - silent: true, - ignoreReturnCode: true - }); -}); - -describe('getVersion', () => { - it('valid', async () => { - const version = await buildx.getVersion(); - expect(semver.valid(version)).not.toBeNull(); - }); -}); - -describe('parseVersion', () => { - test.each([ - ['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'], - ['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'], - ['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'], - ['github.com/docker/buildx f117971 f11797113e5a9b86bd976329c5dbb8a8bfdfadfa', 'f117971'] - ])('given %p', async (stdout, expected) => { - expect(buildx.parseVersion(stdout)).toEqual(expected); - }); -}); - -describe('satisfies', () => { - test.each([ - ['0.4.1', '>=0.3.2', true], - ['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false], - ['f117971', '>0.6.0', true] - ])('given %p', async (version, range, expected) => { - expect(buildx.satisfies(version, range)).toBe(expected); - }); -}); - -describe('getSecret', () => { - test.each([ - ['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', false], - ['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false], - ['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', false, 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false], - ['aaaaaaaa', false, '', '', true], - ['aaaaaaaa=', false, '', '', true], - ['=bbbbbbb', false, '', '', true], - [`foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`, true, 'foo', 'bar', false], - [`notfound=secret`, true, '', '', true] - ])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => { - try { - let secret: string; - if (file) { - secret = await buildx.getSecretFile(kvp); - } else { - secret = await buildx.getSecretString(kvp); - } - expect(true).toBe(!invalid); - expect(secret).toEqual(`id=${exKey},src=${tmpNameSync}`); - expect(fs.readFileSync(tmpNameSync, 'utf-8')).toEqual(exValue); - } catch (err) { - // eslint-disable-next-line jest/no-conditional-expect - expect(true).toBe(invalid); - } - }); -}); diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts index a5171f9..6595599 100644 --- a/__tests__/context.test.ts +++ b/__tests__/context.test.ts @@ -1,134 +1,58 @@ -import {beforeEach, describe, expect, it, jest, test} from '@jest/globals'; +import {beforeEach, describe, expect, jest, test} from '@jest/globals'; import * as fs from 'fs'; import * as path from 'path'; +import {Builder} from '@docker/actions-toolkit/lib/buildx/builder'; +import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx'; +import {Context} from '@docker/actions-toolkit/lib/context'; +import {Docker} from '@docker/actions-toolkit/lib/docker'; +import {GitHub} from '@docker/actions-toolkit/lib/github'; +import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; +import {BuilderInfo} from '@docker/actions-toolkit/lib/types/builder'; +import {GitHubRepo} from '@docker/actions-toolkit/lib/types/github'; -import * as buildx from '../src/buildx'; import * as context from '../src/context'; -const pgp = `-----BEGIN PGP PRIVATE KEY BLOCK----- +const tmpDir = path.join('/tmp', '.docker-build-push-jest'); +const tmpName = path.join(tmpDir, '.tmpname-jest'); -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 -PejgXO0uIRolYQ3sz2tMGhx1MfBqH64= -=WbwB ------END PGP PRIVATE KEY BLOCK-----`; - -jest.spyOn(context, 'defaultContext').mockImplementation((): string => { - return 'https://github.com/docker/build-push-action.git#refs/heads/test-jest'; +import repoFixture from './fixtures/github-repo.json'; +jest.spyOn(GitHub.prototype, 'repoData').mockImplementation((): Promise => { + return >(repoFixture as unknown); }); -jest.spyOn(context, 'tmpDir').mockImplementation((): string => { - const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep); +jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir, {recursive: true}); } return tmpDir; }); -jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => { - return path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep); +jest.spyOn(Context, 'tmpName').mockImplementation((): string => { + return tmpName; }); -jest.spyOn(buildx, 'satisfiesBuildKitVersion').mockResolvedValueOnce(true); +jest.spyOn(Docker, 'isAvailable').mockImplementation(async (): Promise => { + return true; +}); + +jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise => { + return { + name: 'builder2', + driver: 'docker-container', + lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'), + nodes: [ + { + buildkitVersion: 'v0.11.0', + buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', + driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'], + endpoint: 'unix:///var/run/docker.sock', + name: 'builder20', + platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6', + status: 'running' + } + ] + }; +}); describe('getArgs', () => { beforeEach(() => { @@ -154,7 +78,7 @@ describe('getArgs', () => { ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '.' ] ], @@ -177,8 +101,8 @@ ccc"`], '--build-arg', 'MY_ARG=val1,val2,val3', '--build-arg', 'ARG=val', '--build-arg', `MULTILINE=aaaa\nbbbb\nccc`, - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - 'https://github.com/docker/build-push-action.git#refs/heads/test-jest' + '--iidfile', path.join(tmpDir, 'iidfile'), + 'https://github.com/docker/build-push-action.git#refs/heads/master' ] ], [ @@ -193,10 +117,10 @@ ccc"`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '--tag', 'name/app:7.4', '--tag', 'name/app:latest', - 'https://github.com/docker/build-push-action.git#refs/heads/test-jest' + 'https://github.com/docker/build-push-action.git#refs/heads/master' ] ], [ @@ -248,7 +172,7 @@ ccc"`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '.' ] ], @@ -265,8 +189,8 @@ ccc"`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', + '--iidfile', path.join(tmpDir, 'iidfile'), + '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, '.' ] ], @@ -284,8 +208,8 @@ ccc"`], [ 'build', '--output', '.', - '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', - 'https://github.com/docker/build-push-action.git#refs/heads/test-jest' + '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, + 'https://github.com/docker/build-push-action.git#refs/heads/master' ] ], [ @@ -306,9 +230,9 @@ ccc"`], [ 'build', '--file', './test/Dockerfile', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '--platform', 'linux/amd64,linux/arm64', - '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', + '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, '--builder', 'builder-git-context-2', '--push', 'https://github.com/docker/build-push-action.git#refs/heads/master' @@ -340,12 +264,12 @@ ccc"`], [ 'build', '--file', './test/Dockerfile', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '--platform', 'linux/amd64,linux/arm64', - '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--secret', 'id=MYSECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--secret', 'id=FOO,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--secret', 'id=EMPTYLINE,src=/tmp/.docker-build-push-jest/.tmpname-jest', + '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, + '--secret', `id=MYSECRET,src=${tmpName}`, + '--secret', `id=FOO,src=${tmpName}`, + '--secret', `id=EMPTYLINE,src=${tmpName}`, '--builder', 'builder-git-context-2', '--push', 'https://github.com/docker/build-push-action.git#refs/heads/master' @@ -377,12 +301,12 @@ ccc`], [ 'build', '--file', './test/Dockerfile', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '--platform', 'linux/amd64,linux/arm64', - '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--secret', 'id=MYSECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--secret', 'id=FOO,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--secret', 'id=EMPTYLINE,src=/tmp/.docker-build-push-jest/.tmpname-jest', + '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, + '--secret', `id=MYSECRET,src=${tmpName}`, + '--secret', `id=FOO,src=${tmpName}`, + '--secret', `id=EMPTYLINE,src=${tmpName}`, '--builder', 'builder-git-context-2', '--push', 'https://github.com/docker/build-push-action.git#refs/heads/master' @@ -394,7 +318,7 @@ ccc`], new Map([ ['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'], ['tag', 'localhost:5000/name/app:latest'], - ['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`], + ['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt')}`], ['file', './test/Dockerfile'], ['builder', 'builder-git-context-2'], ['network', 'host'], @@ -406,8 +330,8 @@ ccc`], [ 'build', '--file', './test/Dockerfile', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - '--secret', 'id=MY_SECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest', + '--iidfile', path.join(tmpDir, 'iidfile'), + '--secret', `id=MY_SECRET,src=${tmpName}`, '--builder', 'builder-git-context-2', '--network', 'host', '--push', @@ -453,8 +377,8 @@ ccc`], '--add-host', 'docker:10.180.0.1', '--add-host', 'foo:10.0.0.1', '--file', './test/Dockerfile', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--iidfile', path.join(tmpDir, 'iidfile'), + '--metadata-file', path.join(tmpDir, 'metadata-file'), '--network', 'host', '--push', '.' @@ -482,11 +406,11 @@ nproc=3`], '--add-host', 'foo:10.0.0.1', '--cgroup-parent', 'foo', '--file', './test/Dockerfile', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), '--shm-size', '2g', '--ulimit', 'nofile=1024:1024', '--ulimit', 'nproc=3', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -502,9 +426,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', - 'https://github.com/docker/build-push-action.git#refs/heads/test-jest:docker' + '--iidfile', path.join(tmpDir, 'iidfile'), + '--metadata-file', path.join(tmpDir, 'metadata-file'), + 'https://github.com/docker/build-push-action.git#refs/heads/master:docker' ] ], [ @@ -520,10 +444,10 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - '--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', - 'https://github.com/docker/build-push-action.git#refs/heads/test-jest:subdir' + '--iidfile', path.join(tmpDir, 'iidfile'), + '--secret', `id=GIT_AUTH_TOKEN,src=${tmpName}`, + '--metadata-file', path.join(tmpDir, 'metadata-file'), + 'https://github.com/docker/build-push-action.git#refs/heads/master:subdir' ] ], [ @@ -539,8 +463,8 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--iidfile', path.join(tmpDir, 'iidfile'), + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -556,9 +480,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), "--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -575,9 +499,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), "--provenance", `builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -594,9 +518,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), "--provenance", `mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -613,9 +537,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), "--provenance", 'false', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -632,9 +556,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), "--provenance", 'builder-id=foo', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -651,9 +575,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', + '--iidfile', path.join(tmpDir, 'iidfile'), "--output", 'type=docker', - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -669,9 +593,9 @@ nproc=3`], ]), [ 'build', - '--iidfile', '/tmp/.docker-build-push-jest/iidfile', - "--load", - '--metadata-file', '/tmp/.docker-build-push-jest/metadata-file', + '--iidfile', path.join(tmpDir, 'iidfile'), + '--load', + '--metadata-file', path.join(tmpDir, 'metadata-file'), '.' ] ], @@ -681,171 +605,17 @@ nproc=3`], inputs.forEach((value: string, name: string) => { setInput(name, value); }); - const defContext = context.defaultContext(); - const inp = await context.getInputs(defContext); - const res = await context.getArgs(inp, defContext, buildxVersion); + const toolkit = new Toolkit(); + jest.spyOn(Buildx.prototype, 'version').mockImplementation(async (): Promise => { + return buildxVersion; + }); + const inp = await context.getInputs(); + const res = await context.getArgs(inp, toolkit); expect(res).toEqual(expected); } ); }); -describe('getInputList', () => { - it('single line correctly', async () => { - await setInput('foo', 'bar'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar']); - }); - - it('multiline correctly', async () => { - setInput('foo', 'bar\nbaz'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar', 'baz']); - }); - - it('empty lines correctly', async () => { - setInput('foo', 'bar\n\nbaz'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar', 'baz']); - }); - - it('comma correctly', async () => { - setInput('foo', 'bar,baz'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar', 'baz']); - }); - - it('empty result correctly', async () => { - setInput('foo', 'bar,baz,'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar', 'baz']); - }); - - it('different new lines correctly', async () => { - setInput('foo', 'bar\r\nbaz'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar', 'baz']); - }); - - it('different new lines and comma correctly', async () => { - setInput('foo', 'bar\r\nbaz,bat'); - const res = await context.getInputList('foo'); - expect(res).toEqual(['bar', 'baz', 'bat']); - }); - - it('multiline and ignoring comma correctly', async () => { - setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir'); - const res = await context.getInputList('cache-from', true); - expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']); - }); - - it('different new lines and ignoring comma correctly', async () => { - setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir'); - const res = await context.getInputList('cache-from', true); - expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']); - }); - - it('multiline values', async () => { - setInput( - 'secrets', - `GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789 -"MYSECRET=aaaaaaaa -bbbbbbb -ccccccccc" -FOO=bar` - ); - const res = await context.getInputList('secrets', true); - expect(res).toEqual([ - 'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', - `MYSECRET=aaaaaaaa -bbbbbbb -ccccccccc`, - 'FOO=bar' - ]); - }); - - it('multiline values with empty lines', async () => { - setInput( - 'secrets', - `GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789 -"MYSECRET=aaaaaaaa -bbbbbbb -ccccccccc" -FOO=bar -"EMPTYLINE=aaaa - -bbbb -ccc"` - ); - const res = await context.getInputList('secrets', true); - expect(res).toEqual([ - 'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', - `MYSECRET=aaaaaaaa -bbbbbbb -ccccccccc`, - 'FOO=bar', - `EMPTYLINE=aaaa - -bbbb -ccc` - ]); - }); - - it('multiline values without quotes', async () => { - setInput( - 'secrets', - `GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789 -MYSECRET=aaaaaaaa -bbbbbbb -ccccccccc -FOO=bar` - ); - const res = await context.getInputList('secrets', true); - expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']); - }); - - it('large multiline values', async () => { - setInput( - 'secrets', - `"GPG_KEY=${pgp}" -FOO=bar` - ); - const res = await context.getInputList('secrets', true); - expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']); - }); - - it('multiline values escape quotes', async () => { - setInput( - 'secrets', - `GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789 -"MYSECRET=aaaaaaaa -bbbb""bbb -ccccccccc" -FOO=bar` - ); - const res = await context.getInputList('secrets', true); - expect(res).toEqual([ - 'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', - `MYSECRET=aaaaaaaa -bbbb"bbb -ccccccccc`, - 'FOO=bar' - ]); - }); -}); - -describe('asyncForEach', () => { - it('executes async tasks sequentially', async () => { - const testValues = [1, 2, 3, 4, 5]; - const results: number[] = []; - - await context.asyncForEach(testValues, async value => { - results.push(value); - }); - - expect(results).toEqual(testValues); - }); -}); - // See: https://github.com/actions/toolkit/blob/a1b068ec31a042ff1e10a522d8fdf0b8869d53ca/packages/core/src/core.ts#L89 function getInputName(name: string): string { return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`; diff --git a/__tests__/docker.test.ts b/__tests__/docker.test.ts deleted file mode 100644 index d1b7075..0000000 --- a/__tests__/docker.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {describe, expect, it, jest} from '@jest/globals'; -import * as docker from '../src/docker'; -import * as exec from '@actions/exec'; - -describe('isAvailable', () => { - it('cli', () => { - const execSpy = jest.spyOn(exec, 'getExecOutput'); - docker.isAvailable(); - - // eslint-disable-next-line jest/no-standalone-expect - expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, { - silent: true, - ignoreReturnCode: true - }); - }); -}); diff --git a/__tests__/fixtures/github-repo.json b/__tests__/fixtures/github-repo.json new file mode 100644 index 0000000..faf700c --- /dev/null +++ b/__tests__/fixtures/github-repo.json @@ -0,0 +1,362 @@ +{ + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "pull": true, + "triage": true, + "push": false, + "maintain": false, + "admin": false + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZW1pdA==" + }, + "organization": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "Organization", + "site_admin": false + }, + "parent": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0 + }, + "source": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0 + } +} diff --git a/__tests__/fixtures/secret.txt b/__tests__/fixtures/secret.txt index ba0e162..5716ca5 100644 --- a/__tests__/fixtures/secret.txt +++ b/__tests__/fixtures/secret.txt @@ -1 +1 @@ -bar \ No newline at end of file +bar diff --git a/jest.config.ts b/jest.config.ts index 60d168a..bc38ba9 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,8 +1,14 @@ +import fs from 'fs'; +import os from 'os'; +import path from 'path'; + +const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-build-push-action-')); + process.env = Object.assign({}, process.env, { - RUNNER_TEMP: '/tmp/github_runner', - RUNNER_TOOL_CACHE: '/tmp/github_tool_cache', + TEMP: tmpDir, GITHUB_REPOSITORY: 'docker/build-push-action', - GITHUB_RUN_ID: '123456789' + RUNNER_TEMP: path.join(tmpDir, 'runner-temp'), + RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache') }) as { [key: string]: string; }; @@ -11,7 +17,6 @@ module.exports = { clearMocks: false, testEnvironment: 'node', moduleFileExtensions: ['js', 'ts'], - setupFiles: ['dotenv/config'], testMatch: ['**/*.test.ts'], transform: { '^.+\\.ts$': 'ts-jest' @@ -19,5 +24,7 @@ module.exports = { moduleNameMapper: { '^csv-parse/sync': '/node_modules/csv-parse/dist/cjs/sync.cjs' }, + collectCoverageFrom: ['src/**/{!(main.ts),}.ts'], + coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'], verbose: true }; diff --git a/package.json b/package.json index 29b3a3b..dee3c49 100644 --- a/package.json +++ b/package.json @@ -29,23 +29,16 @@ "license": "Apache-2.0", "dependencies": { "@actions/core": "^1.10.0", - "@actions/exec": "^1.1.1", - "@actions/github": "^5.1.1", + "@docker/actions-toolkit": "^0.1.0-beta.14", "csv-parse": "^5.3.5", - "handlebars": "^4.7.7", - "jwt-decode": "^3.1.2", - "semver": "^7.3.7", - "tmp": "^0.2.1" + "handlebars": "^4.7.7" }, "devDependencies": { "@types/csv-parse": "^1.2.2", "@types/node": "^16.11.26", - "@types/semver": "^7.3.9", - "@types/tmp": "^0.2.3", "@typescript-eslint/eslint-plugin": "^5.14.0", "@typescript-eslint/parser": "^5.14.0", "@vercel/ncc": "^0.33.3", - "dotenv": "^16.0.0", "eslint": "^8.11.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-jest": "^26.1.1", diff --git a/src/buildx.ts b/src/buildx.ts deleted file mode 100644 index 4f503a5..0000000 --- a/src/buildx.ts +++ /dev/null @@ -1,282 +0,0 @@ -import {parse} from 'csv-parse/sync'; -import fs from 'fs'; -import path from 'path'; -import * as semver from 'semver'; -import * as exec from '@actions/exec'; -import * as context from './context'; - -export type Builder = { - name?: string; - driver?: string; - nodes: Node[]; -}; - -export type Node = { - name?: string; - endpoint?: string; - 'driver-opts'?: Array; - status?: string; - 'buildkitd-flags'?: string; - buildkit?: string; - platforms?: string; -}; - -export async function getImageIDFile(): Promise { - return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep); -} - -export async function getImageID(): Promise { - const iidFile = await getImageIDFile(); - if (!fs.existsSync(iidFile)) { - return undefined; - } - return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim(); -} - -export async function getMetadataFile(): Promise { - return path.join(context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep); -} - -export async function getMetadata(): Promise { - const metadataFile = await getMetadataFile(); - if (!fs.existsSync(metadataFile)) { - return undefined; - } - const content = fs.readFileSync(metadataFile, {encoding: 'utf-8'}).trim(); - if (content === 'null') { - return undefined; - } - return content; -} - -export async function getDigest(metadata: string | undefined): Promise { - if (metadata === undefined) { - return undefined; - } - const metadataJSON = JSON.parse(metadata); - if (metadataJSON['containerimage.digest']) { - return metadataJSON['containerimage.digest']; - } - return undefined; -} - -export async function getSecretString(kvp: string): Promise { - return getSecret(kvp, false); -} - -export async function getSecretFile(kvp: string): Promise { - return getSecret(kvp, true); -} - -export async function getSecret(kvp: string, file: boolean): Promise { - const delimiterIndex = kvp.indexOf('='); - const key = kvp.substring(0, delimiterIndex); - let value = kvp.substring(delimiterIndex + 1); - if (key.length == 0 || value.length == 0) { - throw new Error(`${kvp} is not a valid secret`); - } - - if (file) { - if (!fs.existsSync(value)) { - throw new Error(`secret file ${value} not found`); - } - value = fs.readFileSync(value, {encoding: 'utf-8'}); - } - - const secretFile = context.tmpNameSync({ - tmpdir: context.tmpDir() - }); - fs.writeFileSync(secretFile, value); - - return `id=${key},src=${secretFile}`; -} - -export function isLocalOrTarExporter(outputs: string[]): boolean { - const records = parse(outputs.join(`\n`), { - delimiter: ',', - trim: true, - columns: false, - relaxColumnCount: true - }); - for (const record of records) { - // Local if no type is defined - // https://github.com/docker/buildx/blob/d2bf42f8b4784d83fde17acb3ed84703ddc2156b/build/output.go#L29-L43 - if (record.length == 1 && !record[0].startsWith('type=')) { - return true; - } - for (const [key, value] of record.map(chunk => chunk.split('=').map(item => item.trim()))) { - if (key == 'type' && (value == 'local' || value == 'tar')) { - return true; - } - } - } - return false; -} - -export function hasGitAuthToken(secrets: string[]): boolean { - for (const secret of secrets) { - if (secret.startsWith('GIT_AUTH_TOKEN=')) { - return true; - } - } - return false; -} - -export async function isAvailable(standalone?: boolean): Promise { - const cmd = getCommand([], standalone); - return await exec - .getExecOutput(cmd.command, cmd.args, { - ignoreReturnCode: true, - silent: true - }) - .then(res => { - if (res.stderr.length > 0 && res.exitCode != 0) { - return false; - } - return res.exitCode == 0; - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .catch(error => { - return false; - }); -} - -export async function satisfiesBuildKitVersion(builderName: string, range: string, standalone?: boolean): Promise { - const builderInspect = await inspect(builderName, standalone); - for (const node of builderInspect.nodes) { - if (!node.buildkit) { - return false; - } - // BuildKit version reported by moby is in the format of `v0.11.0-moby` - if (builderInspect.driver == 'docker' && !node.buildkit.endsWith('-moby')) { - return false; - } - const version = node.buildkit.replace(/-moby$/, ''); - if (!semver.satisfies(version, range)) { - return false; - } - } - return true; -} - -async function inspect(name: string, standalone?: boolean): Promise { - const cmd = getCommand(['inspect', name], standalone); - return await exec - .getExecOutput(cmd.command, cmd.args, { - ignoreReturnCode: true, - silent: true - }) - .then(res => { - if (res.stderr.length > 0 && res.exitCode != 0) { - throw new Error(res.stderr.trim()); - } - return parseInspect(res.stdout); - }); -} - -async function parseInspect(data: string): Promise { - const builder: Builder = { - nodes: [] - }; - let node: Node = {}; - for (const line of data.trim().split(`\n`)) { - const [key, ...rest] = line.split(':'); - const value = rest.map(v => v.trim()).join(':'); - if (key.length == 0 || value.length == 0) { - continue; - } - switch (key.toLowerCase()) { - case 'name': { - if (builder.name == undefined) { - builder.name = value; - } else { - if (Object.keys(node).length > 0) { - builder.nodes.push(node); - node = {}; - } - node.name = value; - } - break; - } - case 'driver': { - builder.driver = value; - break; - } - case 'endpoint': { - node.endpoint = value; - break; - } - case 'driver options': { - node['driver-opts'] = (value.match(/(\w+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2')); - break; - } - case 'status': { - node.status = value; - break; - } - case 'flags': { - node['buildkitd-flags'] = value; - break; - } - case 'buildkit': { - node.buildkit = value; - break; - } - case 'platforms': { - let platforms: Array = []; - // if a preferred platform is being set then use only these - // https://docs.docker.com/engine/reference/commandline/buildx_inspect/#get-information-about-a-builder-instance - if (value.includes('*')) { - for (const platform of value.split(', ')) { - if (platform.includes('*')) { - platforms.push(platform.replace('*', '')); - } - } - } else { - // otherwise set all platforms available - platforms = value.split(', '); - } - node.platforms = platforms.join(','); - break; - } - } - } - if (Object.keys(node).length > 0) { - builder.nodes.push(node); - } - return builder; -} - -export async function getVersion(standalone?: boolean): Promise { - const cmd = getCommand(['version'], standalone); - return await exec - .getExecOutput(cmd.command, cmd.args, { - ignoreReturnCode: true, - silent: true - }) - .then(res => { - if (res.stderr.length > 0 && res.exitCode != 0) { - throw new Error(res.stderr.trim()); - } - return parseVersion(res.stdout.trim()); - }); -} - -export function parseVersion(stdout: string): string { - const matches = /\sv?([0-9a-f]{7}|[0-9.]+)/.exec(stdout); - if (!matches) { - throw new Error(`Cannot parse buildx version`); - } - return matches[1]; -} - -export function satisfies(version: string, range: string): boolean { - return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null; -} - -export function getCommand(args: Array, standalone?: boolean) { - return { - command: standalone ? 'buildx' : 'docker', - args: standalone ? args : ['buildx', ...args] - }; -} diff --git a/src/context.ts b/src/context.ts index bb18868..91121a0 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,14 +1,11 @@ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import * as tmp from 'tmp'; -import * as buildx from './buildx'; import * as core from '@actions/core'; -import * as github from '@actions/github'; import {parse} from 'csv-parse/sync'; import * as handlebars from 'handlebars'; - -let _defaultContext, _tmpDir: string; +import {Context} from '@docker/actions-toolkit/lib/context'; +import {GitHub} from '@docker/actions-toolkit/lib/github'; +import {Inputs as BuildxInputs} from '@docker/actions-toolkit/lib/buildx/inputs'; +import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; +import {Util} from '@docker/actions-toolkit/lib/util'; export interface Inputs { addHosts: string[]; @@ -43,105 +40,78 @@ export interface Inputs { githubToken: string; } -export function defaultContext(): string { - if (!_defaultContext) { - let ref = github.context.ref; - if (github.context.sha && ref && !ref.startsWith('refs/')) { - ref = `refs/heads/${github.context.ref}`; - } - if (github.context.sha && !ref.startsWith(`refs/pull/`)) { - ref = github.context.sha; - } - _defaultContext = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}.git#${ref}`; - } - return _defaultContext; -} - -export function tmpDir(): string { - if (!_tmpDir) { - _tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-build-push-')).split(path.sep).join(path.posix.sep); - } - return _tmpDir; -} - -export function tmpNameSync(options?: tmp.TmpNameOptions): string { - return tmp.tmpNameSync(options); -} - -export function provenanceBuilderID(): string { - return `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`; -} - -export async function getInputs(defaultContext: string): Promise { +export async function getInputs(): Promise { return { - addHosts: await getInputList('add-hosts'), - allow: await getInputList('allow'), - attests: await getInputList('attests', true), - buildArgs: await getInputList('build-args', true), - buildContexts: await getInputList('build-contexts', true), + addHosts: Util.getInputList('add-hosts'), + allow: Util.getInputList('allow'), + attests: Util.getInputList('attests', {ignoreComma: true}), + buildArgs: Util.getInputList('build-args', {ignoreComma: true}), + buildContexts: Util.getInputList('build-contexts', {ignoreComma: true}), builder: core.getInput('builder'), - cacheFrom: await getInputList('cache-from', true), - cacheTo: await getInputList('cache-to', true), + cacheFrom: Util.getInputList('cache-from', {ignoreComma: true}), + cacheTo: Util.getInputList('cache-to', {ignoreComma: true}), cgroupParent: core.getInput('cgroup-parent'), - context: core.getInput('context') || defaultContext, + context: core.getInput('context') || Context.gitContext(), file: core.getInput('file'), - labels: await getInputList('labels', true), + labels: Util.getInputList('labels', {ignoreComma: true}), load: core.getBooleanInput('load'), network: core.getInput('network'), noCache: core.getBooleanInput('no-cache'), - noCacheFilters: await getInputList('no-cache-filters'), - outputs: await getInputList('outputs', true), - platforms: await getInputList('platforms'), + noCacheFilters: Util.getInputList('no-cache-filters'), + outputs: Util.getInputList('outputs', {ignoreComma: true}), + platforms: Util.getInputList('platforms'), provenance: getProvenanceInput('provenance'), pull: core.getBooleanInput('pull'), push: core.getBooleanInput('push'), sbom: core.getInput('sbom'), - secrets: await getInputList('secrets', true), - secretFiles: await getInputList('secret-files', true), + secrets: Util.getInputList('secrets', {ignoreComma: true}), + secretFiles: Util.getInputList('secret-files', {ignoreComma: true}), shmSize: core.getInput('shm-size'), - ssh: await getInputList('ssh'), - tags: await getInputList('tags'), + ssh: Util.getInputList('ssh'), + tags: Util.getInputList('tags'), target: core.getInput('target'), - ulimit: await getInputList('ulimit', true), + ulimit: Util.getInputList('ulimit', {ignoreComma: true}), githubToken: core.getInput('github-token') }; } -export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string, standalone?: boolean): Promise> { - const context = handlebars.compile(inputs.context)({defaultContext}); +export async function getArgs(inputs: Inputs, toolkit: Toolkit): Promise> { + const context = handlebars.compile(inputs.context)({ + defaultContext: Context.gitContext() + }); // prettier-ignore return [ - ...await getBuildArgs(inputs, defaultContext, context, buildxVersion, standalone), - ...await getCommonArgs(inputs, buildxVersion), + ...await getBuildArgs(inputs, context, toolkit), + ...await getCommonArgs(inputs, toolkit), context ]; } -async function getBuildArgs(inputs: Inputs, defaultContext: string, context: string, buildxVersion: string, standalone?: boolean): Promise> { +async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit): Promise> { const args: Array = ['build']; - await asyncForEach(inputs.addHosts, async addHost => { + await Util.asyncForEach(inputs.addHosts, async addHost => { args.push('--add-host', addHost); }); if (inputs.allow.length > 0) { args.push('--allow', inputs.allow.join(',')); } - if (buildx.satisfies(buildxVersion, '>=0.10.0')) { - await asyncForEach(inputs.attests, async attest => { + if (await toolkit.buildx.versionSatisfies('>=0.10.0')) { + await Util.asyncForEach(inputs.attests, async attest => { args.push('--attest', attest); }); } - await asyncForEach(inputs.buildArgs, async buildArg => { + await Util.asyncForEach(inputs.buildArgs, async buildArg => { args.push('--build-arg', buildArg); }); - if (buildx.satisfies(buildxVersion, '>=0.8.0')) { - await asyncForEach(inputs.buildContexts, async buildContext => { + if (await toolkit.buildx.versionSatisfies('>=0.8.0')) { + await Util.asyncForEach(inputs.buildContexts, async buildContext => { args.push('--build-context', buildContext); }); } - await asyncForEach(inputs.cacheFrom, async cacheFrom => { + await Util.asyncForEach(inputs.cacheFrom, async cacheFrom => { args.push('--cache-from', cacheFrom); }); - await asyncForEach(inputs.cacheTo, async cacheTo => { + await Util.asyncForEach(inputs.cacheTo, async cacheTo => { args.push('--cache-to', cacheTo); }); if (inputs.cgroupParent) { @@ -150,29 +120,29 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str if (inputs.file) { args.push('--file', inputs.file); } - if (!buildx.isLocalOrTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || buildx.satisfies(buildxVersion, '>=0.4.2'))) { - args.push('--iidfile', await buildx.getImageIDFile()); + if (!BuildxInputs.hasLocalExporter(inputs.outputs) && !BuildxInputs.hasTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || (await toolkit.buildx.versionSatisfies('>=0.4.2')))) { + args.push('--iidfile', toolkit.buildx.inputs.getBuildImageIDFilePath()); } - await asyncForEach(inputs.labels, async label => { + await Util.asyncForEach(inputs.labels, async label => { args.push('--label', label); }); - await asyncForEach(inputs.noCacheFilters, async noCacheFilter => { + await Util.asyncForEach(inputs.noCacheFilters, async noCacheFilter => { args.push('--no-cache-filter', noCacheFilter); }); - await asyncForEach(inputs.outputs, async output => { + await Util.asyncForEach(inputs.outputs, async output => { args.push('--output', output); }); if (inputs.platforms.length > 0) { args.push('--platform', inputs.platforms.join(',')); } - if (buildx.satisfies(buildxVersion, '>=0.10.0')) { + if (await toolkit.buildx.versionSatisfies('>=0.10.0')) { if (inputs.provenance) { args.push('--provenance', inputs.provenance); - } else if ((await buildx.satisfiesBuildKitVersion(inputs.builder, '>=0.11.0', standalone)) && !hasDockerExport(inputs)) { + } else if ((await toolkit.buildkit.versionSatisfies(inputs.builder, '>=0.11.0')) && !BuildxInputs.hasDockerExporter(inputs.outputs, inputs.load)) { // if provenance not specified and BuildKit version compatible for // attestation, set default provenance. Also needs to make sure user // doesn't want to explicitly load the image to docker. - if (fromPayload('repository.private') !== false) { + if (GitHub.context.payload.repository?.private ?? false) { // if this is a private repository, we set the default provenance // attributes being set in buildx: https://github.com/docker/buildx/blob/fb27e3f919dcbf614d7126b10c2bc2d0b1927eb6/build/build.go#L603 args.push('--provenance', getProvenanceAttrs(`mode=min,inline-only=true`)); @@ -185,42 +155,42 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str args.push('--sbom', inputs.sbom); } } - await asyncForEach(inputs.secrets, async secret => { + await Util.asyncForEach(inputs.secrets, async secret => { try { - args.push('--secret', await buildx.getSecretString(secret)); + args.push('--secret', toolkit.buildx.inputs.resolveBuildSecretString(secret)); } catch (err) { core.warning(err.message); } }); - await asyncForEach(inputs.secretFiles, async secretFile => { + await Util.asyncForEach(inputs.secretFiles, async secretFile => { try { - args.push('--secret', await buildx.getSecretFile(secretFile)); + args.push('--secret', toolkit.buildx.inputs.resolveBuildSecretFile(secretFile)); } catch (err) { core.warning(err.message); } }); - if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && context.startsWith(defaultContext)) { - args.push('--secret', await buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); + if (inputs.githubToken && !BuildxInputs.hasGitAuthTokenSecret(inputs.secrets) && context.startsWith(Context.gitContext())) { + args.push('--secret', toolkit.buildx.inputs.resolveBuildSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); } if (inputs.shmSize) { args.push('--shm-size', inputs.shmSize); } - await asyncForEach(inputs.ssh, async ssh => { + await Util.asyncForEach(inputs.ssh, async ssh => { args.push('--ssh', ssh); }); - await asyncForEach(inputs.tags, async tag => { + await Util.asyncForEach(inputs.tags, async tag => { args.push('--tag', tag); }); if (inputs.target) { args.push('--target', inputs.target); } - await asyncForEach(inputs.ulimit, async ulimit => { + await Util.asyncForEach(inputs.ulimit, async ulimit => { args.push('--ulimit', ulimit); }); return args; } -async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise> { +async function getCommonArgs(inputs: Inputs, toolkit: Toolkit): Promise> { const args: Array = []; if (inputs.builder) { args.push('--builder', inputs.builder); @@ -228,8 +198,8 @@ async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise=0.6.0')) { - args.push('--metadata-file', await buildx.getMetadataFile()); + if (await toolkit.buildx.versionSatisfies('>=0.6.0')) { + args.push('--metadata-file', toolkit.buildx.inputs.getBuildMetadataFilePath()); } if (inputs.network) { args.push('--network', inputs.network); @@ -246,68 +216,14 @@ async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise { - const res: Array = []; - - const items = core.getInput(name); - if (items == '') { - return res; - } - - const records = await parse(items, { - columns: false, - relaxQuotes: true, - relaxColumnCount: true, - skipEmptyLines: true - }); - - for (const record of records as Array) { - if (record.length == 1) { - res.push(record[0]); - continue; - } else if (!ignoreComma) { - res.push(...record); - continue; - } - res.push(record.join(',')); - } - - return res.filter(item => item).map(pat => pat.trim()); -} - -export const asyncForEach = async (array, callback) => { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array); - } -}; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function fromPayload(path: string): any { - return select(github.context.payload, path); -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function select(obj: any, path: string): any { - if (!obj) { - return undefined; - } - const i = path.indexOf('.'); - if (i < 0) { - return obj[path]; - } - const key = path.slice(0, i); - return select(obj[key], path.slice(i + 1)); -} - function getProvenanceInput(name: string): string { const input = core.getInput(name); if (!input) { // if input is not set, default values will be set later. return input; } - const builderID = provenanceBuilderID(); try { - return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false'; + return core.getBooleanInput(name) ? `builder-id=${Context.provenanceBuilderID()}` : 'false'; } catch (err) { // not a valid boolean, so we assume it's a string return getProvenanceAttrs(input); @@ -315,7 +231,6 @@ function getProvenanceInput(name: string): string { } function getProvenanceAttrs(input: string): string { - const builderID = provenanceBuilderID(); // parse attributes from input const fields = parse(input, { relaxColumnCount: true, @@ -332,30 +247,5 @@ function getProvenanceAttrs(input: string): string { } } // if not add builder-id attribute - return `${input},builder-id=${builderID}`; -} - -function hasDockerExport(inputs: Inputs): boolean { - if (inputs.load) { - return true; - } - for (const output of inputs.outputs) { - const fields = parse(output, { - relaxColumnCount: true, - skipEmptyLines: true - })[0]; - for (const field of fields) { - const parts = field - .toString() - .split(/(?<=^[^=]+?)=/) - .map(item => item.trim()); - if (parts.length != 2) { - continue; - } - if (parts[0] == 'type' && parts[1] == 'docker') { - return true; - } - } - } - return false; + return `${input},builder-id=${Context.provenanceBuilderID()}`; } diff --git a/src/docker.ts b/src/docker.ts deleted file mode 100644 index 46497b2..0000000 --- a/src/docker.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as exec from '@actions/exec'; - -export async function isAvailable(): Promise { - return await exec - .getExecOutput('docker', undefined, { - ignoreReturnCode: true, - silent: true - }) - .then(res => { - if (res.stderr.length > 0 && res.exitCode != 0) { - return false; - } - return res.exitCode == 0; - }) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .catch(error => { - return false; - }); -} diff --git a/src/github.ts b/src/github.ts deleted file mode 100644 index a33d995..0000000 --- a/src/github.ts +++ /dev/null @@ -1,9 +0,0 @@ -import jwt_decode, {JwtPayload} from 'jwt-decode'; - -interface Jwt extends JwtPayload { - ac?: string; -} - -export const parseRuntimeToken = (token: string): Jwt => { - return jwt_decode(token); -}; diff --git a/src/main.ts b/src/main.ts index f6dda8d..ea470c5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,71 +1,62 @@ import * as fs from 'fs'; -import * as buildx from './buildx'; -import * as context from './context'; -import * as docker from './docker'; -import * as github from './github'; import * as stateHelper from './state-helper'; import * as core from '@actions/core'; -import * as exec from '@actions/exec'; +import * as actionsToolkit from '@docker/actions-toolkit'; +import {Context} from '@docker/actions-toolkit/lib/context'; +import {Docker} from '@docker/actions-toolkit/lib/docker'; +import {Exec} from '@docker/actions-toolkit/lib/exec'; +import {GitHub} from '@docker/actions-toolkit/lib/github'; +import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; -async function run(): Promise { - try { - const defContext = context.defaultContext(); - const inputs: context.Inputs = await context.getInputs(defContext); +import * as context from './context'; - // standalone if docker cli not available - const standalone = !(await docker.isAvailable()); +actionsToolkit.run( + // main + async () => { + const inputs: context.Inputs = await context.getInputs(); + const toolkit = new Toolkit(); - await core.group(`GitHub Actions runtime token access controls`, async () => { - const actionsRuntimeToken = process.env['ACTIONS_RUNTIME_TOKEN']; - if (actionsRuntimeToken) { - core.info(JSON.stringify(JSON.parse(github.parseRuntimeToken(actionsRuntimeToken).ac as string), undefined, 2)); - } else { - core.info(`ACTIONS_RUNTIME_TOKEN not set`); + await core.group(`GitHub Actions runtime token ACs`, async () => { + try { + await GitHub.printActionsRuntimeTokenACs(); + } catch (e) { + core.warning(e.message); } }); - core.startGroup(`Docker info`); - if (standalone) { - core.info(`Docker info skipped in standalone mode`); - } else { - await exec.exec('docker', ['version'], { - failOnStdErr: false - }); - await exec.exec('docker', ['info'], { - failOnStdErr: false - }); - } - core.endGroup(); + await core.group(`Docker info`, async () => { + try { + await Docker.printVersion(); + await Docker.printInfo(); + } catch (e) { + core.info(e.message); + } + }); - if (!(await buildx.isAvailable(standalone))) { + if (!(await toolkit.buildx.isAvailable())) { core.setFailed(`Docker buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`); return; } - stateHelper.setTmpDir(context.tmpDir()); - const buildxVersion = await buildx.getVersion(standalone); + stateHelper.setTmpDir(Context.tmpDir()); + await core.group(`Buildx version`, async () => { - const versionCmd = buildx.getCommand(['version'], standalone); - await exec.exec(versionCmd.command, versionCmd.args, { - failOnStdErr: false - }); + await toolkit.buildx.printVersion(); }); - const args: string[] = await context.getArgs(inputs, defContext, buildxVersion, standalone); - const buildCmd = buildx.getCommand(args, standalone); - await exec - .getExecOutput(buildCmd.command, buildCmd.args, { - ignoreReturnCode: true - }) - .then(res => { - if (res.stderr.length > 0 && res.exitCode != 0) { - throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); - } - }); + const args: string[] = await context.getArgs(inputs, toolkit); + const buildCmd = await toolkit.buildx.getCommand(args); + await Exec.getExecOutput(buildCmd.command, buildCmd.args, { + ignoreReturnCode: true + }).then(res => { + if (res.stderr.length > 0 && res.exitCode != 0) { + throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); + } + }); - const imageID = await buildx.getImageID(); - const metadata = await buildx.getMetadata(); - const digest = await buildx.getDigest(metadata); + const imageID = await toolkit.buildx.inputs.resolveBuildImageID(); + const metadata = await toolkit.buildx.inputs.resolveBuildMetadata(); + const digest = await toolkit.buildx.inputs.resolveDigest(); if (imageID) { await core.group(`ImageID`, async () => { @@ -85,21 +76,13 @@ async function run(): Promise { core.setOutput('metadata', metadata); }); } - } catch (error) { - core.setFailed(error.message); + }, + // post + async () => { + if (stateHelper.tmpDir.length > 0) { + await core.group(`Removing temp folder ${stateHelper.tmpDir}`, async () => { + fs.rmSync(stateHelper.tmpDir, {recursive: true}); + }); + } } -} - -async function cleanup(): Promise { - if (stateHelper.tmpDir.length > 0) { - core.startGroup(`Removing temp folder ${stateHelper.tmpDir}`); - fs.rmSync(stateHelper.tmpDir, {recursive: true}); - core.endGroup(); - } -} - -if (!stateHelper.IsPost) { - run(); -} else { - cleanup(); -} +); diff --git a/src/state-helper.ts b/src/state-helper.ts index b04c859..01c11be 100644 --- a/src/state-helper.ts +++ b/src/state-helper.ts @@ -1,12 +1,7 @@ import * as core from '@actions/core'; -export const IsPost = !!process.env['STATE_isPost']; export const tmpDir = process.env['STATE_tmpDir'] || ''; export function setTmpDir(tmpDir: string) { core.saveState('tmpDir', tmpDir); } - -if (!IsPost) { - core.saveState('isPost', 'true'); -} diff --git a/tsconfig.json b/tsconfig.json index 7339491..9720dc0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,22 @@ { "compilerOptions": { + "esModuleInterop": true, "target": "es6", "module": "commonjs", + "strict": true, "newLine": "lf", "outDir": "./lib", "rootDir": "./src", - "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "strict": true, "noImplicitAny": false, + "resolveJsonModule": true, "useUnknownInCatchVariables": false, }, "exclude": [ + "./__mocks__/**/*", + "./__tests__/**/*", + "./lib/**/*", "node_modules", - "**/*.test.ts", "jest.config.ts" ] } diff --git a/yarn.lock b/yarn.lock index 9dbb08f..256c552 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@actions/core@^1.10.0": +"@actions/core@^1.10.0", "@actions/core@^1.2.6": version "1.10.0" resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.10.0.tgz#44551c3c71163949a2f06e94d9ca2157a0cfac4f" integrity sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug== @@ -10,7 +10,7 @@ "@actions/http-client" "^2.0.1" uuid "^8.3.2" -"@actions/exec@^1.1.1": +"@actions/exec@^1.0.0", "@actions/exec@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@actions/exec/-/exec-1.1.1.tgz#2e43f28c54022537172819a7cf886c844221a611" integrity sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w== @@ -39,6 +39,23 @@ resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.0.2.tgz#2f614b6e69ce14d191180451eb38e6576a6e6b27" integrity sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg== +"@actions/io@^1.1.1", "@actions/io@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.1.2.tgz#766ac09674a289ce0f1550ffe0a6eac9261a8ea9" + integrity sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw== + +"@actions/tool-cache@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@actions/tool-cache/-/tool-cache-2.0.1.tgz#8a649b9c07838d9d750c9864814e66a7660ab720" + integrity sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA== + dependencies: + "@actions/core" "^1.2.6" + "@actions/exec" "^1.0.0" + "@actions/http-client" "^2.0.1" + "@actions/io" "^1.1.1" + semver "^6.1.0" + uuid "^3.3.2" + "@ampproject/remapping@^2.1.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" @@ -546,6 +563,22 @@ dependencies: "@cspotcode/source-map-consumer" "0.8.0" +"@docker/actions-toolkit@^0.1.0-beta.14": + version "0.1.0-beta.14" + resolved "https://registry.yarnpkg.com/@docker/actions-toolkit/-/actions-toolkit-0.1.0-beta.14.tgz#82fa8a6b9802a7f770fde3ddcef1cf591739a80b" + integrity sha512-N+aqiO0E2ygoaBORN8fx4K7j/CzJ2nCSgOewtDm0gdzrch8qZmTU14e3oNAbZlP8Q34Lk45KKefm5wDfLipRqg== + dependencies: + "@actions/core" "^1.10.0" + "@actions/exec" "^1.1.1" + "@actions/github" "^5.1.1" + "@actions/http-client" "^2.0.1" + "@actions/io" "^1.1.2" + "@actions/tool-cache" "^2.0.1" + csv-parse "^5.3.5" + jwt-decode "^3.1.2" + semver "^7.3.8" + tmp "^0.2.1" + "@eslint/eslintrc@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" @@ -1077,21 +1110,11 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== -"@types/semver@^7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc" - integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ== - "@types/stack-utils@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== -"@types/tmp@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.3.tgz#908bfb113419fd6a42273674c00994d40902c165" - integrity sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA== - "@types/yargs-parser@*": version "20.2.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" @@ -1701,11 +1724,6 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" -dotenv@^16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411" - integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q== - electron-to-chromium@^1.3.723: version "1.3.755" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.755.tgz#4b6101f13de910cf3f0a1789ddc57328133b9332" @@ -3275,18 +3293,25 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -semver@7.x, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: +semver@7.x, semver@^7.3.2, semver@^7.3.5: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3624,6 +3649,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"