Compare commits
44 Commits
v0.1.0-bet
...
v0.1.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e8f679709 | ||
|
|
f288f4f7ea | ||
|
|
cb9121174a | ||
|
|
464dfbe1ec | ||
|
|
5695c0049b | ||
|
|
44b1545abd | ||
|
|
4d9d62d542 | ||
|
|
aa3c8ef106 | ||
|
|
259abb56df | ||
|
|
76e5a25cff | ||
|
|
bb8a659d9e | ||
|
|
6ab0483b34 | ||
|
|
d7dbf54456 | ||
|
|
496d7e2c9d | ||
|
|
094239d9eb | ||
|
|
c8a13a2352 | ||
|
|
875c6c9e95 | ||
|
|
12e3bd7469 | ||
|
|
2abe456e6b | ||
|
|
80dc124c6b | ||
|
|
6ac2b2eb02 | ||
|
|
8cb1698b20 | ||
|
|
b13d2bd668 | ||
|
|
c2dfc9dae8 | ||
|
|
beff1d58b7 | ||
|
|
01219141e4 | ||
|
|
ec7bb99421 | ||
|
|
b223e0a42b | ||
|
|
5e365b5a48 | ||
|
|
392903fad6 | ||
|
|
406e440bcb | ||
|
|
64c6f33406 | ||
|
|
f0f0b76920 | ||
|
|
5e3916dce6 | ||
|
|
815affc0ed | ||
|
|
96ad2a52f8 | ||
|
|
556fff451f | ||
|
|
d1181e8a16 | ||
|
|
11bdb1082a | ||
|
|
fdfeb2486a | ||
|
|
7a9a28cd90 | ||
|
|
3e2548a8ed | ||
|
|
ad59af8cf2 | ||
|
|
40e9a15129 |
@@ -29,6 +29,7 @@
|
|||||||
"error", {
|
"error", {
|
||||||
"ignore": ["csv-parse/sync"]
|
"ignore": ["csv-parse/sync"]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"jest/no-disabled-tests": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
115
.github/buildx-releases.json
vendored
115
.github/buildx-releases.json
vendored
@@ -1,43 +1,84 @@
|
|||||||
{
|
{
|
||||||
"latest": {
|
"latest": {
|
||||||
"id": 90741208,
|
"id": 92694870,
|
||||||
"tag_name": "v0.10.2",
|
"tag_name": "v0.10.3",
|
||||||
"html_url": "https://github.com/docker/buildx/releases/tag/v0.10.2",
|
"html_url": "https://github.com/docker/buildx/releases/tag/v0.10.3",
|
||||||
"assets": [
|
"assets": [
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.darwin-amd64",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.darwin-amd64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.darwin-amd64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.darwin-arm64",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.darwin-arm64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.darwin-arm64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-amd64",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-amd64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-amd64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm-v6",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm-v6.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm-v6.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm-v7",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm-v7.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm-v7.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm64",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-arm64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-ppc64le",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-ppc64le.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-ppc64le.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-riscv64",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-riscv64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-riscv64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-s390x",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-s390x.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.linux-s390x.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.windows-amd64.exe",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.exe",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.windows-amd64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.windows-amd64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.windows-arm64.exe",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.exe",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.windows-arm64.provenance.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.provenance.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/buildx-v0.10.2.windows-arm64.sbom.json",
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.sbom.json",
|
||||||
"https://github.com/docker/buildx/releases/download/v0.10.2/checksums.txt"
|
"https://github.com/docker/buildx/releases/download/v0.10.3/checksums.txt"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"v0.10.3": {
|
||||||
|
"id": 92694870,
|
||||||
|
"tag_name": "v0.10.3",
|
||||||
|
"html_url": "https://github.com/docker/buildx/releases/tag/v0.10.3",
|
||||||
|
"assets": [
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-amd64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.darwin-arm64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-amd64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v6.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm-v7.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-arm64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-ppc64le.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-riscv64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.linux-s390x.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.exe",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-amd64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.exe",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.provenance.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/buildx-v0.10.3.windows-arm64.sbom.json",
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.10.3/checksums.txt"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"v0.10.2": {
|
"v0.10.2": {
|
||||||
|
|||||||
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@@ -41,8 +41,8 @@ jobs:
|
|||||||
targets: test-coverage
|
targets: test-coverage
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
# -
|
-
|
||||||
# name: Upload coverage
|
name: Upload coverage
|
||||||
# uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
# with:
|
with:
|
||||||
# file: ./coverage/clover.xml
|
file: ./coverage/clover.xml
|
||||||
|
|||||||
2
.github/workflows/virtual-env.yml
vendored
2
.github/workflows/virtual-env.yml
vendored
@@ -67,4 +67,4 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: Dump context
|
name: Dump context
|
||||||
if: always()
|
if: always()
|
||||||
uses: crazy-max/ghaction-dump-context@v1
|
uses: crazy-max/ghaction-dump-context@v2
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
[](https://www.npmjs.com/package/@docker/actions-toolkit)
|
||||||
|
[](https://www.npmjs.com/package/@docker/actions-toolkit)
|
||||||
|
[](https://github.com/docker/actions-toolkit/actions?workflow=test)
|
||||||
|
[](https://codecov.io/gh/docker/actions-toolkit)
|
||||||
|
|
||||||
# Actions Toolkit
|
# Actions Toolkit
|
||||||
|
|
||||||
Toolkit for Docker (GitHub) Actions.
|
Toolkit for Docker (GitHub) Actions.
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ afterEach(() => {
|
|||||||
rimraf.sync(tmpDir);
|
rimraf.sync(tmpDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('generate', () => {
|
describe('resolve', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['debug = true', false, 'debug = true', null],
|
['debug = true', false, 'debug = true', null],
|
||||||
[`notfound.toml`, true, '', new Error('config file notfound.toml not found')],
|
[`notfound.toml`, true, '', new Error('config file notfound.toml not found')],
|
||||||
@@ -65,9 +65,9 @@ describe('generate', () => {
|
|||||||
});
|
});
|
||||||
let config: string;
|
let config: string;
|
||||||
if (file) {
|
if (file) {
|
||||||
config = buildkit.config.generateFromFile(val);
|
config = buildkit.config.resolveFromFile(val);
|
||||||
} else {
|
} else {
|
||||||
config = buildkit.config.generateFromString(val);
|
config = buildkit.config.resolveFromString(val);
|
||||||
}
|
}
|
||||||
expect(config).toEqual(tmpName);
|
expect(config).toEqual(tmpName);
|
||||||
const configValue = fs.readFileSync(tmpName, 'utf-8');
|
const configValue = fs.readFileSync(tmpName, 'utf-8');
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import * as exec from '@actions/exec';
|
|||||||
import {Buildx} from '../../src/buildx/buildx';
|
import {Buildx} from '../../src/buildx/buildx';
|
||||||
import {Context} from '../../src/context';
|
import {Context} from '../../src/context';
|
||||||
|
|
||||||
|
import {Cert} from '../../src/types/buildx';
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
|
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
|
||||||
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||||
@@ -46,6 +48,46 @@ afterEach(() => {
|
|||||||
rimraf.sync(tmpDir);
|
rimraf.sync(tmpDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('configDir', () => {
|
||||||
|
const originalEnv = process.env;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
BUILDX_CONFIG: '/var/docker/buildx',
|
||||||
|
DOCKER_CONFIG: '/var/docker/config'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv;
|
||||||
|
});
|
||||||
|
it('returns default', async () => {
|
||||||
|
process.env.BUILDX_CONFIG = '';
|
||||||
|
expect(Buildx.configDir).toEqual(path.join('/var/docker/config', 'buildx'));
|
||||||
|
});
|
||||||
|
it('returns from env', async () => {
|
||||||
|
expect(Buildx.configDir).toEqual('/var/docker/buildx');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('certsDir', () => {
|
||||||
|
const originalEnv = process.env;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
BUILDX_CONFIG: '/var/docker/buildx'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv;
|
||||||
|
});
|
||||||
|
it('returns default', async () => {
|
||||||
|
process.env.BUILDX_CONFIG = '/var/docker/buildx';
|
||||||
|
expect(Buildx.certsDir).toEqual(path.join('/var/docker/buildx', 'certs'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('isAvailable', () => {
|
describe('isAvailable', () => {
|
||||||
it('docker cli', async () => {
|
it('docker cli', async () => {
|
||||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
@@ -152,3 +194,88 @@ describe('versionSatisfies', () => {
|
|||||||
expect(await buildx.versionSatisfies(range, version)).toBe(expected);
|
expect(await buildx.versionSatisfies(range, version)).toBe(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('resolveCertsDriverOpts', () => {
|
||||||
|
const originalEnv = process.env;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
BUILDX_CONFIG: path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx')
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv;
|
||||||
|
rimraf.sync(path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx'));
|
||||||
|
});
|
||||||
|
// prettier-ignore
|
||||||
|
test.each([
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
'mycontext',
|
||||||
|
'docker-container',
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2,
|
||||||
|
'docker-container://mycontainer',
|
||||||
|
'docker-container',
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3,
|
||||||
|
'tcp://graviton2:1234',
|
||||||
|
'remote',
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
4,
|
||||||
|
'tcp://graviton2:1234',
|
||||||
|
'remote',
|
||||||
|
{
|
||||||
|
cacert: 'foo',
|
||||||
|
cert: 'foo',
|
||||||
|
key: 'foo',
|
||||||
|
} as Cert,
|
||||||
|
[
|
||||||
|
path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'cacert_graviton2-1234.pem'),
|
||||||
|
path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'cert_graviton2-1234.pem'),
|
||||||
|
path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'key_graviton2-1234.pem')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
`cacert=${path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'cacert_graviton2-1234.pem')}`,
|
||||||
|
`cert=${path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'cert_graviton2-1234.pem')}`,
|
||||||
|
`key=${path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'key_graviton2-1234.pem')}`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
5,
|
||||||
|
'tcp://mybuilder:1234',
|
||||||
|
'docker-container',
|
||||||
|
{
|
||||||
|
cacert: 'foo',
|
||||||
|
cert: 'foo',
|
||||||
|
key: 'foo',
|
||||||
|
} as Cert,
|
||||||
|
[
|
||||||
|
path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'cacert_mybuilder-1234.pem'),
|
||||||
|
path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'cert_mybuilder-1234.pem'),
|
||||||
|
path.join(tmpDir, 'resolveCertsDriverOpts', 'buildx', 'certs', 'key_mybuilder-1234.pem')
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
])('%p. given %p endpoint, %p driver', async (id: number, endpoint: string, driver: string, cert: Cert, expectedFiles: Array<string>, expectedOpts: Array<string>) => {
|
||||||
|
fs.mkdirSync(Buildx.certsDir, {recursive: true});
|
||||||
|
expect(Buildx.resolveCertsDriverOpts(driver, endpoint, cert)).toEqual(expectedOpts);
|
||||||
|
for (const k in expectedFiles) {
|
||||||
|
const file = expectedFiles[k];
|
||||||
|
expect(fs.existsSync(file)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ afterEach(() => {
|
|||||||
rimraf.sync(tmpDir);
|
rimraf.sync(tmpDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getBuildImageID', () => {
|
describe('resolveBuildImageID', () => {
|
||||||
it('matches', async () => {
|
it('matches', async () => {
|
||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
@@ -58,31 +58,31 @@ describe('getBuildImageID', () => {
|
|||||||
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||||
const imageIDFile = buildx.inputs.getBuildImageIDFilePath();
|
const imageIDFile = buildx.inputs.getBuildImageIDFilePath();
|
||||||
await fs.writeFileSync(imageIDFile, imageID);
|
await fs.writeFileSync(imageIDFile, imageID);
|
||||||
const expected = buildx.inputs.getBuildImageID();
|
const expected = buildx.inputs.resolveBuildImageID();
|
||||||
expect(expected).toEqual(imageID);
|
expect(expected).toEqual(imageID);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getBuildMetadata', () => {
|
describe('resolveBuildMetadata', () => {
|
||||||
it('matches', async () => {
|
it('matches', async () => {
|
||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
||||||
await fs.writeFileSync(metadataFile, metadata);
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
const expected = buildx.inputs.getBuildMetadata();
|
const expected = buildx.inputs.resolveBuildMetadata();
|
||||||
expect(expected).toEqual(metadata);
|
expect(expected).toEqual(metadata);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getDigest', () => {
|
describe('resolveDigest', () => {
|
||||||
it('matches', async () => {
|
it('matches', async () => {
|
||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
||||||
await fs.writeFileSync(metadataFile, metadata);
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
const expected = buildx.inputs.getDigest();
|
const expected = buildx.inputs.resolveDigest();
|
||||||
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -136,7 +136,7 @@ describe('getProvenanceInput', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getProvenanceAttrs', () => {
|
describe('resolveProvenanceAttrs', () => {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
test.each([
|
test.each([
|
||||||
[
|
[
|
||||||
@@ -163,11 +163,11 @@ describe('getProvenanceAttrs', () => {
|
|||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
expect(buildx.inputs.getProvenanceAttrs(input)).toEqual(expected);
|
expect(buildx.inputs.resolveProvenanceAttrs(input)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('generateBuildSecret', () => {
|
describe('resolveBuildSecret', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', null],
|
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', null],
|
||||||
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', null],
|
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', null],
|
||||||
@@ -184,9 +184,9 @@ describe('generateBuildSecret', () => {
|
|||||||
});
|
});
|
||||||
let secret: string;
|
let secret: string;
|
||||||
if (file) {
|
if (file) {
|
||||||
secret = buildx.inputs.generateBuildSecretFile(kvp);
|
secret = buildx.inputs.resolveBuildSecretFile(kvp);
|
||||||
} else {
|
} else {
|
||||||
secret = buildx.inputs.generateBuildSecretString(kvp);
|
secret = buildx.inputs.resolveBuildSecretString(kvp);
|
||||||
}
|
}
|
||||||
expect(secret).toEqual(`id=${exKey},src=${tmpName}`);
|
expect(secret).toEqual(`id=${exKey},src=${tmpName}`);
|
||||||
expect(fs.readFileSync(tmpName, 'utf-8')).toEqual(exValue);
|
expect(fs.readFileSync(tmpName, 'utf-8')).toEqual(exValue);
|
||||||
|
|||||||
@@ -14,31 +14,36 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {describe, expect, it, jest, test, beforeEach} from '@jest/globals';
|
import {describe, expect, it, jest, test, beforeEach, afterEach} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as rimraf from 'rimraf';
|
||||||
import osm = require('os');
|
import osm = require('os');
|
||||||
|
|
||||||
import {Install} from '../../src/buildx/install';
|
import {Install} from '../../src/buildx/install';
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-jest').split(path.sep).join(path.posix.sep);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('install', () => {
|
afterEach(function () {
|
||||||
// prettier-ignore
|
rimraf.sync(tmpDir);
|
||||||
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-install-jest').split(path.sep).join(path.posix.sep);
|
});
|
||||||
|
|
||||||
|
describe('download', () => {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
test.each([
|
test.each([
|
||||||
['v0.4.1', false],
|
['v0.9.1', false],
|
||||||
['latest', false],
|
['latest', false],
|
||||||
['v0.4.1', true],
|
['v0.9.1', true],
|
||||||
['latest', true]
|
['latest', true]
|
||||||
])(
|
])(
|
||||||
'acquires %p of buildx (standalone: %p)', async (version, standalone) => {
|
'acquires %p of buildx (standalone: %p)', async (version, standalone) => {
|
||||||
const install = new Install({standalone: standalone});
|
const install = new Install({standalone: standalone});
|
||||||
const buildxBin = await install.install(version, tmpDir);
|
const buildxBin = await install.download(version, tmpDir);
|
||||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
},
|
},
|
||||||
100000
|
100000
|
||||||
@@ -60,7 +65,7 @@ describe('install', () => {
|
|||||||
jest.spyOn(osm, 'platform').mockImplementation(() => os);
|
jest.spyOn(osm, 'platform').mockImplementation(() => os);
|
||||||
jest.spyOn(osm, 'arch').mockImplementation(() => arch);
|
jest.spyOn(osm, 'arch').mockImplementation(() => arch);
|
||||||
const install = new Install();
|
const install = new Install();
|
||||||
const buildxBin = await install.install('latest', tmpDir);
|
const buildxBin = await install.download('latest', tmpDir);
|
||||||
expect(fs.existsSync(buildxBin)).toBe(true);
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
},
|
},
|
||||||
100000
|
100000
|
||||||
@@ -73,6 +78,22 @@ describe('install', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('build', () => {
|
||||||
|
// eslint-disable-next-line jest/no-disabled-tests
|
||||||
|
it.skip('builds refs/pull/648/head', async () => {
|
||||||
|
const install = new Install();
|
||||||
|
const buildxBin = await install.build('https://github.com/docker/buildx.git#refs/pull/648/head', tmpDir);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
// eslint-disable-next-line jest/no-disabled-tests
|
||||||
|
it.skip('builds 67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', async () => {
|
||||||
|
const install = new Install();
|
||||||
|
const buildxBin = await install.build('https://github.com/docker/buildx.git#67bd6f4dc82a9cd96f34133dab3f6f7af803bb14', tmpDir);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
}, 100000);
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRelease', () => {
|
describe('getRelease', () => {
|
||||||
it('returns latest buildx GitHub release', async () => {
|
it('returns latest buildx GitHub release', async () => {
|
||||||
const release = await Install.getRelease('latest');
|
const release = await Install.getRelease('latest');
|
||||||
|
|||||||
121
__tests__/dockerhub.test.ts
Normal file
121
__tests__/dockerhub.test.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 actions-toolkit authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {describe, expect, jest, it, beforeEach} from '@jest/globals';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import {DockerHub} from '../src/dockerhub';
|
||||||
|
import {RepositoryResponse, RepositoryTagsResponse} from '../src/types/dockerhub';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
import repoInfoFixture from './fixtures/dockerhub-repoinfo.json';
|
||||||
|
import repoTagsFixture from './fixtures/dockerhub-repotags.json';
|
||||||
|
import repoAllTagsFixture from './fixtures/dockerhub-repoalltags.json';
|
||||||
|
|
||||||
|
describe('getRepository', () => {
|
||||||
|
it('returns repo info', async () => {
|
||||||
|
jest.spyOn(DockerHub.prototype, 'getRepository').mockImplementation((): Promise<RepositoryResponse> => {
|
||||||
|
return <Promise<RepositoryResponse>>(repoInfoFixture as unknown);
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
jest.spyOn(DockerHub as any, 'login').mockReturnValue('jwt_token');
|
||||||
|
const dockerhub = await DockerHub.build({
|
||||||
|
credentials: {
|
||||||
|
username: 'foo',
|
||||||
|
password: '0123456-7890-0000-1111-222222222'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const repoinfo = await dockerhub.getRepository({
|
||||||
|
namespace: 'foo',
|
||||||
|
name: 'bar'
|
||||||
|
});
|
||||||
|
expect(repoinfo.namespace).toEqual('foo');
|
||||||
|
expect(repoinfo.name).toEqual('bar');
|
||||||
|
expect(repoinfo.repository_type).toEqual('image');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRepositoryTags', () => {
|
||||||
|
it('return repo tags', async () => {
|
||||||
|
jest.spyOn(DockerHub.prototype, 'getRepositoryTags').mockImplementation((): Promise<RepositoryTagsResponse> => {
|
||||||
|
return <Promise<RepositoryTagsResponse>>(repoTagsFixture as unknown);
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
jest.spyOn(DockerHub as any, 'login').mockReturnValue('jwt_token');
|
||||||
|
const dockerhub = await DockerHub.build({
|
||||||
|
credentials: {
|
||||||
|
username: 'foo',
|
||||||
|
password: '0123456-7890-0000-1111-222222222'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const resp = await dockerhub.getRepositoryTags({
|
||||||
|
namespace: 'crazymax',
|
||||||
|
name: 'diun'
|
||||||
|
});
|
||||||
|
expect(resp.count).toBeGreaterThan(0);
|
||||||
|
expect(resp.next).not.toBeNull();
|
||||||
|
expect(resp.results.length).toBeGreaterThan(0);
|
||||||
|
expect(resp.results[0].last_updater_username).toEqual('crazymax');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRepositoryAllTags', () => {
|
||||||
|
it('return repo all tags', async () => {
|
||||||
|
jest.spyOn(DockerHub.prototype, 'getRepositoryAllTags').mockImplementation((): Promise<RepositoryTagsResponse> => {
|
||||||
|
return <Promise<RepositoryTagsResponse>>(repoAllTagsFixture as unknown);
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
jest.spyOn(DockerHub as any, 'login').mockReturnValue('jwt_token');
|
||||||
|
const dockerhub = await DockerHub.build({
|
||||||
|
credentials: {
|
||||||
|
username: 'foo',
|
||||||
|
password: '0123456-7890-0000-1111-222222222'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const resp = await dockerhub.getRepositoryAllTags({
|
||||||
|
namespace: 'crazymax',
|
||||||
|
name: 'diun'
|
||||||
|
});
|
||||||
|
expect(resp.count).toBeGreaterThan(0);
|
||||||
|
expect(resp.next).toBeNull();
|
||||||
|
expect(resp.results.length).toBeGreaterThan(0);
|
||||||
|
expect(resp.results[0].last_updater_username).toEqual('crazymax');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateRepoDescription', () => {
|
||||||
|
it.skip('set repo description', async () => {
|
||||||
|
const dockerhub = await DockerHub.build({
|
||||||
|
credentials: {
|
||||||
|
username: 'foo',
|
||||||
|
password: 'bar'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const resp = await dockerhub.updateRepoDescription({
|
||||||
|
namespace: 'crazymax',
|
||||||
|
name: 'test-toolkit',
|
||||||
|
description: 'Hello-World',
|
||||||
|
full_description: fs.readFileSync(path.join(__dirname, '..', 'README.md'), 'utf-8')
|
||||||
|
});
|
||||||
|
expect(resp.namespace).toEqual('foo');
|
||||||
|
expect(resp.name).toEqual('bar');
|
||||||
|
expect(resp.description).toEqual('Hello-World');
|
||||||
|
});
|
||||||
|
});
|
||||||
7131
__tests__/fixtures/dockerhub-repoalltags.json
Normal file
7131
__tests__/fixtures/dockerhub-repoalltags.json
Normal file
File diff suppressed because it is too large
Load Diff
34
__tests__/fixtures/dockerhub-repoinfo.json
Normal file
34
__tests__/fixtures/dockerhub-repoinfo.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"user": "foo",
|
||||||
|
"name": "bar",
|
||||||
|
"namespace": "foo",
|
||||||
|
"repository_type": "image",
|
||||||
|
"status": 1,
|
||||||
|
"status_description": "active",
|
||||||
|
"description": "Bar",
|
||||||
|
"is_private": false,
|
||||||
|
"is_automated": false,
|
||||||
|
"can_edit": true,
|
||||||
|
"star_count": 68,
|
||||||
|
"pull_count": 178255909,
|
||||||
|
"last_updated": "2023-02-02T14:22:31.184404Z",
|
||||||
|
"date_registered": "2019-06-04T20:08:57.306333Z",
|
||||||
|
"collaborator_count": 0,
|
||||||
|
"affiliation": "owner",
|
||||||
|
"hub_user": "foo",
|
||||||
|
"has_starred": false,
|
||||||
|
"full_description": "This is the full description of the repo.",
|
||||||
|
"permissions": {
|
||||||
|
"read": true,
|
||||||
|
"write": true,
|
||||||
|
"admin": true
|
||||||
|
},
|
||||||
|
"media_types": [
|
||||||
|
"application/vnd.docker.container.image.v1+json",
|
||||||
|
"application/vnd.docker.distribution.manifest.list.v2+json",
|
||||||
|
"application/vnd.oci.image.index.v1+json"
|
||||||
|
],
|
||||||
|
"content_types": [
|
||||||
|
"image"
|
||||||
|
]
|
||||||
|
}
|
||||||
1053
__tests__/fixtures/dockerhub-repotags.json
Normal file
1053
__tests__/fixtures/dockerhub-repotags.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
|||||||
import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
|
import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
import {GitHub} from '../src/github';
|
import {GitHub} from '../src/github';
|
||||||
import {GitHubRepo} from '../src/types/github';
|
import {GitHubRepo} from '../src/types/github';
|
||||||
@@ -25,7 +26,7 @@ beforeEach(() => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
import repoFixture from './fixtures/repo.json';
|
import repoFixture from './fixtures/github-repo.json';
|
||||||
jest.spyOn(GitHub.prototype, 'repoData').mockImplementation((): Promise<GitHubRepo> => {
|
jest.spyOn(GitHub.prototype, 'repoData').mockImplementation((): Promise<GitHubRepo> => {
|
||||||
return <Promise<GitHubRepo>>(repoFixture as unknown);
|
return <Promise<GitHubRepo>>(repoFixture as unknown);
|
||||||
});
|
});
|
||||||
@@ -101,12 +102,52 @@ describe('actionsRuntimeToken', () => {
|
|||||||
});
|
});
|
||||||
it('empty', async () => {
|
it('empty', async () => {
|
||||||
process.env.ACTIONS_RUNTIME_TOKEN = '';
|
process.env.ACTIONS_RUNTIME_TOKEN = '';
|
||||||
expect(GitHub.actionsRuntimeToken).toEqual({});
|
expect(GitHub.actionsRuntimeToken).toBeUndefined();
|
||||||
|
});
|
||||||
|
it('malformed', async () => {
|
||||||
|
process.env.ACTIONS_RUNTIME_TOKEN = 'foo';
|
||||||
|
expect(() => {
|
||||||
|
GitHub.actionsRuntimeToken;
|
||||||
|
}).toThrowError();
|
||||||
});
|
});
|
||||||
it('fixture', async () => {
|
it('fixture', async () => {
|
||||||
process.env.ACTIONS_RUNTIME_TOKEN = fs.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt')).toString().trim();
|
process.env.ACTIONS_RUNTIME_TOKEN = fs.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt')).toString().trim();
|
||||||
const runtimeToken = GitHub.actionsRuntimeToken;
|
const runtimeToken = GitHub.actionsRuntimeToken;
|
||||||
expect(runtimeToken.ac).toEqual('[{"Scope":"refs/heads/master","Permission":3}]');
|
expect(runtimeToken?.ac).toEqual('[{"Scope":"refs/heads/master","Permission":3}]');
|
||||||
expect(runtimeToken.iss).toEqual('vstoken.actions.githubusercontent.com');
|
expect(runtimeToken?.iss).toEqual('vstoken.actions.githubusercontent.com');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('printActionsRuntimeTokenACs', () => {
|
||||||
|
const originalEnv = process.env;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = {
|
||||||
|
...originalEnv
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv;
|
||||||
|
});
|
||||||
|
it('empty', async () => {
|
||||||
|
const warnSpy = jest.spyOn(core, 'warning');
|
||||||
|
process.env.ACTIONS_RUNTIME_TOKEN = '';
|
||||||
|
await GitHub.printActionsRuntimeTokenACs();
|
||||||
|
expect(warnSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(warnSpy).toHaveBeenCalledWith(`ACTIONS_RUNTIME_TOKEN not set`);
|
||||||
|
});
|
||||||
|
it('malformed', async () => {
|
||||||
|
const warnSpy = jest.spyOn(core, 'warning');
|
||||||
|
process.env.ACTIONS_RUNTIME_TOKEN = 'foo';
|
||||||
|
await GitHub.printActionsRuntimeTokenACs();
|
||||||
|
expect(warnSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(warnSpy).toHaveBeenCalledWith(`Cannot parse Actions Runtime Token: Invalid token specified: Cannot read properties of undefined (reading 'replace')`);
|
||||||
|
});
|
||||||
|
it('refs/heads/master', async () => {
|
||||||
|
const infoSpy = jest.spyOn(core, 'info');
|
||||||
|
process.env.ACTIONS_RUNTIME_TOKEN = fs.readFileSync(path.join(__dirname, 'fixtures', 'runtimeToken.txt')).toString().trim();
|
||||||
|
await GitHub.printActionsRuntimeTokenACs();
|
||||||
|
expect(infoSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith(`refs/heads/master: read/write`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -69,16 +69,28 @@ describe('getInputList', () => {
|
|||||||
|
|
||||||
it('multiline and ignoring comma correctly', async () => {
|
it('multiline and ignoring comma correctly', async () => {
|
||||||
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
||||||
const res = Util.getInputList('cache-from', true);
|
const res = Util.getInputList('cache-from', {ignoreComma: true});
|
||||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('different new lines and ignoring comma correctly', async () => {
|
it('different new lines and ignoring comma correctly', async () => {
|
||||||
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
||||||
const res = Util.getInputList('cache-from', true);
|
const res = Util.getInputList('cache-from', {ignoreComma: true});
|
||||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('do not escape surrounding quotes', async () => {
|
||||||
|
setInput('driver-opts', `"env.no_proxy=localhost,127.0.0.1,.mydomain"`);
|
||||||
|
const res = Util.getInputList('driver-opts', {ignoreComma: true, quote: false});
|
||||||
|
expect(res).toEqual(['"env.no_proxy=localhost,127.0.0.1,.mydomain"']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('escape surrounding quotes', async () => {
|
||||||
|
setInput('platforms', 'linux/amd64\n"linux/arm64,linux/arm/v7"');
|
||||||
|
const res = Util.getInputList('platforms');
|
||||||
|
expect(res).toEqual(['linux/amd64', 'linux/arm64', 'linux/arm/v7']);
|
||||||
|
});
|
||||||
|
|
||||||
it('multiline values', async () => {
|
it('multiline values', async () => {
|
||||||
setInput(
|
setInput(
|
||||||
'secrets',
|
'secrets',
|
||||||
@@ -88,7 +100,7 @@ bbbbbbb
|
|||||||
ccccccccc"
|
ccccccccc"
|
||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = Util.getInputList('secrets', true);
|
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||||
expect(res).toEqual([
|
expect(res).toEqual([
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||||
`MYSECRET=aaaaaaaa
|
`MYSECRET=aaaaaaaa
|
||||||
@@ -111,7 +123,7 @@ FOO=bar
|
|||||||
bbbb
|
bbbb
|
||||||
ccc"`
|
ccc"`
|
||||||
);
|
);
|
||||||
const res = Util.getInputList('secrets', true);
|
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||||
expect(res).toEqual([
|
expect(res).toEqual([
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||||
`MYSECRET=aaaaaaaa
|
`MYSECRET=aaaaaaaa
|
||||||
@@ -134,7 +146,7 @@ bbbbbbb
|
|||||||
ccccccccc
|
ccccccccc
|
||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = Util.getInputList('secrets', true);
|
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||||
expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']);
|
expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -145,7 +157,7 @@ FOO=bar`
|
|||||||
`"GPG_KEY=${pgp}"
|
`"GPG_KEY=${pgp}"
|
||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = Util.getInputList('secrets', true);
|
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||||
expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']);
|
expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -158,7 +170,7 @@ bbbb""bbb
|
|||||||
ccccccccc"
|
ccccccccc"
|
||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = Util.getInputList('secrets', true);
|
const res = Util.getInputList('secrets', {ignoreComma: true});
|
||||||
expect(res).toEqual([
|
expect(res).toEqual([
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||||
`MYSECRET=aaaaaaaa
|
`MYSECRET=aaaaaaaa
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@docker/actions-toolkit",
|
"name": "@docker/actions-toolkit",
|
||||||
|
"version": "0.0.0+unknown",
|
||||||
"description": "Toolkit for Docker (GitHub) Actions",
|
"description": "Toolkit for Docker (GitHub) Actions",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
"@actions/github": "^5.1.1",
|
"@actions/github": "^5.1.1",
|
||||||
"@actions/http-client": "^2.0.1",
|
"@actions/http-client": "^2.0.1",
|
||||||
"@actions/tool-cache": "^2.0.1",
|
"@actions/tool-cache": "^2.0.1",
|
||||||
"csv-parse": "^5.3.4",
|
"csv-parse": "^5.3.5",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"semver": "^7.3.8",
|
"semver": "^7.3.8",
|
||||||
"tmp": "^0.2.1"
|
"tmp": "^0.2.1"
|
||||||
|
|||||||
@@ -25,15 +25,15 @@ export class Config {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public generateFromString(s: string): string {
|
public resolveFromString(s: string): string {
|
||||||
return this.generate(s, false);
|
return this.resolve(s, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public generateFromFile(s: string): string {
|
public resolveFromFile(s: string): string {
|
||||||
return this.generate(s, true);
|
return this.resolve(s, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private generate(s: string, file: boolean): string {
|
private resolve(s: string, file: boolean): string {
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!fs.existsSync(s)) {
|
if (!fs.existsSync(s)) {
|
||||||
throw new Error(`config file ${s} not found`);
|
throw new Error(`config file ${s} not found`);
|
||||||
|
|||||||
@@ -14,13 +14,16 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
|
||||||
import {Docker} from '../docker';
|
import {Docker} from '../docker';
|
||||||
import {Context} from '../context';
|
import {Context} from '../context';
|
||||||
import {Inputs} from './inputs';
|
import {Inputs} from './inputs';
|
||||||
import {Install} from './install';
|
|
||||||
|
import {Cert} from '../types/buildx';
|
||||||
|
|
||||||
export interface BuildxOpts {
|
export interface BuildxOpts {
|
||||||
context: Context;
|
context: Context;
|
||||||
@@ -32,16 +35,22 @@ export class Buildx {
|
|||||||
private _version: string | undefined;
|
private _version: string | undefined;
|
||||||
|
|
||||||
public readonly inputs: Inputs;
|
public readonly inputs: Inputs;
|
||||||
public readonly install: Install;
|
|
||||||
public readonly standalone: boolean;
|
public readonly standalone: boolean;
|
||||||
|
|
||||||
constructor(opts: BuildxOpts) {
|
constructor(opts: BuildxOpts) {
|
||||||
this.context = opts.context;
|
this.context = opts.context;
|
||||||
this.inputs = new Inputs(this.context);
|
this.inputs = new Inputs(this.context);
|
||||||
this.install = new Install({standalone: opts.standalone});
|
|
||||||
this.standalone = opts?.standalone ?? !Docker.isAvailable;
|
this.standalone = opts?.standalone ?? !Docker.isAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get configDir(): string {
|
||||||
|
return process.env.BUILDX_CONFIG || path.join(Docker.configDir, 'buildx');
|
||||||
|
}
|
||||||
|
|
||||||
|
static get certsDir(): string {
|
||||||
|
return path.join(Buildx.configDir, 'certs');
|
||||||
|
}
|
||||||
|
|
||||||
public getCommand(args: Array<string>) {
|
public getCommand(args: Array<string>) {
|
||||||
return {
|
return {
|
||||||
command: this.standalone ? 'buildx' : 'docker',
|
command: this.standalone ? 'buildx' : 'docker',
|
||||||
@@ -117,4 +126,43 @@ export class Buildx {
|
|||||||
}
|
}
|
||||||
return semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
|
return semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static resolveCertsDriverOpts(driver: string, endpoint: string, cert: Cert): Array<string> {
|
||||||
|
let url: URL;
|
||||||
|
try {
|
||||||
|
url = new URL(endpoint);
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (url.protocol != 'tcp:') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const driverOpts: Array<string> = [];
|
||||||
|
if (Object.keys(cert).length == 0) {
|
||||||
|
return driverOpts;
|
||||||
|
}
|
||||||
|
let host = url.hostname;
|
||||||
|
if (url.port.length > 0) {
|
||||||
|
host += `-${url.port}`;
|
||||||
|
}
|
||||||
|
if (cert.cacert !== undefined) {
|
||||||
|
const cacertpath = path.join(Buildx.certsDir, `cacert_${host}.pem`);
|
||||||
|
fs.writeFileSync(cacertpath, cert.cacert);
|
||||||
|
driverOpts.push(`cacert=${cacertpath}`);
|
||||||
|
}
|
||||||
|
if (cert.cert !== undefined) {
|
||||||
|
const certpath = path.join(Buildx.certsDir, `cert_${host}.pem`);
|
||||||
|
fs.writeFileSync(certpath, cert.cert);
|
||||||
|
driverOpts.push(`cert=${certpath}`);
|
||||||
|
}
|
||||||
|
if (cert.key !== undefined) {
|
||||||
|
const keypath = path.join(Buildx.certsDir, `key_${host}.pem`);
|
||||||
|
fs.writeFileSync(keypath, cert.key);
|
||||||
|
driverOpts.push(`key=${keypath}`);
|
||||||
|
}
|
||||||
|
if (driver != 'remote') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return driverOpts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class Inputs {
|
|||||||
return path.join(this.context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep);
|
return path.join(this.context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBuildImageID(): string | undefined {
|
public resolveBuildImageID(): string | undefined {
|
||||||
const iidFile = this.getBuildImageIDFilePath();
|
const iidFile = this.getBuildImageIDFilePath();
|
||||||
if (!fs.existsSync(iidFile)) {
|
if (!fs.existsSync(iidFile)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -44,7 +44,7 @@ export class Inputs {
|
|||||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBuildMetadata(): string | undefined {
|
public resolveBuildMetadata(): string | undefined {
|
||||||
const metadataFile = this.getBuildMetadataFilePath();
|
const metadataFile = this.getBuildMetadataFilePath();
|
||||||
if (!fs.existsSync(metadataFile)) {
|
if (!fs.existsSync(metadataFile)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -56,8 +56,8 @@ export class Inputs {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDigest(): string | undefined {
|
public resolveDigest(): string | undefined {
|
||||||
const metadata = this.getBuildMetadata();
|
const metadata = this.resolveBuildMetadata();
|
||||||
if (metadata === undefined) {
|
if (metadata === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -68,15 +68,15 @@ export class Inputs {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public generateBuildSecretString(kvp: string): string {
|
public resolveBuildSecretString(kvp: string): string {
|
||||||
return this.generateBuildSecret(kvp, false);
|
return this.resolveBuildSecret(kvp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public generateBuildSecretFile(kvp: string): string {
|
public resolveBuildSecretFile(kvp: string): string {
|
||||||
return this.generateBuildSecret(kvp, true);
|
return this.resolveBuildSecret(kvp, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public generateBuildSecret(kvp: string, file: boolean): string {
|
public resolveBuildSecret(kvp: string, file: boolean): string {
|
||||||
const delimiterIndex = kvp.indexOf('=');
|
const delimiterIndex = kvp.indexOf('=');
|
||||||
const key = kvp.substring(0, delimiterIndex);
|
const key = kvp.substring(0, delimiterIndex);
|
||||||
let value = kvp.substring(delimiterIndex + 1);
|
let value = kvp.substring(delimiterIndex + 1);
|
||||||
@@ -105,11 +105,11 @@ export class Inputs {
|
|||||||
return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false';
|
return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// not a valid boolean, so we assume it's a string
|
// not a valid boolean, so we assume it's a string
|
||||||
return this.getProvenanceAttrs(input);
|
return this.resolveProvenanceAttrs(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getProvenanceAttrs(input: string): string {
|
public resolveProvenanceAttrs(input: string): string {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return `builder-id=${this.context.provenanceBuilderID}`;
|
return `builder-id=${this.context.provenanceBuilderID}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,27 +18,37 @@ import fs from 'fs';
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
import * as httpm from '@actions/http-client';
|
import * as httpm from '@actions/http-client';
|
||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
|
|
||||||
|
import {Buildx} from './buildx';
|
||||||
|
import {Context} from '../context';
|
||||||
|
import {Docker} from '../docker';
|
||||||
|
import {Git} from '../git';
|
||||||
|
|
||||||
import {GitHubRelease} from '../types/github';
|
import {GitHubRelease} from '../types/github';
|
||||||
|
|
||||||
export interface InstallOpts {
|
export interface InstallOpts {
|
||||||
|
context?: Context;
|
||||||
standalone?: boolean;
|
standalone?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Install {
|
export class Install {
|
||||||
private readonly opts: InstallOpts;
|
private readonly context: Context;
|
||||||
|
private readonly standalone: boolean;
|
||||||
|
|
||||||
constructor(opts?: InstallOpts) {
|
constructor(opts?: InstallOpts) {
|
||||||
this.opts = opts || {};
|
this.context = opts?.context || new Context();
|
||||||
|
this.standalone = opts?.standalone ?? !Docker.isAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async install(version: string, dest: string): Promise<string> {
|
public async download(version: string, dest?: string): Promise<string> {
|
||||||
const release: GitHubRelease = await Install.getRelease(version);
|
const release: GitHubRelease = await Install.getRelease(version);
|
||||||
const fversion = release.tag_name.replace(/^v+|v+$/g, '');
|
const fversion = release.tag_name.replace(/^v+|v+$/g, '');
|
||||||
|
|
||||||
let toolPath: string;
|
let toolPath: string;
|
||||||
toolPath = tc.find('buildx', fversion, this.platform());
|
toolPath = tc.find('buildx', fversion, this.platform());
|
||||||
if (!toolPath) {
|
if (!toolPath) {
|
||||||
@@ -46,14 +56,87 @@ export class Install {
|
|||||||
if (!semver.valid(c)) {
|
if (!semver.valid(c)) {
|
||||||
throw new Error(`Invalid Buildx version "${fversion}".`);
|
throw new Error(`Invalid Buildx version "${fversion}".`);
|
||||||
}
|
}
|
||||||
toolPath = await this.download(fversion);
|
toolPath = await this.fetchBinary(fversion);
|
||||||
}
|
}
|
||||||
if (this.opts.standalone) {
|
|
||||||
|
dest = dest || (this.standalone ? this.context.tmpDir() : Docker.configDir);
|
||||||
|
if (this.standalone) {
|
||||||
return this.setStandalone(toolPath, dest);
|
return this.setStandalone(toolPath, dest);
|
||||||
}
|
}
|
||||||
return this.setPlugin(toolPath, dest);
|
return this.setPlugin(toolPath, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async build(gitContext: string, dest?: string): Promise<string> {
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let [repo, ref] = gitContext.split('#');
|
||||||
|
if (ref.length == 0) {
|
||||||
|
ref = 'master';
|
||||||
|
}
|
||||||
|
|
||||||
|
let vspec: string;
|
||||||
|
// TODO: include full ref as fingerprint. Use commit sha as best-effort in the meantime.
|
||||||
|
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 outputDir = path.join(this.context.tmpDir(), 'build-cache').split(path.sep).join(path.posix.sep);
|
||||||
|
const buildCmd = await this.buildCommand(gitContext, outputDir);
|
||||||
|
toolPath = await exec
|
||||||
|
.getExecOutput(buildCmd.command, buildCmd.args, {
|
||||||
|
ignoreReturnCode: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
core.warning(res.stderr.trim());
|
||||||
|
}
|
||||||
|
return tc.cacheFile(`${outputDir}/buildx`, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx', 'buildx', vspec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = dest || Docker.configDir;
|
||||||
|
if (this.standalone) {
|
||||||
|
return this.setStandalone(toolPath, dest);
|
||||||
|
}
|
||||||
|
return this.setPlugin(toolPath, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async buildCommand(gitContext: string, outputDir: string): Promise<{args: Array<string>; command: string}> {
|
||||||
|
const buildxStandaloneFound = await new Buildx({context: this.context, standalone: true}).isAvailable();
|
||||||
|
const buildxPluginFound = await new Buildx({context: this.context, standalone: false}).isAvailable();
|
||||||
|
|
||||||
|
let buildStandalone = false;
|
||||||
|
if (this.standalone && buildxStandaloneFound) {
|
||||||
|
core.debug(`Buildx standalone found, build with it`);
|
||||||
|
buildStandalone = true;
|
||||||
|
} else if (!this.standalone && buildxPluginFound) {
|
||||||
|
core.debug(`Buildx plugin found, build with it`);
|
||||||
|
buildStandalone = false;
|
||||||
|
} else if (buildxStandaloneFound) {
|
||||||
|
core.debug(`Buildx plugin not found, but standalone found so trying to build with it`);
|
||||||
|
buildStandalone = true;
|
||||||
|
} else if (buildxPluginFound) {
|
||||||
|
core.debug(`Buildx standalone not found, but plugin found so trying to build with it`);
|
||||||
|
buildStandalone = false;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Neither buildx standalone or plugin have been found to build from ref ${gitContext}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
//prettier-ignore
|
||||||
|
return new Buildx({context: this.context, standalone: buildStandalone}).getCommand([
|
||||||
|
'build',
|
||||||
|
'--target', 'binaries',
|
||||||
|
'--build-arg', 'BUILDKIT_CONTEXT_KEEP_GIT_DIR=1',
|
||||||
|
'--output', `type=local,dest=${outputDir}`,
|
||||||
|
gitContext
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
private async setStandalone(toolPath: string, dest: string): Promise<string> {
|
private async setStandalone(toolPath: string, dest: string): Promise<string> {
|
||||||
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||||
const binDir = path.join(dest, 'bin');
|
const binDir = path.join(dest, 'bin');
|
||||||
@@ -81,7 +164,7 @@ export class Install {
|
|||||||
return pluginPath;
|
return pluginPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async download(version: string): Promise<string> {
|
private async fetchBinary(version: string): Promise<string> {
|
||||||
const targetFile: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
const targetFile: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||||
const downloadURL = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, this.filename(version));
|
const downloadURL = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, this.filename(version));
|
||||||
const downloadPath = await tc.downloadTool(downloadURL);
|
const downloadPath = await tc.downloadTool(downloadURL);
|
||||||
|
|||||||
127
src/dockerhub.ts
Normal file
127
src/dockerhub.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 actions-toolkit authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as httpm from '@actions/http-client';
|
||||||
|
import {HttpCodes} from '@actions/http-client';
|
||||||
|
|
||||||
|
import {RepositoryRequest, RepositoryResponse, RepositoryTagsRequest, RepositoryTagsResponse, TokenRequest, TokenResponse, UpdateRepoDescriptionRequest} from './types/dockerhub';
|
||||||
|
|
||||||
|
export interface DockerHubOpts {
|
||||||
|
credentials: TokenRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiBaseURL = 'https://hub.docker.com';
|
||||||
|
const loginURL = `${apiBaseURL}/v2/users/login?refresh_token=true`;
|
||||||
|
const repositoriesURL = `${apiBaseURL}/v2/repositories/`;
|
||||||
|
|
||||||
|
export class DockerHub {
|
||||||
|
private readonly opts: DockerHubOpts;
|
||||||
|
private readonly httpc: httpm.HttpClient;
|
||||||
|
|
||||||
|
private constructor(opts: DockerHubOpts, httpc: httpm.HttpClient) {
|
||||||
|
this.opts = opts;
|
||||||
|
this.httpc = httpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async build(opts: DockerHubOpts): Promise<DockerHub> {
|
||||||
|
return new DockerHub(
|
||||||
|
opts,
|
||||||
|
new httpm.HttpClient('docker-actions-toolkit', [], {
|
||||||
|
headers: {
|
||||||
|
Authorization: `JWT ${await DockerHub.login(opts.credentials)}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRepositoryTags(req: RepositoryTagsRequest): Promise<RepositoryTagsResponse> {
|
||||||
|
const url = new URL(`${repositoriesURL}${req.namespace}/${req.name}/tags`);
|
||||||
|
if (req.page) {
|
||||||
|
url.searchParams.append('page', req.page.toString());
|
||||||
|
}
|
||||||
|
if (req.page_size) {
|
||||||
|
url.searchParams.append('page_size', req.page_size.toString());
|
||||||
|
}
|
||||||
|
const resp: httpm.HttpClientResponse = await this.httpc.get(url.toString());
|
||||||
|
return <RepositoryTagsResponse>JSON.parse(await DockerHub.handleResponse(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRepositoryAllTags(req: RepositoryTagsRequest): Promise<RepositoryTagsResponse> {
|
||||||
|
const tags: RepositoryTagsResponse = await this.getRepositoryTags(req);
|
||||||
|
while (tags.next) {
|
||||||
|
const nextURL = new URL(tags.next);
|
||||||
|
const pageNumber = Number(nextURL.searchParams.get('page'));
|
||||||
|
const pageSize = Number(nextURL.searchParams.get('page_size')) || undefined;
|
||||||
|
const nextTags = await this.getRepositoryTags({
|
||||||
|
namespace: req.namespace,
|
||||||
|
name: req.name,
|
||||||
|
page: pageNumber,
|
||||||
|
page_size: pageSize || req.page_size
|
||||||
|
} as RepositoryTagsRequest);
|
||||||
|
tags.results.push(...nextTags.results);
|
||||||
|
tags.next = nextTags.next;
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRepository(req: RepositoryRequest): Promise<RepositoryResponse> {
|
||||||
|
const resp: httpm.HttpClientResponse = await this.httpc.get(`${repositoriesURL}${req.namespace}/${req.name}`);
|
||||||
|
return <RepositoryResponse>JSON.parse(await DockerHub.handleResponse(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateRepoDescription(req: UpdateRepoDescriptionRequest): Promise<RepositoryResponse> {
|
||||||
|
const body = {
|
||||||
|
full_description: req.full_description
|
||||||
|
};
|
||||||
|
if (req.description) {
|
||||||
|
body['description'] = req.description;
|
||||||
|
}
|
||||||
|
const resp: httpm.HttpClientResponse = await this.httpc.patch(`${repositoriesURL}${req.namespace}/${req.name}`, JSON.stringify(body));
|
||||||
|
return <RepositoryResponse>JSON.parse(await DockerHub.handleResponse(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async login(req: TokenRequest): Promise<string> {
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit', [], {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const resp: httpm.HttpClientResponse = await http.post(loginURL, JSON.stringify(req));
|
||||||
|
const tokenResp = <TokenResponse>JSON.parse(await DockerHub.handleResponse(resp));
|
||||||
|
core.setSecret(`${tokenResp.token}`);
|
||||||
|
return `${tokenResp.token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async handleResponse(resp: httpm.HttpClientResponse): Promise<string> {
|
||||||
|
const body = await resp.readBody();
|
||||||
|
resp.message.statusCode = resp.message.statusCode || HttpCodes.InternalServerError;
|
||||||
|
if (resp.message.statusCode < 200 || resp.message.statusCode >= 300) {
|
||||||
|
if (resp.message.statusCode == HttpCodes.Unauthorized) {
|
||||||
|
throw new Error(`Docker Hub API: operation not permitted`);
|
||||||
|
}
|
||||||
|
const errResp = <Record<string, string>>JSON.parse(body);
|
||||||
|
for (const k of ['message', 'detail', 'error']) {
|
||||||
|
if (errResp[k]) {
|
||||||
|
throw new Error(`Docker Hub API: bad status code ${resp.message.statusCode}: ${errResp[k]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Docker Hub API: bad status code ${resp.message.statusCode}`);
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,11 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {GitHub as Octokit} from '@actions/github/lib/utils';
|
import {GitHub as Octokit} from '@actions/github/lib/utils';
|
||||||
|
import * as core from '@actions/core';
|
||||||
import * as github from '@actions/github';
|
import * as github from '@actions/github';
|
||||||
import {Context} from '@actions/github/lib/context';
|
import {Context} from '@actions/github/lib/context';
|
||||||
import jwt_decode from 'jwt-decode';
|
import jwt_decode from 'jwt-decode';
|
||||||
|
|
||||||
import {GitHubActionsRuntimeToken, GitHubRepo} from './types/github';
|
import {GitHubActionsRuntimeToken, GitHubActionsRuntimeTokenAC, GitHubRepo} from './types/github';
|
||||||
|
|
||||||
export interface GitHubOpts {
|
export interface GitHubOpts {
|
||||||
token?: string;
|
token?: string;
|
||||||
@@ -48,8 +49,43 @@ export class GitHub {
|
|||||||
return process.env.GITHUB_API_URL || 'https://api.github.com';
|
return process.env.GITHUB_API_URL || 'https://api.github.com';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get actionsRuntimeToken(): GitHubActionsRuntimeToken {
|
static get actionsRuntimeToken(): GitHubActionsRuntimeToken | undefined {
|
||||||
const token = process.env['ACTIONS_RUNTIME_TOKEN'] || '';
|
const token = process.env['ACTIONS_RUNTIME_TOKEN'] || '';
|
||||||
return token ? jwt_decode<GitHubActionsRuntimeToken>(token) : {};
|
return token ? jwt_decode<GitHubActionsRuntimeToken>(token) : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async printActionsRuntimeTokenACs() {
|
||||||
|
let jwt: GitHubActionsRuntimeToken | undefined;
|
||||||
|
try {
|
||||||
|
jwt = GitHub.actionsRuntimeToken;
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(`Cannot parse Actions Runtime Token: ${e.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!jwt) {
|
||||||
|
core.warning(`ACTIONS_RUNTIME_TOKEN not set`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
<Array<GitHubActionsRuntimeTokenAC>>JSON.parse(`${jwt.ac}`).forEach(ac => {
|
||||||
|
let permission: string;
|
||||||
|
switch (ac.Permission) {
|
||||||
|
case 1:
|
||||||
|
permission = 'read';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
permission = 'write';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
permission = 'read/write';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
permission = `unimplemented (${ac.Permission})`;
|
||||||
|
}
|
||||||
|
core.info(`${ac.Scope}: ${permission}`);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(`Cannot parse Actions Runtime Token Access Controls: ${e.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
import {Context} from './context';
|
import {Context} from './context';
|
||||||
import {Buildx} from './buildx/buildx';
|
import {Buildx} from './buildx/buildx';
|
||||||
|
import {Install} from './buildx/install';
|
||||||
|
import {Builder} from './buildx/builder';
|
||||||
import {BuildKit} from './buildkit/buildkit';
|
import {BuildKit} from './buildkit/buildkit';
|
||||||
import {GitHub} from './github';
|
import {GitHub} from './github';
|
||||||
|
|
||||||
@@ -31,12 +33,16 @@ export class Toolkit {
|
|||||||
public context: Context;
|
public context: Context;
|
||||||
public github: GitHub;
|
public github: GitHub;
|
||||||
public buildx: Buildx;
|
public buildx: Buildx;
|
||||||
|
public buildxInstall: Install;
|
||||||
|
public builder: Builder;
|
||||||
public buildkit: BuildKit;
|
public buildkit: BuildKit;
|
||||||
|
|
||||||
constructor(opts: ToolkitOpts = {}) {
|
constructor(opts: ToolkitOpts = {}) {
|
||||||
this.context = new Context();
|
this.context = new Context();
|
||||||
this.github = new GitHub({token: opts.githubToken});
|
this.github = new GitHub({token: opts.githubToken});
|
||||||
this.buildx = new Buildx({context: this.context});
|
this.buildx = new Buildx({context: this.context});
|
||||||
|
this.buildxInstall = new Install({context: this.context, standalone: this.buildx.standalone});
|
||||||
|
this.builder = new Builder({context: this.context, buildx: this.buildx});
|
||||||
this.buildkit = new BuildKit({context: this.context, buildx: this.buildx});
|
this.buildkit = new BuildKit({context: this.context, buildx: this.buildx});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,3 +30,11 @@ export interface NodeInfo {
|
|||||||
buildkitVersion?: string;
|
buildkitVersion?: string;
|
||||||
platforms?: string;
|
platforms?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Node {
|
||||||
|
name?: string;
|
||||||
|
endpoint?: string;
|
||||||
|
'driver-opts'?: Array<string>;
|
||||||
|
'buildkitd-flags'?: string;
|
||||||
|
platforms?: string;
|
||||||
|
}
|
||||||
|
|||||||
21
src/types/buildx.ts
Normal file
21
src/types/buildx.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 actions-toolkit authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Cert {
|
||||||
|
cacert?: string;
|
||||||
|
cert?: string;
|
||||||
|
key?: string;
|
||||||
|
}
|
||||||
113
src/types/dockerhub.ts
Normal file
113
src/types/dockerhub.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 actions-toolkit authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface TokenRequest {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenResponse {
|
||||||
|
token: string;
|
||||||
|
detail: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryRequest {
|
||||||
|
namespace: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryResponse {
|
||||||
|
user: string;
|
||||||
|
name: string;
|
||||||
|
namespace: string;
|
||||||
|
repository_type: string;
|
||||||
|
status: number;
|
||||||
|
status_description: string;
|
||||||
|
description: string;
|
||||||
|
is_private: boolean;
|
||||||
|
is_automated: boolean;
|
||||||
|
can_edit: boolean;
|
||||||
|
star_count: number;
|
||||||
|
pull_count: number;
|
||||||
|
last_updated: string;
|
||||||
|
date_registered: string;
|
||||||
|
collaborator_count: number;
|
||||||
|
affiliation: string;
|
||||||
|
hub_user: string;
|
||||||
|
has_starred: boolean;
|
||||||
|
full_description: string;
|
||||||
|
permissions: {
|
||||||
|
read: boolean;
|
||||||
|
write: boolean;
|
||||||
|
admin: boolean;
|
||||||
|
};
|
||||||
|
media_types: Array<string>;
|
||||||
|
content_types: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryTagsRequest {
|
||||||
|
namespace: string;
|
||||||
|
name: string;
|
||||||
|
page?: number;
|
||||||
|
page_size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryTagsResponse {
|
||||||
|
count: number;
|
||||||
|
next?: string;
|
||||||
|
previous?: string;
|
||||||
|
results: Array<RepositoryTagsResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryTagsResult {
|
||||||
|
creator: number;
|
||||||
|
id: number;
|
||||||
|
images: Array<RepositoryTagsResultImage>;
|
||||||
|
last_updated: Date;
|
||||||
|
last_updater: number;
|
||||||
|
last_updater_username: string;
|
||||||
|
name: string;
|
||||||
|
repository: number;
|
||||||
|
full_size: number;
|
||||||
|
v2: boolean;
|
||||||
|
tag_status: string;
|
||||||
|
tag_last_pulled: Date;
|
||||||
|
tag_last_pushed: Date;
|
||||||
|
media_type: string;
|
||||||
|
content_type: string;
|
||||||
|
digest: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepositoryTagsResultImage {
|
||||||
|
architecture: string;
|
||||||
|
features: string;
|
||||||
|
variant?: string;
|
||||||
|
digest: string;
|
||||||
|
os: string;
|
||||||
|
os_features: string;
|
||||||
|
os_version?: string;
|
||||||
|
size: number;
|
||||||
|
status: string;
|
||||||
|
last_pulled: Date;
|
||||||
|
last_pushed: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateRepoDescriptionRequest {
|
||||||
|
name: string;
|
||||||
|
namespace: string;
|
||||||
|
description?: string;
|
||||||
|
full_description: string;
|
||||||
|
}
|
||||||
@@ -29,3 +29,8 @@ export type GitHubRepo = OctoOpenApiTypes['schemas']['repository'];
|
|||||||
export interface GitHubActionsRuntimeToken extends JwtPayload {
|
export interface GitHubActionsRuntimeToken extends JwtPayload {
|
||||||
ac?: string;
|
ac?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GitHubActionsRuntimeTokenAC {
|
||||||
|
Scope: string;
|
||||||
|
Permission: number;
|
||||||
|
}
|
||||||
|
|||||||
23
src/util.ts
23
src/util.ts
@@ -17,8 +17,13 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import {parse} from 'csv-parse/sync';
|
import {parse} from 'csv-parse/sync';
|
||||||
|
|
||||||
|
export interface InputListOpts {
|
||||||
|
ignoreComma?: boolean;
|
||||||
|
quote?: string | boolean | Buffer | null;
|
||||||
|
}
|
||||||
|
|
||||||
export class Util {
|
export class Util {
|
||||||
public static getInputList(name: string, ignoreComma?: boolean): string[] {
|
public static getInputList(name: string, opts?: InputListOpts): string[] {
|
||||||
const res: Array<string> = [];
|
const res: Array<string> = [];
|
||||||
|
|
||||||
const items = core.getInput(name);
|
const items = core.getInput(name);
|
||||||
@@ -31,18 +36,22 @@ export class Util {
|
|||||||
relaxQuotes: true,
|
relaxQuotes: true,
|
||||||
comment: '#',
|
comment: '#',
|
||||||
relaxColumnCount: true,
|
relaxColumnCount: true,
|
||||||
skipEmptyLines: true
|
skipEmptyLines: true,
|
||||||
|
quote: opts?.quote
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const record of records as Array<string[]>) {
|
for (const record of records as Array<string[]>) {
|
||||||
if (record.length == 1) {
|
if (record.length == 1) {
|
||||||
res.push(record[0]);
|
if (opts?.ignoreComma) {
|
||||||
continue;
|
res.push(record[0]);
|
||||||
} else if (!ignoreComma) {
|
} else {
|
||||||
|
res.push(...record[0].split(','));
|
||||||
|
}
|
||||||
|
} else if (!opts?.ignoreComma) {
|
||||||
res.push(...record);
|
res.push(...record);
|
||||||
continue;
|
} else {
|
||||||
|
res.push(record.join(','));
|
||||||
}
|
}
|
||||||
res.push(record.join(','));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.filter(item => item).map(pat => pat.trim());
|
return res.filter(item => item).map(pat => pat.trim());
|
||||||
|
|||||||
10
yarn.lock
10
yarn.lock
@@ -774,7 +774,7 @@ __metadata:
|
|||||||
"@typescript-eslint/eslint-plugin": ^5.49.0
|
"@typescript-eslint/eslint-plugin": ^5.49.0
|
||||||
"@typescript-eslint/parser": ^5.49.0
|
"@typescript-eslint/parser": ^5.49.0
|
||||||
cpy-cli: ^4.2.0
|
cpy-cli: ^4.2.0
|
||||||
csv-parse: ^5.3.4
|
csv-parse: ^5.3.5
|
||||||
dotenv: ^16.0.3
|
dotenv: ^16.0.3
|
||||||
eslint: ^8.33.0
|
eslint: ^8.33.0
|
||||||
eslint-config-prettier: ^8.6.0
|
eslint-config-prettier: ^8.6.0
|
||||||
@@ -2568,10 +2568,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"csv-parse@npm:^5.3.4":
|
"csv-parse@npm:^5.3.5":
|
||||||
version: 5.3.4
|
version: 5.3.5
|
||||||
resolution: "csv-parse@npm:5.3.4"
|
resolution: "csv-parse@npm:5.3.5"
|
||||||
checksum: 853648004d74dd02b06f51e45efff0cce79a4bbbd03eb344ae0f7e91733c90938b3fab424a9275d5b4cf7845c9d55acbdee90775a92bc8476a0d1d2cd335ec4e
|
checksum: 077e010db2ebbc9db708b719f2f650577c5ec8d176cd4363235d6644c36c642811d05ef1b6907390dd7466bde20a8dbb0f34994bc0e101521eb09e6691a02206
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user