Compare commits
No commits in common. 'master' and 'v1' have entirely different histories.
@ -1,12 +1,2 @@
|
|||||||
/coverage
|
/coverage
|
||||||
|
/node_modules
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
/dist/**
|
|
||||||
/coverage/**
|
|
||||||
/node_modules/**
|
|
||||||
@ -1,4 +1,2 @@
|
|||||||
/.yarn/releases/** binary
|
|
||||||
/.yarn/plugins/** binary
|
|
||||||
/dist/** linguist-generated=true
|
/dist/** linguist-generated=true
|
||||||
/lib/** linguist-generated=true
|
/lib/** linguist-generated=true
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
* @crazy-max
|
||||||
@ -1,3 +0,0 @@
|
|||||||
# Code of conduct
|
|
||||||
|
|
||||||
- [Moby community guidelines](https://github.com/moby/moby/blob/master/CONTRIBUTING.md#moby-community-guidelines)
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
|
||||||
name: Bug Report
|
|
||||||
description: Report a bug
|
|
||||||
labels:
|
|
||||||
- status/triage
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thank you for taking the time to report a bug!
|
|
||||||
If this is a security issue please report it to the [Docker Security team](mailto:security@docker.com).
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Contributing guidelines
|
|
||||||
description: >
|
|
||||||
Make sure you've read the contributing guidelines before proceeding.
|
|
||||||
options:
|
|
||||||
- label: I've read the [contributing guidelines](https://github.com/docker/setup-buildx-action/blob/master/.github/CONTRIBUTING.md) and wholeheartedly agree
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: "I've found a bug, and:"
|
|
||||||
description: |
|
|
||||||
Make sure that your request fulfills all of the following requirements.
|
|
||||||
If one requirement cannot be satisfied, explain in detail why.
|
|
||||||
options:
|
|
||||||
- label: The documentation does not mention anything about my problem
|
|
||||||
- label: There are no open or closed issues that are related to my problem
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: >
|
|
||||||
Provide a brief description of the bug in 1-2 sentences.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Expected behaviour
|
|
||||||
description: >
|
|
||||||
Describe precisely what you'd expect to happen.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Actual behaviour
|
|
||||||
description: >
|
|
||||||
Describe precisely what is actually happening.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Repository URL
|
|
||||||
description: >
|
|
||||||
Enter the URL of the repository where you are experiencing the
|
|
||||||
issue. If your repository is private, provide a link to a minimal
|
|
||||||
repository that reproduces the issue.
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Workflow run URL
|
|
||||||
description: >
|
|
||||||
Enter the URL of the GitHub Action workflow run if public (e.g.
|
|
||||||
`https://github.com/<user>/<repo>/actions/runs/<id>`)
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: YAML workflow
|
|
||||||
description: |
|
|
||||||
Provide the YAML of the workflow that's causing the issue.
|
|
||||||
Make sure to remove any sensitive information.
|
|
||||||
render: yaml
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Workflow logs
|
|
||||||
description: >
|
|
||||||
[Attach](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files)
|
|
||||||
the [log file of your workflow run](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
|
|
||||||
and make sure to remove any sensitive information.
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: BuildKit logs
|
|
||||||
description: >
|
|
||||||
If applicable, provide the [BuildKit container logs](https://docs.docker.com/build/ci/github-actions/configure-builder/#buildkit-container-logs)
|
|
||||||
render: text
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional info
|
|
||||||
description: |
|
|
||||||
Provide any additional information that could be useful.
|
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
---
|
||||||
|
|
||||||
|
### Behaviour
|
||||||
|
|
||||||
|
#### Steps to reproduce this issue
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
#### Expected behaviour
|
||||||
|
|
||||||
|
> Tell us what should happen
|
||||||
|
|
||||||
|
#### Actual behaviour
|
||||||
|
|
||||||
|
> Tell us what happens instead
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
* Repository URL (if public):
|
||||||
|
* Build URL (if public):
|
||||||
|
|
||||||
|
```yml
|
||||||
|
# paste your YAML workflow file here and remove sensitive data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logs
|
||||||
|
|
||||||
|
> Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
|
||||||
|
> and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.
|
||||||
@ -1,9 +0,0 @@
|
|||||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
|
|
||||||
blank_issues_enabled: true
|
|
||||||
contact_links:
|
|
||||||
- name: Questions and Discussions
|
|
||||||
url: https://github.com/docker/setup-buildx-action/discussions/new
|
|
||||||
about: Use Github Discussions to ask questions and/or open discussion topics.
|
|
||||||
- name: Documentation
|
|
||||||
url: https://docs.docker.com/build/ci/github-actions/
|
|
||||||
about: Read the documentation.
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
|
||||||
name: Feature request
|
|
||||||
description: Missing functionality? Come tell us about it!
|
|
||||||
labels:
|
|
||||||
- kind/enhancement
|
|
||||||
- status/triage
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: What is the feature you want to see?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
# Reporting security issues
|
|
||||||
|
|
||||||
The project maintainers take security seriously. If you discover a security
|
|
||||||
issue, please bring it to their attention right away!
|
|
||||||
|
|
||||||
**Please _DO NOT_ file a public issue**, instead send your report privately to
|
|
||||||
[security@docker.com](mailto:security@docker.com).
|
|
||||||
|
|
||||||
Security reports are greatly appreciated, and we will publicly thank you for it.
|
|
||||||
We also like to send gifts—if you'd like Docker swag, make sure to let
|
|
||||||
us know. We currently do not offer a paid security bounty program, but are not
|
|
||||||
ruling it out in the future.
|
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
# Support [](https://isitmaintained.com/project/docker/setup-buildx-action)
|
||||||
|
|
||||||
|
First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md).
|
||||||
|
|
||||||
|
## Reporting an issue
|
||||||
|
|
||||||
|
Please do a search in [open issues](https://github.com/docker/setup-buildx-action/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed.
|
||||||
|
|
||||||
|
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment.
|
||||||
|
|
||||||
|
:+1: - upvote
|
||||||
|
|
||||||
|
:-1: - downvote
|
||||||
|
|
||||||
|
If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.
|
||||||
|
|
||||||
|
## Writing good bug reports and feature requests
|
||||||
|
|
||||||
|
File a single issue per problem and feature request.
|
||||||
|
|
||||||
|
* Do not enumerate multiple bugs or feature requests in the same issue.
|
||||||
|
* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
|
||||||
|
|
||||||
|
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
|
||||||
|
|
||||||
|
You are now ready to [create a new issue](https://github.com/docker/setup-buildx-action/issues/new/choose)!
|
||||||
|
|
||||||
|
## Closure policy
|
||||||
|
|
||||||
|
* Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines.
|
||||||
|
* Issues that go a week without a response from original poster are subject to closure at our discretion.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
@ -1,17 +0,0 @@
|
|||||||
name: pr-assign-author
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run:
|
|
||||||
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@1b673f36fad86812f538c1df9794904038a23cbf
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
name: publish
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types:
|
|
||||||
- published
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
packages: write
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
-
|
|
||||||
name: Publish
|
|
||||||
uses: actions/publish-immutable-action@v0.0.4
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
name: validate
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
- 'releases/v*'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
prepare:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
targets: ${{ steps.generate.outputs.targets }}
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
-
|
|
||||||
name: List targets
|
|
||||||
id: generate
|
|
||||||
uses: docker/bake-action/subaction/list-targets@v6
|
|
||||||
with:
|
|
||||||
target: validate
|
|
||||||
|
|
||||||
validate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- prepare
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
target: ${{ fromJson(needs.prepare.outputs.targets) }}
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Validate
|
|
||||||
uses: docker/bake-action@v6
|
|
||||||
with:
|
|
||||||
targets: ${{ matrix.target }}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
# https://yarnpkg.com/configuration/yarnrc
|
|
||||||
|
|
||||||
compressionLevel: mixed
|
|
||||||
enableGlobalCache: false
|
|
||||||
enableHardenedMode: true
|
|
||||||
|
|
||||||
logFilters:
|
|
||||||
- code: YN0013
|
|
||||||
level: discard
|
|
||||||
- code: YN0019
|
|
||||||
level: discard
|
|
||||||
- code: YN0076
|
|
||||||
level: discard
|
|
||||||
- code: YN0086
|
|
||||||
level: discard
|
|
||||||
|
|
||||||
nodeLinker: node-modules
|
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as buildx from '../src/buildx';
|
||||||
|
import * as context from '../src/context';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
const tmpNameSync = path.join('/tmp/.docker-setup-buildx-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||||
|
|
||||||
|
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||||
|
const tmpDir = path.join('/tmp/.docker-setup-buildx-jest').split(path.sep).join(path.posix.sep);
|
||||||
|
if (!fs.existsSync(tmpDir)) {
|
||||||
|
fs.mkdirSync(tmpDir, {recursive: true});
|
||||||
|
}
|
||||||
|
return tmpDir;
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
|
||||||
|
return tmpNameSync;
|
||||||
|
});
|
||||||
|
|
||||||
|
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('inspect', () => {
|
||||||
|
it('valid', async () => {
|
||||||
|
const builder = await buildx.inspect('');
|
||||||
|
expect(builder).not.toBeUndefined();
|
||||||
|
expect(builder.name).not.toEqual('');
|
||||||
|
expect(builder.driver).not.toEqual('');
|
||||||
|
expect(builder.node_platforms).not.toEqual('');
|
||||||
|
}, 100000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('build', () => {
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
|
||||||
|
|
||||||
|
// eslint-disable-next-line jest/no-disabled-tests
|
||||||
|
it.skip('builds refs/pull/648/head', async () => {
|
||||||
|
const buildxBin = await buildx.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir, false);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
// eslint-disable-next-line jest/no-disabled-tests
|
||||||
|
it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
|
||||||
|
const buildxBin = await buildx.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir, false);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
}, 100000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('install', () => {
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-buildx-'));
|
||||||
|
test.each([
|
||||||
|
['v0.4.1', false],
|
||||||
|
['latest', false],
|
||||||
|
['v0.4.1', true],
|
||||||
|
['latest', true]
|
||||||
|
])(
|
||||||
|
'acquires %p of buildx (standalone: %p)',
|
||||||
|
async (version, standalone) => {
|
||||||
|
const buildxBin = await buildx.install(version, tmpDir, standalone);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getConfig', () => {
|
||||||
|
test.each([
|
||||||
|
['debug = true', false, 'debug = true', false],
|
||||||
|
[`notfound.toml`, true, '', true],
|
||||||
|
[
|
||||||
|
`${path.join(__dirname, 'fixtures', 'buildkitd.toml').split(path.sep).join(path.posix.sep)}`,
|
||||||
|
true,
|
||||||
|
`debug = true
|
||||||
|
[registry."docker.io"]
|
||||||
|
mirrors = ["mirror.gcr.io"]
|
||||||
|
`,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
])('given %p config', async (val, file, exValue, invalid) => {
|
||||||
|
try {
|
||||||
|
let config: string;
|
||||||
|
if (file) {
|
||||||
|
config = await buildx.getConfigFile(val);
|
||||||
|
} else {
|
||||||
|
config = await buildx.getConfigInline(val);
|
||||||
|
}
|
||||||
|
expect(true).toBe(!invalid);
|
||||||
|
expect(config).toEqual(`${tmpNameSync}`);
|
||||||
|
const configValue = fs.readFileSync(tmpNameSync, 'utf-8');
|
||||||
|
expect(configValue).toEqual(exValue);
|
||||||
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
|
expect(true).toBe(invalid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1 +1,3 @@
|
|||||||
debug = true
|
debug = true
|
||||||
|
[registry."docker.io"]
|
||||||
|
mirrors = ["mirror.gcr.io"]
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
import {describe, expect, it} from '@jest/globals';
|
||||||
|
import * as git from '../src/git';
|
||||||
|
|
||||||
|
describe('git', () => {
|
||||||
|
it('returns git remote ref', async () => {
|
||||||
|
const ref: string = await git.getRemoteSha('https://github.com/docker/buildx.git', 'refs/pull/648/head');
|
||||||
|
expect(ref).toEqual('f11797113e5a9b86bd976329c5dbb8a8bfdfadfa');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
import {describe, expect, it} from '@jest/globals';
|
||||||
|
import * as github from '../src/github';
|
||||||
|
|
||||||
|
describe('github', () => {
|
||||||
|
it('returns latest buildx GitHub release', async () => {
|
||||||
|
const release = await github.getRelease('latest');
|
||||||
|
expect(release).not.toBeNull();
|
||||||
|
expect(release?.tag_name).not.toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns v0.2.2 buildx GitHub release', async () => {
|
||||||
|
const release = await github.getRelease('v0.2.2');
|
||||||
|
expect(release).not.toBeNull();
|
||||||
|
expect(release?.tag_name).toEqual('v0.2.2');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import {describe, expect, test} from '@jest/globals';
|
||||||
|
import * as util from '../src/util';
|
||||||
|
|
||||||
|
describe('isValidUrl', () => {
|
||||||
|
test.each([
|
||||||
|
['https://github.com/docker/buildx.git', true],
|
||||||
|
['https://github.com/docker/buildx.git#refs/pull/648/head', true],
|
||||||
|
['v0.4.1', false]
|
||||||
|
])('given %p', async (url, expected) => {
|
||||||
|
expect(util.isValidUrl(url)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,29 +1,10 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-action-')).split(path.sep).join(path.posix.sep);
|
|
||||||
|
|
||||||
process.env = Object.assign({}, process.env, {
|
|
||||||
TEMP: tmpDir,
|
|
||||||
GITHUB_REPOSITORY: 'docker/setup-buildx-action',
|
|
||||||
RUNNER_TEMP: path.join(tmpDir, 'runner-temp').split(path.sep).join(path.posix.sep),
|
|
||||||
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache').split(path.sep).join(path.posix.sep)
|
|
||||||
}) as {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
clearMocks: true,
|
clearMocks: true,
|
||||||
moduleFileExtensions: ['js', 'ts'],
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
setupFiles: ["dotenv/config"],
|
||||||
testMatch: ['**/*.test.ts'],
|
testMatch: ['**/*.test.ts'],
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.ts$': 'ts-jest'
|
'^.+\\.ts$': 'ts-jest'
|
||||||
},
|
},
|
||||||
moduleNameMapper: {
|
|
||||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
|
||||||
},
|
|
||||||
collectCoverageFrom: ['src/**/{!(main.ts),}.ts'],
|
|
||||||
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__tests__/'],
|
|
||||||
verbose: true
|
verbose: true
|
||||||
};
|
}
|
||||||
|
|||||||
@ -0,0 +1,337 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as util from 'util';
|
||||||
|
import * as context from './context';
|
||||||
|
import * as git from './git';
|
||||||
|
import * as github from './github';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
|
||||||
|
export type Builder = {
|
||||||
|
name?: string;
|
||||||
|
driver?: string;
|
||||||
|
node_name?: string;
|
||||||
|
node_endpoint?: string;
|
||||||
|
node_status?: string;
|
||||||
|
node_flags?: string;
|
||||||
|
node_platforms?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getConfigInline(s: string): Promise<string> {
|
||||||
|
return getConfig(s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getConfigFile(s: string): Promise<string> {
|
||||||
|
return getConfig(s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getConfig(s: string, file: boolean): Promise<string> {
|
||||||
|
if (file) {
|
||||||
|
if (!fs.existsSync(s)) {
|
||||||
|
throw new Error(`config file ${s} not found`);
|
||||||
|
}
|
||||||
|
s = fs.readFileSync(s, {encoding: 'utf-8'});
|
||||||
|
}
|
||||||
|
const configFile = context.tmpNameSync({
|
||||||
|
tmpdir: context.tmpDir()
|
||||||
|
});
|
||||||
|
fs.writeFileSync(configFile, s);
|
||||||
|
return configFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function isAvailable(standalone?: boolean): Promise<boolean> {
|
||||||
|
const cmd = getCommand([], standalone);
|
||||||
|
return await exec
|
||||||
|
.getExecOutput(cmd.commandLine, 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 getVersion(standalone?: boolean): Promise<string> {
|
||||||
|
const cmd = getCommand(['version'], standalone);
|
||||||
|
return await exec
|
||||||
|
.getExecOutput(cmd.commandLine, 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 async function inspect(name: string, standalone?: boolean): Promise<Builder> {
|
||||||
|
const cmd = getCommand(['inspect', name], standalone);
|
||||||
|
return await exec
|
||||||
|
.getExecOutput(cmd.commandLine, cmd.args, {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr.trim());
|
||||||
|
}
|
||||||
|
const builder: Builder = {};
|
||||||
|
itlines: for (const line of res.stdout.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) {
|
||||||
|
case 'Name': {
|
||||||
|
if (builder.name == undefined) {
|
||||||
|
builder.name = value;
|
||||||
|
} else {
|
||||||
|
builder.node_name = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Driver': {
|
||||||
|
builder.driver = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Endpoint': {
|
||||||
|
builder.node_endpoint = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Status': {
|
||||||
|
builder.node_status = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Flags': {
|
||||||
|
builder.node_flags = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'Platforms': {
|
||||||
|
builder.node_platforms = value.replace(/\s/g, '');
|
||||||
|
break itlines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function build(inputBuildRef: string, dest: string, standalone: boolean): Promise<string> {
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let [repo, ref] = inputBuildRef.split('#');
|
||||||
|
if (ref.length == 0) {
|
||||||
|
ref = 'master';
|
||||||
|
}
|
||||||
|
|
||||||
|
let vspec: string;
|
||||||
|
if (ref.match(/^[0-9a-fA-F]{40}$/)) {
|
||||||
|
vspec = ref;
|
||||||
|
} else {
|
||||||
|
vspec = await git.getRemoteSha(repo, ref);
|
||||||
|
}
|
||||||
|
core.debug(`Tool version spec ${vspec}`);
|
||||||
|
|
||||||
|
let toolPath: string;
|
||||||
|
toolPath = tc.find('buildx', vspec);
|
||||||
|
if (!toolPath) {
|
||||||
|
const outFolder = path.join(context.tmpDir(), 'out').split(path.sep).join(path.posix.sep);
|
||||||
|
let buildWithStandalone = false;
|
||||||
|
const standaloneFound = await isAvailable(true);
|
||||||
|
const pluginFound = await isAvailable(false);
|
||||||
|
if (standalone && standaloneFound) {
|
||||||
|
core.debug(`Buildx standalone found, build with it`);
|
||||||
|
buildWithStandalone = true;
|
||||||
|
} else if (!standalone && pluginFound) {
|
||||||
|
core.debug(`Buildx plugin found, build with it`);
|
||||||
|
buildWithStandalone = false;
|
||||||
|
} else if (standaloneFound) {
|
||||||
|
core.debug(`Buildx plugin not found, but standalone found so trying to build with it`);
|
||||||
|
buildWithStandalone = true;
|
||||||
|
} else if (pluginFound) {
|
||||||
|
core.debug(`Buildx standalone not found, but plugin found so trying to build with it`);
|
||||||
|
buildWithStandalone = false;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Neither buildx standalone or plugin have been found to build from ref`);
|
||||||
|
}
|
||||||
|
const buildCmd = getCommand(['build', '--target', 'binaries', '--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1', '--output', `type=local,dest=${outFolder}`, inputBuildRef], buildWithStandalone);
|
||||||
|
toolPath = await exec
|
||||||
|
.getExecOutput(buildCmd.commandLine, buildCmd.args, {
|
||||||
|
ignoreReturnCode: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
core.warning(res.stderr.trim());
|
||||||
|
}
|
||||||
|
return tc.cacheFile(`${outFolder}/buildx`, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (standalone) {
|
||||||
|
return setStandalone(toolPath, dest);
|
||||||
|
}
|
||||||
|
return setPlugin(toolPath, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function install(inputVersion: string, dest: string, standalone: boolean): Promise<string> {
|
||||||
|
const release: github.GitHubRelease | null = await github.getRelease(inputVersion);
|
||||||
|
if (!release) {
|
||||||
|
throw new Error(`Cannot find buildx ${inputVersion} release`);
|
||||||
|
}
|
||||||
|
core.debug(`Release ${release.tag_name} found`);
|
||||||
|
const version = release.tag_name.replace(/^v+|v+$/g, '');
|
||||||
|
|
||||||
|
let toolPath: string;
|
||||||
|
toolPath = tc.find('buildx', version);
|
||||||
|
if (!toolPath) {
|
||||||
|
const c = semver.clean(version) || '';
|
||||||
|
if (!semver.valid(c)) {
|
||||||
|
throw new Error(`Invalid Buildx version "${version}".`);
|
||||||
|
}
|
||||||
|
toolPath = await download(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (standalone) {
|
||||||
|
return setStandalone(toolPath, dest);
|
||||||
|
}
|
||||||
|
return setPlugin(toolPath, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setStandalone(toolPath: string, dest: string): Promise<string> {
|
||||||
|
core.info('Standalone mode');
|
||||||
|
const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||||
|
|
||||||
|
const binDir = path.join(dest, 'bin');
|
||||||
|
core.debug(`Bin dir is ${binDir}`);
|
||||||
|
if (!fs.existsSync(binDir)) {
|
||||||
|
fs.mkdirSync(binDir, {recursive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename: string = context.osPlat == 'win32' ? 'buildx.exe' : 'buildx';
|
||||||
|
const buildxPath: string = path.join(binDir, filename);
|
||||||
|
core.debug(`Bin path is ${buildxPath}`);
|
||||||
|
fs.copyFileSync(toolBinPath, buildxPath);
|
||||||
|
|
||||||
|
core.info('Fixing perms');
|
||||||
|
fs.chmodSync(buildxPath, '0755');
|
||||||
|
|
||||||
|
core.addPath(binDir);
|
||||||
|
core.info('Added buildx to the path');
|
||||||
|
|
||||||
|
return buildxPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setPlugin(toolPath: string, dockerConfigHome: string): Promise<string> {
|
||||||
|
core.info('Docker plugin mode');
|
||||||
|
const toolBinPath = path.join(toolPath, context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||||
|
|
||||||
|
const pluginsDir: string = path.join(dockerConfigHome, 'cli-plugins');
|
||||||
|
core.debug(`Plugins dir is ${pluginsDir}`);
|
||||||
|
if (!fs.existsSync(pluginsDir)) {
|
||||||
|
fs.mkdirSync(pluginsDir, {recursive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||||
|
const pluginPath: string = path.join(pluginsDir, filename);
|
||||||
|
core.debug(`Plugin path is ${pluginPath}`);
|
||||||
|
fs.copyFileSync(toolBinPath, pluginPath);
|
||||||
|
|
||||||
|
core.info('Fixing perms');
|
||||||
|
fs.chmodSync(pluginPath, '0755');
|
||||||
|
|
||||||
|
return pluginPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function download(version: string): Promise<string> {
|
||||||
|
const targetFile: string = context.osPlat == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||||
|
const downloadUrl = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, await filename(version));
|
||||||
|
core.info(`Downloading ${downloadUrl}`);
|
||||||
|
const downloadPath = await tc.downloadTool(downloadUrl);
|
||||||
|
core.debug(`Downloaded to ${downloadPath}`);
|
||||||
|
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function filename(version: string): Promise<string> {
|
||||||
|
let arch: string;
|
||||||
|
switch (context.osArch) {
|
||||||
|
case 'x64': {
|
||||||
|
arch = 'amd64';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'ppc64': {
|
||||||
|
arch = 'ppc64le';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'arm': {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const arm_version = (process.config.variables as any).arm_version;
|
||||||
|
arch = arm_version ? 'arm-v' + arm_version : 'arm';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
arch = context.osArch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const platform: string = context.osPlat == 'win32' ? 'windows' : context.osPlat;
|
||||||
|
const ext: string = context.osPlat == 'win32' ? '.exe' : '';
|
||||||
|
return util.format('buildx-v%s.%s-%s%s', version, platform, arch, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getBuildKitVersion(containerID: string): Promise<string> {
|
||||||
|
return exec
|
||||||
|
.getExecOutput(`docker`, ['inspect', '--format', '{{.Config.Image}}', containerID], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(bkitimage => {
|
||||||
|
if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) {
|
||||||
|
return exec
|
||||||
|
.getExecOutput(`docker`, ['run', '--rm', bkitimage.stdout.trim(), '--version'], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(bkitversion => {
|
||||||
|
if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) {
|
||||||
|
return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`;
|
||||||
|
} else if (bkitversion.stderr.length > 0) {
|
||||||
|
core.warning(bkitversion.stderr.trim());
|
||||||
|
}
|
||||||
|
return bkitversion.stdout.trim();
|
||||||
|
});
|
||||||
|
} else if (bkitimage.stderr.length > 0) {
|
||||||
|
core.warning(bkitimage.stderr.trim());
|
||||||
|
}
|
||||||
|
return bkitimage.stdout.trim();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCommand(args: Array<string>, standalone?: boolean) {
|
||||||
|
return {
|
||||||
|
commandLine: standalone ? 'buildx' : 'docker',
|
||||||
|
args: standalone ? args : ['buildx', ...args]
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,134 +1,69 @@
|
|||||||
import * as crypto from 'crypto';
|
import fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
import * as tmp from 'tmp';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import {issueCommand} from '@actions/core/lib/command';
|
||||||
|
|
||||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
|
let _tmpDir: string;
|
||||||
import {Util} from '@docker/actions-toolkit/lib/util';
|
export const osPlat: string = os.platform();
|
||||||
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
|
export const osArch: string = os.arch();
|
||||||
|
|
||||||
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder';
|
export function tmpDir(): string {
|
||||||
|
if (!_tmpDir) {
|
||||||
|
_tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-setup-buildx-')).split(path.sep).join(path.posix.sep);
|
||||||
|
}
|
||||||
|
return _tmpDir;
|
||||||
|
}
|
||||||
|
|
||||||
export const builderNodeEnvPrefix = 'BUILDER_NODE';
|
export function tmpNameSync(options?: tmp.TmpNameOptions): string {
|
||||||
const defaultBuildkitdFlags = '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host';
|
return tmp.tmpNameSync(options);
|
||||||
|
}
|
||||||
|
|
||||||
export interface Inputs {
|
export interface Inputs {
|
||||||
version: string;
|
version: string;
|
||||||
name: string;
|
|
||||||
driver: string;
|
driver: string;
|
||||||
driverOpts: string[];
|
driverOpts: string[];
|
||||||
buildkitdFlags: string;
|
buildkitdFlags: string;
|
||||||
buildkitdConfig: string;
|
|
||||||
buildkitdConfigInline: string;
|
|
||||||
platforms: string[];
|
|
||||||
install: boolean;
|
install: boolean;
|
||||||
use: boolean;
|
use: boolean;
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
append: string;
|
config: string;
|
||||||
cacheBinary: boolean;
|
configInline: string;
|
||||||
cleanup: boolean;
|
|
||||||
keepState: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getInputs(): Promise<Inputs> {
|
export async function getInputs(): Promise<Inputs> {
|
||||||
return {
|
return {
|
||||||
version: core.getInput('version'),
|
version: core.getInput('version'),
|
||||||
name: await getBuilderName(core.getInput('name'), core.getInput('driver') || 'docker-container'),
|
|
||||||
driver: core.getInput('driver') || 'docker-container',
|
driver: core.getInput('driver') || 'docker-container',
|
||||||
driverOpts: Util.getInputList('driver-opts', {ignoreComma: true, quote: false}),
|
driverOpts: await getInputList('driver-opts', true),
|
||||||
buildkitdFlags: core.getInput('buildkitd-flags'),
|
buildkitdFlags: core.getInput('buildkitd-flags') || '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||||
platforms: Util.getInputList('platforms'),
|
|
||||||
install: core.getBooleanInput('install'),
|
install: core.getBooleanInput('install'),
|
||||||
use: core.getBooleanInput('use'),
|
use: core.getBooleanInput('use'),
|
||||||
endpoint: core.getInput('endpoint'),
|
endpoint: core.getInput('endpoint'),
|
||||||
buildkitdConfig: core.getInput('buildkitd-config') || core.getInput('config'),
|
config: core.getInput('config'),
|
||||||
buildkitdConfigInline: core.getInput('buildkitd-config-inline') || core.getInput('config-inline'),
|
configInline: core.getInput('config-inline')
|
||||||
append: core.getInput('append'),
|
|
||||||
keepState: core.getBooleanInput('keep-state'),
|
|
||||||
cacheBinary: core.getBooleanInput('cache-binary'),
|
|
||||||
cleanup: core.getBooleanInput('cleanup')
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getBuilderName(name: string, driver: string): Promise<string> {
|
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
|
||||||
return driver == 'docker' ? await Docker.context() : name || `builder-${crypto.randomUUID()}`;
|
const items = core.getInput(name);
|
||||||
}
|
if (items == '') {
|
||||||
|
return [];
|
||||||
export async function getCreateArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
|
|
||||||
const args: Array<string> = ['create', '--name', inputs.name, '--driver', inputs.driver];
|
|
||||||
if (await toolkit.buildx.versionSatisfies('>=0.3.0')) {
|
|
||||||
await Util.asyncForEach(inputs.driverOpts, async (driverOpt: string) => {
|
|
||||||
args.push('--driver-opt', driverOpt);
|
|
||||||
});
|
|
||||||
if (inputs.buildkitdFlags) {
|
|
||||||
args.push('--buildkitd-flags', inputs.buildkitdFlags);
|
|
||||||
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
|
|
||||||
args.push('--buildkitd-flags', defaultBuildkitdFlags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (inputs.platforms.length > 0) {
|
return items
|
||||||
args.push('--platform', inputs.platforms.join(','));
|
.split(/\r?\n/)
|
||||||
}
|
.filter(x => x)
|
||||||
if (inputs.use) {
|
.reduce<string[]>((acc, line) => acc.concat(!ignoreComma ? line.split(',').filter(x => x) : line).map(pat => pat.trim()), []);
|
||||||
args.push('--use');
|
|
||||||
}
|
|
||||||
if (inputs.buildkitdConfig) {
|
|
||||||
args.push('--config', toolkit.buildkit.config.resolveFromFile(inputs.buildkitdConfig));
|
|
||||||
} else if (inputs.buildkitdConfigInline) {
|
|
||||||
args.push('--config', toolkit.buildkit.config.resolveFromString(inputs.buildkitdConfigInline));
|
|
||||||
}
|
|
||||||
if (inputs.endpoint) {
|
|
||||||
args.push(inputs.endpoint);
|
|
||||||
}
|
|
||||||
return args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAppendArgs(inputs: Inputs, node: Node, toolkit: Toolkit): Promise<Array<string>> {
|
export const asyncForEach = async (array, callback) => {
|
||||||
const args: Array<string> = ['create', '--name', inputs.name, '--append'];
|
for (let index = 0; index < array.length; index++) {
|
||||||
if (node.name) {
|
await callback(array[index], index, array);
|
||||||
args.push('--node', node.name);
|
|
||||||
} else if (inputs.driver == 'kubernetes' && (await toolkit.buildx.versionSatisfies('<0.11.0'))) {
|
|
||||||
args.push('--node', `node-${crypto.randomUUID()}`);
|
|
||||||
}
|
|
||||||
if (node['driver-opts'] && (await toolkit.buildx.versionSatisfies('>=0.3.0'))) {
|
|
||||||
await Util.asyncForEach(node['driver-opts'], async (driverOpt: string) => {
|
|
||||||
args.push('--driver-opt', driverOpt);
|
|
||||||
});
|
|
||||||
if (node['buildkitd-flags']) {
|
|
||||||
args.push('--buildkitd-flags', node['buildkitd-flags']);
|
|
||||||
} else if (driverSupportsBuildkitdFlags(inputs.driver)) {
|
|
||||||
args.push('--buildkitd-flags', defaultBuildkitdFlags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (node.platforms) {
|
};
|
||||||
args.push('--platform', node.platforms);
|
|
||||||
}
|
|
||||||
if (node.endpoint) {
|
|
||||||
args.push(node.endpoint);
|
|
||||||
}
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getInspectArgs(inputs: Inputs, toolkit: Toolkit): Promise<Array<string>> {
|
// FIXME: Temp fix https://github.com/actions/toolkit/issues/777
|
||||||
const args: Array<string> = ['inspect', '--bootstrap'];
|
export function setOutput(name: string, value: unknown): void {
|
||||||
if (await toolkit.buildx.versionSatisfies('>=0.4.0')) {
|
issueCommand('set-output', {name}, value);
|
||||||
args.push('--builder', inputs.name);
|
|
||||||
}
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
function driverSupportsBuildkitdFlags(driver: string): boolean {
|
|
||||||
return driver == '' || driver == 'docker-container' || driver == 'docker' || driver == 'kubernetes';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getVersion(inputs: Inputs): string {
|
|
||||||
const version = inputs.version;
|
|
||||||
if (inputs.driver === 'cloud') {
|
|
||||||
if (!version || version === 'latest') {
|
|
||||||
return 'cloud:latest';
|
|
||||||
}
|
|
||||||
if (version.startsWith('cloud:') || version.startsWith('lab:')) {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
return `cloud:${version}`;
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
export async function isAvailable(): Promise<boolean> {
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
export async function getRemoteSha(repo: string, ref: string): Promise<string> {
|
||||||
|
return await exec
|
||||||
|
.getExecOutput(`git`, ['ls-remote', repo, ref], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr);
|
||||||
|
}
|
||||||
|
const [rsha] = res.stdout.trim().split(/[\s\t]/);
|
||||||
|
if (rsha.length == 0) {
|
||||||
|
throw new Error(`Cannot find remote ref for ${repo}#${ref}`);
|
||||||
|
}
|
||||||
|
return rsha;
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import * as httpm from '@actions/http-client';
|
||||||
|
|
||||||
|
export interface GitHubRelease {
|
||||||
|
id: number;
|
||||||
|
tag_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRelease = async (version: string): Promise<GitHubRelease | null> => {
|
||||||
|
const url = `https://github.com/docker/buildx/releases/${version}`;
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient('setup-buildx');
|
||||||
|
return (await http.getJson<GitHubRelease>(url)).result;
|
||||||
|
};
|
||||||
@ -1,306 +1,163 @@
|
|||||||
import * as crypto from 'crypto';
|
import * as os from 'os';
|
||||||
import * as fs from 'fs';
|
import * as path from 'path';
|
||||||
import * as yaml from 'js-yaml';
|
import * as uuid from 'uuid';
|
||||||
import * as core from '@actions/core';
|
import * as buildx from './buildx';
|
||||||
import * as actionsToolkit from '@docker/actions-toolkit';
|
|
||||||
|
|
||||||
import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx';
|
|
||||||
import {Builder} from '@docker/actions-toolkit/lib/buildx/builder';
|
|
||||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
|
|
||||||
import {Exec} from '@docker/actions-toolkit/lib/exec';
|
|
||||||
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
|
|
||||||
import {Util} from '@docker/actions-toolkit/lib/util';
|
|
||||||
|
|
||||||
import {Node} from '@docker/actions-toolkit/lib/types/buildx/builder';
|
|
||||||
import {ContextInfo} from '@docker/actions-toolkit/lib/types/docker/docker';
|
|
||||||
|
|
||||||
import * as context from './context';
|
import * as context from './context';
|
||||||
|
import * as docker from './docker';
|
||||||
import * as stateHelper from './state-helper';
|
import * as stateHelper from './state-helper';
|
||||||
|
import * as util from './util';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
actionsToolkit.run(
|
async function run(): Promise<void> {
|
||||||
// main
|
try {
|
||||||
async () => {
|
|
||||||
const inputs: context.Inputs = await context.getInputs();
|
const inputs: context.Inputs = await context.getInputs();
|
||||||
stateHelper.setCleanup(inputs.cleanup);
|
const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
|
||||||
const version = context.getVersion(inputs);
|
|
||||||
|
|
||||||
const toolkit = new Toolkit();
|
// standalone if docker cli not available
|
||||||
const standalone = await toolkit.buildx.isStandalone();
|
const standalone = !(await docker.isAvailable());
|
||||||
stateHelper.setStandalone(standalone);
|
stateHelper.setStandalone(standalone);
|
||||||
|
|
||||||
if (inputs.keepState && inputs.driver !== 'docker-container') {
|
core.startGroup(`Docker info`);
|
||||||
// https://docs.docker.com/reference/cli/docker/buildx/rm/#keep-state
|
if (standalone) {
|
||||||
throw new Error(`Cannot use keep-state with ${inputs.driver} driver`);
|
core.info(`Docker info skipped in standalone mode`);
|
||||||
|
} else {
|
||||||
|
await exec.exec('docker', ['version'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
await exec.exec('docker', ['info'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
stateHelper.setKeepState(inputs.keepState);
|
core.endGroup();
|
||||||
|
|
||||||
await core.group(`Docker info`, async () => {
|
|
||||||
try {
|
|
||||||
await Docker.printVersion();
|
|
||||||
await Docker.printInfo();
|
|
||||||
} catch (e) {
|
|
||||||
core.info(e.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let toolPath;
|
if (util.isValidUrl(inputs.version)) {
|
||||||
if (Util.isValidRef(version)) {
|
|
||||||
if (standalone) {
|
if (standalone) {
|
||||||
throw new Error(`Cannot build from source without the Docker CLI`);
|
throw new Error(`Cannot build from source without the Docker CLI`);
|
||||||
}
|
}
|
||||||
await core.group(`Build buildx from source`, async () => {
|
core.startGroup(`Build and install buildx`);
|
||||||
toolPath = await toolkit.buildxInstall.build(version, !inputs.cacheBinary);
|
await buildx.build(inputs.version, dockerConfigHome, standalone);
|
||||||
});
|
core.endGroup();
|
||||||
} else if (!(await toolkit.buildx.isAvailable()) || version) {
|
} else if (!(await buildx.isAvailable(standalone)) || inputs.version) {
|
||||||
await core.group(`Download buildx from GitHub Releases`, async () => {
|
core.startGroup(`Download and install buildx`);
|
||||||
toolPath = await toolkit.buildxInstall.download(version || 'latest', !inputs.cacheBinary);
|
await buildx.install(inputs.version || 'latest', standalone ? context.tmpDir() : dockerConfigHome, standalone);
|
||||||
});
|
core.endGroup();
|
||||||
}
|
|
||||||
if (toolPath) {
|
|
||||||
await core.group(`Install buildx`, async () => {
|
|
||||||
if (standalone) {
|
|
||||||
await toolkit.buildxInstall.installStandalone(toolPath);
|
|
||||||
} else {
|
|
||||||
await toolkit.buildxInstall.installPlugin(toolPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildxVersion = await buildx.getVersion(standalone);
|
||||||
await core.group(`Buildx version`, async () => {
|
await core.group(`Buildx version`, async () => {
|
||||||
await toolkit.buildx.printVersion();
|
const versionCmd = buildx.getCommand(['version'], standalone);
|
||||||
|
await exec.exec(versionCmd.commandLine, versionCmd.args, {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
core.setOutput('name', inputs.name);
|
const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${uuid.v4()}`;
|
||||||
stateHelper.setBuilderName(inputs.name);
|
context.setOutput('name', builderName);
|
||||||
stateHelper.setBuilderDriver(inputs.driver);
|
stateHelper.setBuilderName(builderName);
|
||||||
|
|
||||||
fs.mkdirSync(Buildx.certsDir, {recursive: true});
|
|
||||||
stateHelper.setCertsDir(Buildx.certsDir);
|
|
||||||
|
|
||||||
// if the default context has TLS data loaded and endpoint is not set, then
|
|
||||||
// we create a temporary docker context only if driver is docker-container
|
|
||||||
// https://github.com/docker/buildx/blob/b96ad59f64d40873e4959336d294b648bb3937fe/builder/builder.go#L489
|
|
||||||
// https://github.com/docker/setup-buildx-action/issues/105
|
|
||||||
if (!standalone && inputs.driver == 'docker-container' && (await Docker.context()) == 'default' && inputs.endpoint.length == 0) {
|
|
||||||
let defaultContextWithTLS: boolean = false;
|
|
||||||
await core.group(`Inspecting default docker context`, async () => {
|
|
||||||
await Docker.getExecOutput(['context', 'inspect', '--format=json', 'default'], {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
core.info(`Cannot inspect default docker context: ${res.stderr.trim()}`);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const contextInfo = (<Array<ContextInfo>>JSON.parse(res.stdout.trim()))[0];
|
|
||||||
core.info(JSON.stringify(JSON.parse(res.stdout.trim()), undefined, 2));
|
|
||||||
const hasTLSData = Object.keys(contextInfo.Endpoints).length > 0 && Object.values(contextInfo.Endpoints)[0].TLSData !== undefined;
|
|
||||||
const hasTLSMaterial = Object.keys(contextInfo.TLSMaterial).length > 0 && Object.values(contextInfo.TLSMaterial)[0].length > 0;
|
|
||||||
defaultContextWithTLS = hasTLSData || hasTLSMaterial;
|
|
||||||
} catch (e) {
|
|
||||||
core.info(`Unable to parse default docker context info: ${e}`);
|
|
||||||
core.info(res.stdout.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (defaultContextWithTLS) {
|
|
||||||
const tmpDockerContext = `buildx-${crypto.randomUUID()}`;
|
|
||||||
await core.group(`Creating temp docker context (TLS data loaded in default one)`, async () => {
|
|
||||||
await Docker.getExecOutput(['context', 'create', tmpDockerContext], {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
core.warning(`Cannot create docker context ${tmpDockerContext}: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
|
||||||
} else {
|
|
||||||
core.info(`Setting builder endpoint to ${tmpDockerContext} context`);
|
|
||||||
inputs.endpoint = tmpDockerContext;
|
|
||||||
stateHelper.setTmpDockerContext(tmpDockerContext);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputs.driver !== 'docker') {
|
if (inputs.driver !== 'docker') {
|
||||||
await core.group(`Creating a new builder instance`, async () => {
|
core.startGroup(`Creating a new builder instance`);
|
||||||
if (await toolkit.builder.exists(inputs.name)) {
|
const createArgs: Array<string> = ['create', '--name', builderName, '--driver', inputs.driver];
|
||||||
core.info(`Builder ${inputs.name} already exists, skipping creation`);
|
if (buildx.satisfies(buildxVersion, '>=0.3.0')) {
|
||||||
} else {
|
await context.asyncForEach(inputs.driverOpts, async driverOpt => {
|
||||||
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, inputs.endpoint, {
|
createArgs.push('--driver-opt', driverOpt);
|
||||||
cacert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CACERT`],
|
});
|
||||||
cert: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_CERT`],
|
if (inputs.buildkitdFlags) {
|
||||||
key: process.env[`${context.builderNodeEnvPrefix}_0_AUTH_TLS_KEY`]
|
createArgs.push('--buildkitd-flags', inputs.buildkitdFlags);
|
||||||
});
|
|
||||||
if (certsDriverOpts.length > 0) {
|
|
||||||
inputs.driverOpts = [...inputs.driverOpts, ...certsDriverOpts];
|
|
||||||
}
|
|
||||||
const createCmd = await toolkit.buildx.getCommand(await context.getCreateArgs(inputs, toolkit));
|
|
||||||
await Exec.getExecOutput(createCmd.command, createCmd.args, {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputs.append) {
|
|
||||||
await core.group(`Appending node(s) to builder`, async () => {
|
|
||||||
let nodeIndex = 1;
|
|
||||||
const nodes = yaml.load(inputs.append) as Node[];
|
|
||||||
for (const node of nodes) {
|
|
||||||
const certsDriverOpts = Buildx.resolveCertsDriverOpts(inputs.driver, `${node.endpoint}`, {
|
|
||||||
cacert: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_CACERT`],
|
|
||||||
cert: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_CERT`],
|
|
||||||
key: process.env[`${context.builderNodeEnvPrefix}_${nodeIndex}_AUTH_TLS_KEY`]
|
|
||||||
});
|
|
||||||
if (certsDriverOpts.length > 0) {
|
|
||||||
node['driver-opts'] = [...(node['driver-opts'] || []), ...certsDriverOpts];
|
|
||||||
}
|
|
||||||
const appendCmd = await toolkit.buildx.getCommand(await context.getAppendArgs(inputs, node, toolkit));
|
|
||||||
await Exec.getExecOutput(appendCmd.command, appendCmd.args, {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
throw new Error(`Failed to append node ${node.name}: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
nodeIndex++;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
if (inputs.use) {
|
||||||
|
createArgs.push('--use');
|
||||||
|
}
|
||||||
|
if (inputs.endpoint) {
|
||||||
|
createArgs.push(inputs.endpoint);
|
||||||
|
}
|
||||||
|
if (inputs.config) {
|
||||||
|
createArgs.push('--config', await buildx.getConfigFile(inputs.config));
|
||||||
|
} else if (inputs.configInline) {
|
||||||
|
createArgs.push('--config', await buildx.getConfigInline(inputs.configInline));
|
||||||
|
}
|
||||||
|
const createCmd = buildx.getCommand(createArgs, standalone);
|
||||||
|
await exec.exec(createCmd.commandLine, createCmd.args);
|
||||||
|
core.endGroup();
|
||||||
|
|
||||||
|
core.startGroup(`Booting builder`);
|
||||||
|
const bootstrapArgs: Array<string> = ['inspect', '--bootstrap'];
|
||||||
|
if (buildx.satisfies(buildxVersion, '>=0.4.0')) {
|
||||||
|
bootstrapArgs.push('--builder', builderName);
|
||||||
|
}
|
||||||
|
const bootstrapCmd = buildx.getCommand(bootstrapArgs, standalone);
|
||||||
|
await exec.exec(bootstrapCmd.commandLine, bootstrapCmd.args);
|
||||||
|
core.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
await core.group(`Booting builder`, async () => {
|
|
||||||
const inspectCmd = await toolkit.buildx.getCommand(await context.getInspectArgs(inputs, toolkit));
|
|
||||||
await Exec.getExecOutput(inspectCmd.command, inspectCmd.args, {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (inputs.install) {
|
if (inputs.install) {
|
||||||
if (standalone) {
|
if (standalone) {
|
||||||
throw new Error(`Cannot set buildx as default builder without the Docker CLI`);
|
throw new Error(`Cannot set buildx as default builder without the Docker CLI`);
|
||||||
}
|
}
|
||||||
await core.group(`Setting buildx as default builder`, async () => {
|
core.startGroup(`Setting buildx as default builder`);
|
||||||
stateHelper.setBuildxIsDefaultBuilder(true);
|
await exec.exec('docker', ['buildx', 'install']);
|
||||||
const installCmd = await toolkit.buildx.getCommand(['install']);
|
core.endGroup();
|
||||||
await Exec.getExecOutput(installCmd.command, installCmd.args, {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const builderInspect = await toolkit.builder.inspect(inputs.name);
|
core.startGroup(`Inspect builder`);
|
||||||
const firstNode = builderInspect.nodes[0];
|
const builder = await buildx.inspect(builderName, standalone);
|
||||||
|
core.info(JSON.stringify(builder, undefined, 2));
|
||||||
await core.group(`Inspect builder`, async () => {
|
context.setOutput('driver', builder.driver);
|
||||||
const reducedPlatforms: Array<string> = [];
|
context.setOutput('endpoint', builder.node_endpoint);
|
||||||
for (const node of builderInspect.nodes) {
|
context.setOutput('status', builder.node_status);
|
||||||
for (const platform of node.platforms?.split(',') || []) {
|
context.setOutput('flags', builder.node_flags);
|
||||||
if (reducedPlatforms.indexOf(platform) > -1) {
|
context.setOutput('platforms', builder.node_platforms);
|
||||||
continue;
|
core.endGroup();
|
||||||
}
|
|
||||||
reducedPlatforms.push(platform);
|
if (!standalone && inputs.driver == 'docker-container') {
|
||||||
}
|
stateHelper.setContainerName(`buildx_buildkit_${builder.node_name}`);
|
||||||
}
|
core.startGroup(`BuildKit version`);
|
||||||
core.info(JSON.stringify(builderInspect, undefined, 2));
|
core.info(await buildx.getBuildKitVersion(`buildx_buildkit_${builder.node_name}`));
|
||||||
core.setOutput('driver', builderInspect.driver);
|
core.endGroup();
|
||||||
core.setOutput('platforms', reducedPlatforms.join(','));
|
|
||||||
core.setOutput('nodes', JSON.stringify(builderInspect.nodes, undefined, 2));
|
|
||||||
core.setOutput('endpoint', firstNode.endpoint); // TODO: deprecated, to be removed in a later version
|
|
||||||
core.setOutput('status', firstNode.status); // TODO: deprecated, to be removed in a later version
|
|
||||||
core.setOutput('flags', firstNode['buildkitd-flags']); // TODO: deprecated, to be removed in a later version
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!standalone && builderInspect.driver == 'docker-container') {
|
|
||||||
stateHelper.setContainerName(`${Buildx.containerNamePrefix}${firstNode.name}`);
|
|
||||||
await core.group(`BuildKit version`, async () => {
|
|
||||||
for (const node of builderInspect.nodes) {
|
|
||||||
const buildkitVersion = await toolkit.buildkit.getVersion(node);
|
|
||||||
core.info(`${node.name}: ${buildkitVersion}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (core.isDebug() || firstNode['buildkitd-flags']?.includes('--debug')) {
|
if (core.isDebug() || builder.node_flags?.includes('--debug')) {
|
||||||
stateHelper.setDebug('true');
|
stateHelper.setDebug('true');
|
||||||
}
|
}
|
||||||
},
|
} catch (error) {
|
||||||
// post
|
core.setFailed(error.message);
|
||||||
async () => {
|
}
|
||||||
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
|
}
|
||||||
await core.group(`BuildKit container logs`, async () => {
|
|
||||||
await Docker.getExecOutput(['logs', `${stateHelper.containerName}`], {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stateHelper.cleanup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateHelper.builderDriver != 'docker' && stateHelper.builderName.length > 0) {
|
async function cleanup(): Promise<void> {
|
||||||
await core.group(`Removing builder`, async () => {
|
if (stateHelper.IsDebug && stateHelper.containerName.length > 0) {
|
||||||
const buildx = new Buildx({standalone: stateHelper.standalone});
|
core.startGroup(`BuildKit container logs`);
|
||||||
const builder = new Builder({buildx: buildx});
|
await exec
|
||||||
if (await builder.exists(stateHelper.builderName)) {
|
.getExecOutput('docker', ['logs', `${stateHelper.containerName}`], {
|
||||||
const rmCmd = await buildx.getCommand(['rm', stateHelper.builderName, ...(stateHelper.keepState ? ['--keep-state'] : [])]);
|
ignoreReturnCode: true
|
||||||
await Exec.getExecOutput(rmCmd.command, rmCmd.args, {
|
})
|
||||||
ignoreReturnCode: true
|
.then(res => {
|
||||||
}).then(res => {
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
core.warning(res.stderr.trim());
|
||||||
core.warning(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
core.info(`${stateHelper.builderName} does not exist`);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
core.endGroup();
|
||||||
|
}
|
||||||
if (stateHelper.tmpDockerContext) {
|
|
||||||
await core.group(`Removing temp docker context`, async () => {
|
|
||||||
await Exec.getExecOutput('docker', ['context', 'rm', '-f', stateHelper.tmpDockerContext], {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
}).then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
core.warning(`${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateHelper.certsDir.length > 0 && fs.existsSync(stateHelper.certsDir)) {
|
|
||||||
await core.group(`Cleaning up certificates`, async () => {
|
|
||||||
fs.rmSync(stateHelper.certsDir, {recursive: true});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateHelper.buildxIsDefaultBuilder) {
|
if (stateHelper.builderName.length > 0) {
|
||||||
await core.group(`Restoring default builder`, async () => {
|
core.startGroup(`Removing builder`);
|
||||||
await Exec.getExecOutput('docker', ['buildx', 'uninstall'], {
|
const rmCmd = buildx.getCommand(['rm', stateHelper.builderName], /true/i.test(stateHelper.standalone));
|
||||||
ignoreReturnCode: true
|
await exec
|
||||||
}).then(res => {
|
.getExecOutput(rmCmd.commandLine, rmCmd.args, {
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
ignoreReturnCode: true
|
||||||
core.warning(`${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
})
|
||||||
}
|
.then(res => {
|
||||||
});
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
core.warning(res.stderr.trim());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
core.endGroup();
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
|
if (!stateHelper.IsPost) {
|
||||||
|
run();
|
||||||
|
} else {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
export function isValidUrl(url: string): boolean {
|
||||||
|
try {
|
||||||
|
new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@ -1,21 +1,19 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"esModuleInterop": true,
|
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"strict": true,
|
|
||||||
"newLine": "lf",
|
"newLine": "lf",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
|
"esModuleInterop": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"resolveJsonModule": true,
|
|
||||||
"useUnknownInCatchVariables": false,
|
"useUnknownInCatchVariables": false,
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"./__tests__/**/*",
|
|
||||||
"./lib/**/*",
|
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
"**/*.test.ts",
|
||||||
"jest.config.ts"
|
"jest.config.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue