Compare commits
40 Commits
v0.1.0-bet
...
v0.1.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8e980fc49 | ||
|
|
3f81bea2c1 | ||
|
|
d21d31d108 | ||
|
|
765b23685c | ||
|
|
c89aa60986 | ||
|
|
3150492079 | ||
|
|
b193ec6e9e | ||
|
|
257dd09431 | ||
|
|
e47d166c4f | ||
|
|
98e69d9e72 | ||
|
|
81d78d2ce7 | ||
|
|
fe8b21ecf5 | ||
|
|
dea2294b93 | ||
|
|
cc48ecede1 | ||
|
|
388280c282 | ||
|
|
c11b80183c | ||
|
|
ae3911e977 | ||
|
|
535aedce51 | ||
|
|
104c7babf8 | ||
|
|
c617b15f70 | ||
|
|
17f9c80d9c | ||
|
|
ffdd47b148 | ||
|
|
eca9342d11 | ||
|
|
433952b109 | ||
|
|
1d52cba4ed | ||
|
|
00f55b8385 | ||
|
|
063d88c841 | ||
|
|
152b37e0f7 | ||
|
|
28b6e2512c | ||
|
|
e218647127 | ||
|
|
a9c554ec83 | ||
|
|
48fba6e0d9 | ||
|
|
bd4df13130 | ||
|
|
201b1942bf | ||
|
|
b40e86b8f4 | ||
|
|
96c92fc206 | ||
|
|
e070c13d66 | ||
|
|
9df71fe601 | ||
|
|
f9b34f0e95 | ||
|
|
32a260e6e5 |
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/.yarn/**
|
||||||
|
/lib/**
|
||||||
|
/coverage/**
|
||||||
|
/node_modules/**
|
||||||
@@ -2,11 +2,15 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"es2021": true,
|
"es2021": true,
|
||||||
"jest/globals": true
|
"mocha": true,
|
||||||
|
"jest": true
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:import/errors",
|
||||||
|
"plugin:import/typescript", // this is needed to allow importing typescript files from JS
|
||||||
|
"plugin:import/warnings",
|
||||||
"plugin:jest/recommended",
|
"plugin:jest/recommended",
|
||||||
"plugin:prettier/recommended"
|
"plugin:prettier/recommended"
|
||||||
],
|
],
|
||||||
@@ -19,5 +23,12 @@
|
|||||||
"@typescript-eslint",
|
"@typescript-eslint",
|
||||||
"jest",
|
"jest",
|
||||||
"prettier"
|
"prettier"
|
||||||
]
|
],
|
||||||
|
"rules": {
|
||||||
|
"import/no-unresolved": [
|
||||||
|
"error", {
|
||||||
|
"ignore": ["csv-parse/sync"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
.github/workflows/buildx-releases-json.yml
vendored
Normal file
59
.github/workflows/buildx-releases-json.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
name: buildx-releases-json
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 */12 * * *'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '.github/buildx-releases.json'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
uses: crazy-max/.github/.github/workflows/releases-json.yml@2a596c917a8ad3e6203ae99b777148525a2e00d5
|
||||||
|
with:
|
||||||
|
repository: docker/buildx
|
||||||
|
artifact_name: buildx-releases-json
|
||||||
|
filename: buildx-releases.json
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
# FIXME: Uncomment when repo public
|
||||||
|
# open-pr:
|
||||||
|
# runs-on: ubuntu-22.04
|
||||||
|
# if: github.event_name != 'pull_request'
|
||||||
|
# needs:
|
||||||
|
# - generate
|
||||||
|
# steps:
|
||||||
|
# -
|
||||||
|
# name: Checkout
|
||||||
|
# uses: actions/checkout@v3
|
||||||
|
# -
|
||||||
|
# name: Download
|
||||||
|
# uses: actions/download-artifact@v3
|
||||||
|
# with:
|
||||||
|
# name: buildx-releases-json
|
||||||
|
# path: .github
|
||||||
|
# -
|
||||||
|
# name: Commit changes
|
||||||
|
# run: |
|
||||||
|
# git add -A .
|
||||||
|
# -
|
||||||
|
# name: Create PR
|
||||||
|
# uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04
|
||||||
|
# with:
|
||||||
|
# base: master
|
||||||
|
# branch: bot/buildx-releases-json
|
||||||
|
# commit-message: "github: update .github/buildx-releases.json"
|
||||||
|
# signoff: true
|
||||||
|
# delete-branch: true
|
||||||
|
# title: "Update `.github/buildx-releases.json`"
|
||||||
|
# body: |
|
||||||
|
# Update `.github/buildx-releases.json` to keep in sync with [https://github.com/docker/buildx](https://github.com/docker/buildx).
|
||||||
|
# draft: false
|
||||||
20
.github/workflows/test.yml
vendored
20
.github/workflows/test.yml
vendored
@@ -5,10 +5,19 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- 'main'
|
- 'main'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '.github/buildx-releases.json'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
validate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- lint
|
||||||
|
- vendor-validate
|
||||||
|
- license-validate
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -17,7 +26,14 @@ jobs:
|
|||||||
name: Validate
|
name: Validate
|
||||||
uses: docker/bake-action@v2
|
uses: docker/bake-action@v2
|
||||||
with:
|
with:
|
||||||
targets: validate
|
targets: ${{ matrix.target }}
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Test
|
name: Test
|
||||||
uses: docker/bake-action@v2
|
uses: docker/bake-action@v2
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
# Dependency directories
|
# Dependency directories
|
||||||
node_modules/
|
/node_modules/**
|
||||||
jspm_packages/
|
/jspm_packages/**
|
||||||
|
|
||||||
# yarn v2
|
# yarn v2
|
||||||
.yarn/
|
/.yarn/**
|
||||||
|
|
||||||
|
# build
|
||||||
|
/lib/**
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
nodeLinker: node-modules
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
npmAuthToken: "${NODE_AUTH_TOKEN:-fallback}"
|
||||||
|
|
||||||
|
logFilters:
|
||||||
|
# https://yarnpkg.com/advanced/error-codes
|
||||||
|
- code: YN0013
|
||||||
|
level: discard
|
||||||
|
- code: YN0076
|
||||||
|
level: discard
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
spec: "@yarnpkg/plugin-interactive-tools"
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -1,3 +1,44 @@
|
|||||||
# Actions Toolkit
|
# Actions Toolkit
|
||||||
|
|
||||||
Toolkit for Docker (GitHub) Actions.
|
Toolkit for Docker (GitHub) Actions.
|
||||||
|
|
||||||
|
## :test_tube: Experimental
|
||||||
|
|
||||||
|
This repository is considered **EXPERIMENTAL** and under active development
|
||||||
|
until further notice. It is subject to non-backward compatible changes or
|
||||||
|
removal in any future version.
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
This repository contains the source code for the toolkit that is consumed as
|
||||||
|
a library by most of our GitHub Actions:
|
||||||
|
|
||||||
|
* [docker/bake-action](https://github.com/docker/bake-action)
|
||||||
|
* [docker/build-push-action](https://github.com/docker/build-push-action)
|
||||||
|
* [docker/login-action](https://github.com/docker/login-action)
|
||||||
|
* [docker/metadata-action](https://github.com/docker/metadata-action)
|
||||||
|
* [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action)
|
||||||
|
* [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action)
|
||||||
|
|
||||||
|
This toolkit provides some utilities and common logic when developing GitHub
|
||||||
|
Actions and also acts as a minimal wrapper around our build tooling such as
|
||||||
|
[Buildx](https://github.com/docker/buildx) and [BuildKit](https://github.com/moby/buildkit)
|
||||||
|
and provides an easier API for interacting with them.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ npm install @docker/actions-toolkit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { Toolkit } = require('@docker/actions-toolkit')
|
||||||
|
const toolkit = new Toolkit()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Want to contribute to the Actions Toolkit? Awesome! You can find information
|
||||||
|
about contributing to this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 {jest} from '@jest/globals';
|
import {jest} from '@jest/globals';
|
||||||
|
|
||||||
export const context = {
|
export const context = {
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
import {describe, expect, it, jest, test, beforeEach, afterEach} from '@jest/globals';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
import rimraf from 'rimraf';
|
|
||||||
import * as semver from 'semver';
|
|
||||||
|
|
||||||
import {BuildKit} from '../src/buildkit';
|
|
||||||
import {Builder, BuilderInfo} from '../src/builder';
|
|
||||||
import {Context} from '../src/context';
|
|
||||||
|
|
||||||
const tmpDir = path.join('/tmp/.docker-actions-toolkit-jest').split(path.sep).join(path.posix.sep);
|
|
||||||
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
|
||||||
|
|
||||||
jest.spyOn(Context.prototype as any, 'tmpDir').mockImplementation((): string => {
|
|
||||||
if (!fs.existsSync(tmpDir)) {
|
|
||||||
fs.mkdirSync(tmpDir, {recursive: true});
|
|
||||||
}
|
|
||||||
return tmpDir;
|
|
||||||
});
|
|
||||||
jest.spyOn(Context.prototype as any, 'tmpName').mockImplementation((): string => {
|
|
||||||
return tmpName;
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
rimraf.sync(tmpDir);
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<BuilderInfo> => {
|
|
||||||
return {
|
|
||||||
name: 'builder2',
|
|
||||||
driver: 'docker-container',
|
|
||||||
lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'),
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
buildkitVersion: 'v0.11.0',
|
|
||||||
buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
|
||||||
driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
|
|
||||||
endpoint: 'unix:///var/run/docker.sock',
|
|
||||||
name: 'builder20',
|
|
||||||
platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6',
|
|
||||||
status: 'running'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getVersion', () => {
|
|
||||||
it('valid', async () => {
|
|
||||||
const buildkit = new BuildKit({
|
|
||||||
context: new Context()
|
|
||||||
});
|
|
||||||
const version = await buildkit.getVersion('builder2');
|
|
||||||
expect(semver.valid(version)).not.toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('satisfies', () => {
|
|
||||||
test.each([
|
|
||||||
['builder2', '>=0.10.0', true],
|
|
||||||
['builder2', '>0.11.0', false]
|
|
||||||
])('given %p', async (builderName, range, expected) => {
|
|
||||||
const buildkit = new BuildKit({
|
|
||||||
context: new Context()
|
|
||||||
});
|
|
||||||
expect(await buildkit.versionSatisfies(builderName, range)).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('generateConfig', () => {
|
|
||||||
test.each([
|
|
||||||
['debug = true', false, 'debug = true', null],
|
|
||||||
[`notfound.toml`, true, '', new Error('config file notfound.toml not found')],
|
|
||||||
[
|
|
||||||
`${path.join(__dirname, 'fixtures', 'buildkitd.toml').split(path.sep).join(path.posix.sep)}`,
|
|
||||||
true,
|
|
||||||
`debug = true
|
|
||||||
[registry."docker.io"]
|
|
||||||
mirrors = ["mirror.gcr.io"]
|
|
||||||
`,
|
|
||||||
null
|
|
||||||
]
|
|
||||||
])('given %p config', async (val, file, exValue, error: Error) => {
|
|
||||||
try {
|
|
||||||
const buildkit = new BuildKit({
|
|
||||||
context: new Context()
|
|
||||||
});
|
|
||||||
let config: string;
|
|
||||||
if (file) {
|
|
||||||
config = buildkit.generateConfigFile(val);
|
|
||||||
} else {
|
|
||||||
config = buildkit.generateConfigInline(val);
|
|
||||||
}
|
|
||||||
expect(config).toEqual(tmpName);
|
|
||||||
const configValue = fs.readFileSync(tmpName, 'utf-8');
|
|
||||||
expect(configValue).toEqual(exValue);
|
|
||||||
} catch (e) {
|
|
||||||
// eslint-disable-next-line jest/no-conditional-expect
|
|
||||||
expect(e.message).toEqual(error?.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
69
__tests__/buildkit/buildkit.test.ts
Normal file
69
__tests__/buildkit/buildkit.test.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* 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 {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
|
||||||
|
import {BuildKit} from '../../src/buildkit/buildkit';
|
||||||
|
import {Builder} from '../../src/buildx/builder';
|
||||||
|
import {Context} from '../../src/context';
|
||||||
|
|
||||||
|
import {BuilderInfo} from '../../src/types/builder';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise<BuilderInfo> => {
|
||||||
|
return {
|
||||||
|
name: 'builder2',
|
||||||
|
driver: 'docker-container',
|
||||||
|
lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'),
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
buildkitVersion: 'v0.11.0',
|
||||||
|
buildkitdFlags: '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host',
|
||||||
|
driverOpts: ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'],
|
||||||
|
endpoint: 'unix:///var/run/docker.sock',
|
||||||
|
name: 'builder20',
|
||||||
|
platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6',
|
||||||
|
status: 'running'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getVersion', () => {
|
||||||
|
it('valid', async () => {
|
||||||
|
const buildkit = new BuildKit({
|
||||||
|
context: new Context()
|
||||||
|
});
|
||||||
|
const version = await buildkit.getVersion('builder2');
|
||||||
|
expect(semver.valid(version)).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('satisfies', () => {
|
||||||
|
test.each([
|
||||||
|
['builder2', '>=0.10.0', true],
|
||||||
|
['builder2', '>0.11.0', false]
|
||||||
|
])('given %p', async (builderName, range, expected) => {
|
||||||
|
const buildkit = new BuildKit({
|
||||||
|
context: new Context()
|
||||||
|
});
|
||||||
|
expect(await buildkit.versionSatisfies(builderName, range)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
80
__tests__/buildkit/config.test.ts
Normal file
80
__tests__/buildkit/config.test.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* 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, test, beforeEach, afterEach} from '@jest/globals';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as rimraf from 'rimraf';
|
||||||
|
|
||||||
|
import {BuildKit} from '../../src/buildkit/buildkit';
|
||||||
|
import {Context} from '../../src/context';
|
||||||
|
|
||||||
|
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||||
|
// prettier-ignore
|
||||||
|
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildkit-config-jest').split(path.sep).join(path.posix.sep);
|
||||||
|
const tmpName = path.join(tmpDir, '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||||
|
|
||||||
|
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||||
|
if (!fs.existsSync(tmpDir)) {
|
||||||
|
fs.mkdirSync(tmpDir, {recursive: true});
|
||||||
|
}
|
||||||
|
return tmpDir;
|
||||||
|
});
|
||||||
|
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||||
|
return tmpName;
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
rimraf.sync(tmpDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('generate', () => {
|
||||||
|
test.each([
|
||||||
|
['debug = true', false, 'debug = true', null],
|
||||||
|
[`notfound.toml`, true, '', new Error('config file notfound.toml not found')],
|
||||||
|
[
|
||||||
|
`${path.join(fixturesDir, 'buildkitd.toml').split(path.sep).join(path.posix.sep)}`,
|
||||||
|
true,
|
||||||
|
`debug = true
|
||||||
|
[registry."docker.io"]
|
||||||
|
mirrors = ["mirror.gcr.io"]
|
||||||
|
`,
|
||||||
|
null
|
||||||
|
]
|
||||||
|
])('given %p config', async (val, file, exValue, error: Error) => {
|
||||||
|
try {
|
||||||
|
const buildkit = new BuildKit({
|
||||||
|
context: new Context()
|
||||||
|
});
|
||||||
|
let config: string;
|
||||||
|
if (file) {
|
||||||
|
config = buildkit.config.generateFromFile(val);
|
||||||
|
} else {
|
||||||
|
config = buildkit.config.generateFromString(val);
|
||||||
|
}
|
||||||
|
expect(config).toEqual(tmpName);
|
||||||
|
const configValue = fs.readFileSync(tmpName, 'utf-8');
|
||||||
|
expect(configValue).toEqual(exValue);
|
||||||
|
} catch (e) {
|
||||||
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
|
expect(e.message).toEqual(error?.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,9 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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 {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import {Builder, BuilderInfo} from '../src/builder';
|
import {Builder} from '../../src/buildx/builder';
|
||||||
import {Context} from '../src/context';
|
import {Context} from '../../src/context';
|
||||||
|
|
||||||
|
import {BuilderInfo} from '../../src/types/builder';
|
||||||
|
|
||||||
|
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@@ -180,6 +200,6 @@ describe('parseInspect', () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
])('given %p', async (inspectFile, expected) => {
|
])('given %p', async (inspectFile, expected) => {
|
||||||
expect(await Builder.parseInspect(fs.readFileSync(path.join(__dirname, 'fixtures', inspectFile)).toString())).toEqual(expected);
|
expect(await Builder.parseInspect(fs.readFileSync(path.join(fixturesDir, inspectFile)).toString())).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
154
__tests__/buildx/buildx.test.ts
Normal file
154
__tests__/buildx/buildx.test.ts
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
/**
|
||||||
|
* 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, it, jest, test, beforeEach, afterEach} from '@jest/globals';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as rimraf from 'rimraf';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
import {Buildx} from '../../src/buildx/buildx';
|
||||||
|
import {Context} from '../../src/context';
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
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);
|
||||||
|
|
||||||
|
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||||
|
if (!fs.existsSync(tmpDir)) {
|
||||||
|
fs.mkdirSync(tmpDir, {recursive: true});
|
||||||
|
}
|
||||||
|
return tmpDir;
|
||||||
|
});
|
||||||
|
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||||
|
return tmpName;
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
rimraf.sync(tmpDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isAvailable', () => {
|
||||||
|
it('docker cli', async () => {
|
||||||
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context(),
|
||||||
|
standalone: false
|
||||||
|
});
|
||||||
|
buildx.isAvailable().catch(() => {
|
||||||
|
// noop
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line jest/no-standalone-expect
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||||
|
silent: true,
|
||||||
|
ignoreReturnCode: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('standalone', async () => {
|
||||||
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context(),
|
||||||
|
standalone: true
|
||||||
|
});
|
||||||
|
buildx.isAvailable().catch(() => {
|
||||||
|
// noop
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line jest/no-standalone-expect
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
||||||
|
silent: true,
|
||||||
|
ignoreReturnCode: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('printInspect', () => {
|
||||||
|
it('prints builder2 instance', () => {
|
||||||
|
const execSpy = jest.spyOn(exec, 'exec');
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context(),
|
||||||
|
standalone: true
|
||||||
|
});
|
||||||
|
buildx.printInspect('builder2').catch(() => {
|
||||||
|
// noop
|
||||||
|
});
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['inspect', 'builder2'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('printVersion', () => {
|
||||||
|
it('docker cli', () => {
|
||||||
|
const execSpy = jest.spyOn(exec, 'exec');
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context(),
|
||||||
|
standalone: false
|
||||||
|
});
|
||||||
|
buildx.printVersion();
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx', 'version'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('standalone', () => {
|
||||||
|
const execSpy = jest.spyOn(exec, 'exec');
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context(),
|
||||||
|
standalone: true
|
||||||
|
});
|
||||||
|
buildx.printVersion();
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['version'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('version', () => {
|
||||||
|
it('valid', async () => {
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context()
|
||||||
|
});
|
||||||
|
expect(semver.valid(await buildx.version)).not.toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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('versionSatisfies', () => {
|
||||||
|
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) => {
|
||||||
|
const buildx = new Buildx({
|
||||||
|
context: new Context()
|
||||||
|
});
|
||||||
|
expect(await buildx.versionSatisfies(range, version)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,27 +1,44 @@
|
|||||||
import {describe, expect, it, jest, test, beforeEach, afterEach} from '@jest/globals';
|
/**
|
||||||
|
* 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 {afterEach, beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import rimraf from 'rimraf';
|
import * as rimraf from 'rimraf';
|
||||||
import * as semver from 'semver';
|
|
||||||
import * as exec from '@actions/exec';
|
|
||||||
|
|
||||||
import {Buildx} from '../src/buildx';
|
import {Context} from '../../src/context';
|
||||||
import {Context} from '../src/context';
|
import {Buildx} from '../../src/buildx/buildx';
|
||||||
|
import {Inputs} from '../../src/buildx/inputs';
|
||||||
|
|
||||||
const tmpDir = path.join('/tmp/.docker-actions-toolkit-jest').split(path.sep).join(path.posix.sep);
|
const fixturesDir = path.join(__dirname, '..', 'fixtures');
|
||||||
|
// prettier-ignore
|
||||||
|
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-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);
|
||||||
const metadata = `{
|
const metadata = `{
|
||||||
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
||||||
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
jest.spyOn(Context.prototype as any, 'tmpDir').mockImplementation((): string => {
|
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||||
if (!fs.existsSync(tmpDir)) {
|
if (!fs.existsSync(tmpDir)) {
|
||||||
fs.mkdirSync(tmpDir, {recursive: true});
|
fs.mkdirSync(tmpDir, {recursive: true});
|
||||||
}
|
}
|
||||||
return tmpDir;
|
return tmpDir;
|
||||||
});
|
});
|
||||||
jest.spyOn(Context.prototype as any, 'tmpName').mockImplementation((): string => {
|
jest.spyOn(Context.prototype, 'tmpName').mockImplementation((): string => {
|
||||||
return tmpName;
|
return tmpName;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,122 +50,15 @@ afterEach(() => {
|
|||||||
rimraf.sync(tmpDir);
|
rimraf.sync(tmpDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isAvailable', () => {
|
|
||||||
it('docker cli', async () => {
|
|
||||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context(),
|
|
||||||
standalone: false
|
|
||||||
});
|
|
||||||
buildx.isAvailable().catch(() => {
|
|
||||||
// noop
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line jest/no-standalone-expect
|
|
||||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
|
||||||
silent: true,
|
|
||||||
ignoreReturnCode: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('standalone', async () => {
|
|
||||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context(),
|
|
||||||
standalone: true
|
|
||||||
});
|
|
||||||
buildx.isAvailable().catch(() => {
|
|
||||||
// noop
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line jest/no-standalone-expect
|
|
||||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
|
||||||
silent: true,
|
|
||||||
ignoreReturnCode: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('printInspect', () => {
|
|
||||||
it('prints builder2 instance', () => {
|
|
||||||
const execSpy = jest.spyOn(exec, 'exec');
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context(),
|
|
||||||
standalone: true
|
|
||||||
});
|
|
||||||
buildx.printInspect('builder2').catch(() => {
|
|
||||||
// noop
|
|
||||||
});
|
|
||||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['inspect', 'builder2'], {
|
|
||||||
failOnStdErr: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('printVersion', () => {
|
|
||||||
it('docker cli', () => {
|
|
||||||
const execSpy = jest.spyOn(exec, 'exec');
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context(),
|
|
||||||
standalone: false
|
|
||||||
});
|
|
||||||
buildx.printVersion();
|
|
||||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx', 'version'], {
|
|
||||||
failOnStdErr: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('standalone', () => {
|
|
||||||
const execSpy = jest.spyOn(exec, 'exec');
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context(),
|
|
||||||
standalone: true
|
|
||||||
});
|
|
||||||
buildx.printVersion();
|
|
||||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, ['version'], {
|
|
||||||
failOnStdErr: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getVersion', () => {
|
|
||||||
it('valid', async () => {
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context()
|
|
||||||
});
|
|
||||||
expect(semver.valid(await buildx.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('versionSatisfies', () => {
|
|
||||||
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) => {
|
|
||||||
const buildx = new Buildx({
|
|
||||||
context: new Context()
|
|
||||||
});
|
|
||||||
expect(await buildx.versionSatisfies(range, version)).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getBuildImageID', () => {
|
describe('getBuildImageID', () => {
|
||||||
it('matches', async () => {
|
it('matches', async () => {
|
||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||||
const imageIDFile = buildx.getBuildImageIDFilePath();
|
const imageIDFile = buildx.inputs.getBuildImageIDFilePath();
|
||||||
await fs.writeFileSync(imageIDFile, imageID);
|
await fs.writeFileSync(imageIDFile, imageID);
|
||||||
const expected = buildx.getBuildImageID();
|
const expected = buildx.inputs.getBuildImageID();
|
||||||
expect(expected).toEqual(imageID);
|
expect(expected).toEqual(imageID);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -158,9 +68,9 @@ describe('getBuildMetadata', () => {
|
|||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
const metadataFile = buildx.getBuildMetadataFilePath();
|
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
||||||
await fs.writeFileSync(metadataFile, metadata);
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
const expected = buildx.getBuildMetadata();
|
const expected = buildx.inputs.getBuildMetadata();
|
||||||
expect(expected).toEqual(metadata);
|
expect(expected).toEqual(metadata);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -170,9 +80,9 @@ describe('getDigest', () => {
|
|||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
const metadataFile = buildx.getBuildMetadataFilePath();
|
const metadataFile = buildx.inputs.getBuildMetadataFilePath();
|
||||||
await fs.writeFileSync(metadataFile, metadata);
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
const expected = buildx.getDigest();
|
const expected = buildx.inputs.getDigest();
|
||||||
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -222,7 +132,7 @@ describe('getProvenanceInput', () => {
|
|||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
expect(buildx.getProvenanceInput('provenance')).toEqual(expected);
|
expect(buildx.inputs.getProvenanceInput('provenance')).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -253,7 +163,7 @@ describe('getProvenanceAttrs', () => {
|
|||||||
const buildx = new Buildx({
|
const buildx = new Buildx({
|
||||||
context: new Context()
|
context: new Context()
|
||||||
});
|
});
|
||||||
expect(buildx.getProvenanceAttrs(input)).toEqual(expected);
|
expect(buildx.inputs.getProvenanceAttrs(input)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -265,7 +175,7 @@ describe('generateBuildSecret', () => {
|
|||||||
['aaaaaaaa', false, '', '', new Error('aaaaaaaa is not a valid secret')],
|
['aaaaaaaa', false, '', '', new Error('aaaaaaaa is not a valid secret')],
|
||||||
['aaaaaaaa=', false, '', '', new Error('aaaaaaaa= is not a valid secret')],
|
['aaaaaaaa=', false, '', '', new Error('aaaaaaaa= is not a valid secret')],
|
||||||
['=bbbbbbb', false, '', '', new Error('=bbbbbbb is not a valid secret')],
|
['=bbbbbbb', false, '', '', new Error('=bbbbbbb is not a valid secret')],
|
||||||
[`foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`, true, 'foo', 'bar', null],
|
[`foo=${path.join(fixturesDir, 'secret.txt').split(path.sep).join(path.posix.sep)}`, true, 'foo', 'bar', null],
|
||||||
[`notfound=secret`, true, '', '', new Error('secret file secret not found')]
|
[`notfound=secret`, true, '', '', new Error('secret file secret not found')]
|
||||||
])('given %p key and %p secret', async (kvp: string, file: boolean, exKey: string, exValue: string, error: Error) => {
|
])('given %p key and %p secret', async (kvp: string, file: boolean, exKey: string, exValue: string, error: Error) => {
|
||||||
try {
|
try {
|
||||||
@@ -274,9 +184,9 @@ describe('generateBuildSecret', () => {
|
|||||||
});
|
});
|
||||||
let secret: string;
|
let secret: string;
|
||||||
if (file) {
|
if (file) {
|
||||||
secret = buildx.generateBuildSecretFile(kvp);
|
secret = buildx.inputs.generateBuildSecretFile(kvp);
|
||||||
} else {
|
} else {
|
||||||
secret = buildx.generateBuildSecretString(kvp);
|
secret = buildx.inputs.generateBuildSecretString(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);
|
||||||
@@ -299,7 +209,7 @@ describe('hasLocalExporter', () => {
|
|||||||
[['" type= local" , dest=./release-out'], true],
|
[['" type= local" , dest=./release-out'], true],
|
||||||
[['.'], true]
|
[['.'], true]
|
||||||
])('given %p returns %p', async (exporters: Array<string>, expected: boolean) => {
|
])('given %p returns %p', async (exporters: Array<string>, expected: boolean) => {
|
||||||
expect(Buildx.hasLocalExporter(exporters)).toEqual(expected);
|
expect(Inputs.hasLocalExporter(exporters)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -315,7 +225,7 @@ describe('hasTarExporter', () => {
|
|||||||
[['" type= local" , dest=./release-out'], false],
|
[['" type= local" , dest=./release-out'], false],
|
||||||
[['.'], false]
|
[['.'], false]
|
||||||
])('given %p returns %p', async (exporters: Array<string>, expected: boolean) => {
|
])('given %p returns %p', async (exporters: Array<string>, expected: boolean) => {
|
||||||
expect(Buildx.hasTarExporter(exporters)).toEqual(expected);
|
expect(Inputs.hasTarExporter(exporters)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -331,7 +241,7 @@ describe('hasDockerExporter', () => {
|
|||||||
[['" type= local" , dest=./release-out'], false, undefined],
|
[['" type= local" , dest=./release-out'], false, undefined],
|
||||||
[['.'], true, true],
|
[['.'], true, true],
|
||||||
])('given %p returns %p', async (exporters: Array<string>, expected: boolean, load: boolean | undefined) => {
|
])('given %p returns %p', async (exporters: Array<string>, expected: boolean, load: boolean | undefined) => {
|
||||||
expect(Buildx.hasDockerExporter(exporters, load)).toEqual(expected);
|
expect(Inputs.hasDockerExporter(exporters, load)).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -341,7 +251,7 @@ describe('hasGitAuthTokenSecret', () => {
|
|||||||
[['A_SECRET=abcdef0123456789'], false],
|
[['A_SECRET=abcdef0123456789'], false],
|
||||||
[['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'], true],
|
[['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'], true],
|
||||||
])('given %p secret', async (kvp: Array<string>, expected: boolean) => {
|
])('given %p secret', async (kvp: Array<string>, expected: boolean) => {
|
||||||
expect(Buildx.hasGitAuthTokenSecret(kvp)).toBe(expected);
|
expect(Inputs.hasGitAuthTokenSecret(kvp)).toBe(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
102
__tests__/buildx/install.test.ts
Normal file
102
__tests__/buildx/install.test.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* 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, it, jest, test, beforeEach} from '@jest/globals';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import osm = require('os');
|
||||||
|
|
||||||
|
import {Install} from '../../src/buildx/install';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('install', () => {
|
||||||
|
// prettier-ignore
|
||||||
|
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-install-jest').split(path.sep).join(path.posix.sep);
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
test.each([
|
||||||
|
['v0.4.1', false],
|
||||||
|
['latest', false],
|
||||||
|
['v0.4.1', true],
|
||||||
|
['latest', true]
|
||||||
|
])(
|
||||||
|
'acquires %p of buildx (standalone: %p)', async (version, standalone) => {
|
||||||
|
const install = new Install({standalone: standalone});
|
||||||
|
const buildxBin = await install.install(version, tmpDir);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: add tests for arm
|
||||||
|
// prettier-ignore
|
||||||
|
test.each([
|
||||||
|
['win32', 'x64'],
|
||||||
|
['win32', 'arm64'],
|
||||||
|
['darwin', 'x64'],
|
||||||
|
['darwin', 'arm64'],
|
||||||
|
['linux', 'x64'],
|
||||||
|
['linux', 'arm64'],
|
||||||
|
['linux', 'ppc64'],
|
||||||
|
['linux', 's390x'],
|
||||||
|
])(
|
||||||
|
'acquires buildx for %s/%s', async (os, arch) => {
|
||||||
|
jest.spyOn(osm, 'platform').mockImplementation(() => os);
|
||||||
|
jest.spyOn(osm, 'arch').mockImplementation(() => arch);
|
||||||
|
const install = new Install();
|
||||||
|
const buildxBin = await install.install('latest', tmpDir);
|
||||||
|
expect(fs.existsSync(buildxBin)).toBe(true);
|
||||||
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
|
|
||||||
|
it('returns latest buildx GitHub release', async () => {
|
||||||
|
const release = await Install.getRelease('latest');
|
||||||
|
expect(release).not.toBeNull();
|
||||||
|
expect(release?.tag_name).not.toEqual('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRelease', () => {
|
||||||
|
it('returns latest buildx GitHub release', async () => {
|
||||||
|
const release = await Install.getRelease('latest');
|
||||||
|
expect(release).not.toBeNull();
|
||||||
|
expect(release?.tag_name).not.toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns v0.10.1 buildx GitHub release', async () => {
|
||||||
|
const release = await Install.getRelease('v0.10.1');
|
||||||
|
expect(release).not.toBeNull();
|
||||||
|
expect(release?.id).toEqual(90346950);
|
||||||
|
expect(release?.tag_name).toEqual('v0.10.1');
|
||||||
|
expect(release?.html_url).toEqual('https://github.com/docker/buildx/releases/tag/v0.10.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns v0.2.2 buildx GitHub release', async () => {
|
||||||
|
const release = await Install.getRelease('v0.2.2');
|
||||||
|
expect(release).not.toBeNull();
|
||||||
|
expect(release?.id).toEqual(17671545);
|
||||||
|
expect(release?.tag_name).toEqual('v0.2.2');
|
||||||
|
expect(release?.html_url).toEqual('https://github.com/docker/buildx/releases/tag/v0.2.2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('unknown release', async () => {
|
||||||
|
await expect(Install.getRelease('foo')).rejects.toThrowError(new Error('Cannot find Buildx release foo in https://raw.githubusercontent.com/docker/buildx/master/.github/releases.json'));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,11 +1,28 @@
|
|||||||
import fs from 'fs';
|
/**
|
||||||
import path from 'path';
|
* Copyright 2023 actions-toolkit authors
|
||||||
import rimraf from 'rimraf';
|
*
|
||||||
|
* 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 fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as rimraf from 'rimraf';
|
||||||
import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
|
import {describe, expect, jest, it, beforeEach, afterEach} from '@jest/globals';
|
||||||
|
|
||||||
import {Context} from '../src/context';
|
import {Context} from '../src/context';
|
||||||
|
|
||||||
const tmpDir = path.join('/tmp/.docker-actions-toolkit-jest').split(path.sep).join(path.posix.sep);
|
// prettier-ignore
|
||||||
|
const tmpDir = path.join(process.env.TEMP || '/tmp', 'context-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);
|
||||||
|
|
||||||
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
jest.spyOn(Context.prototype, 'tmpDir').mockImplementation((): string => {
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
/**
|
||||||
|
* 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 {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
import path from 'path';
|
||||||
|
import osm = require('os');
|
||||||
|
|
||||||
import {Docker} from '../src/docker';
|
import {Docker} from '../src/docker';
|
||||||
|
|
||||||
@@ -7,10 +25,32 @@ beforeEach(() => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('configDir', () => {
|
||||||
|
const originalEnv = process.env;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
DOCKER_CONFIG: '/var/docker/config'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv;
|
||||||
|
});
|
||||||
|
it('returns default', async () => {
|
||||||
|
process.env.DOCKER_CONFIG = '';
|
||||||
|
jest.spyOn(osm, 'homedir').mockImplementation(() => path.join('/tmp', 'home'));
|
||||||
|
expect(Docker.configDir).toEqual(path.join('/tmp', 'home', '.docker'));
|
||||||
|
});
|
||||||
|
it('returns from env', async () => {
|
||||||
|
expect(Docker.configDir).toEqual('/var/docker/config');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('isAvailable', () => {
|
describe('isAvailable', () => {
|
||||||
it('cli', () => {
|
it('cli', () => {
|
||||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
Docker.isAvailable();
|
Docker.isAvailable;
|
||||||
// eslint-disable-next-line jest/no-standalone-expect
|
// eslint-disable-next-line jest/no-standalone-expect
|
||||||
expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
|
expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
|
||||||
silent: true,
|
silent: true,
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
||||||
|
|
||||||
import {Git} from '../src/git';
|
import {Git} from '../src/git';
|
||||||
|
|||||||
@@ -1,26 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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, 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 {GitHub, GitHubRepo} from '../src/github';
|
import {GitHub} from '../src/github';
|
||||||
|
import {GitHubRepo} from '../src/types/github';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
import * as repoFixture from './fixtures/repo.json';
|
import repoFixture from './fixtures/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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('repoData', () => {
|
||||||
|
it('returns GitHub repository', async () => {
|
||||||
|
const github = new GitHub();
|
||||||
|
expect((await github.repoData()).name).toEqual('Hello-World');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('context', () => {
|
describe('context', () => {
|
||||||
it('returns repository name from payload', async () => {
|
it('returns repository name from payload', async () => {
|
||||||
const github = new GitHub();
|
expect(GitHub.context.payload.repository?.name).toEqual('test-docker-action');
|
||||||
expect(github.context.payload.repository?.name).toEqual('test-docker-action');
|
|
||||||
});
|
});
|
||||||
it('is repository private', async () => {
|
it('is repository private', async () => {
|
||||||
const github = new GitHub();
|
expect(GitHub.context.payload.repository?.private).toEqual(true);
|
||||||
expect(github.context.payload.repository?.private).toEqual(true);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -38,12 +60,31 @@ describe('serverURL', () => {
|
|||||||
});
|
});
|
||||||
it('returns default', async () => {
|
it('returns default', async () => {
|
||||||
process.env.GITHUB_SERVER_URL = '';
|
process.env.GITHUB_SERVER_URL = '';
|
||||||
const github = new GitHub();
|
expect(GitHub.serverURL).toEqual('https://github.com');
|
||||||
expect(github.serverURL).toEqual('https://github.com');
|
|
||||||
});
|
});
|
||||||
it('returns from env', async () => {
|
it('returns from env', async () => {
|
||||||
const github = new GitHub();
|
expect(GitHub.serverURL).toEqual('https://foo.github.com');
|
||||||
expect(github.serverURL).toEqual('https://foo.github.com');
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('apiURL', () => {
|
||||||
|
const originalEnv = process.env;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = {
|
||||||
|
...originalEnv,
|
||||||
|
GITHUB_API_URL: 'https://bar.github.com'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
process.env = originalEnv;
|
||||||
|
});
|
||||||
|
it('returns default', async () => {
|
||||||
|
process.env.GITHUB_API_URL = '';
|
||||||
|
expect(GitHub.apiURL).toEqual('https://api.github.com');
|
||||||
|
});
|
||||||
|
it('returns from env', async () => {
|
||||||
|
expect(GitHub.apiURL).toEqual('https://bar.github.com');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,21 +101,12 @@ describe('actionsRuntimeToken', () => {
|
|||||||
});
|
});
|
||||||
it('empty', async () => {
|
it('empty', async () => {
|
||||||
process.env.ACTIONS_RUNTIME_TOKEN = '';
|
process.env.ACTIONS_RUNTIME_TOKEN = '';
|
||||||
const github = new GitHub();
|
expect(GitHub.actionsRuntimeToken).toEqual({});
|
||||||
expect(github.actionsRuntimeToken).toEqual({});
|
|
||||||
});
|
});
|
||||||
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 github = new GitHub();
|
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('repoData', () => {
|
|
||||||
it('returns GitHub repository', async () => {
|
|
||||||
const github = new GitHub();
|
|
||||||
expect((await github.repoData()).name).toEqual('Hello-World');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
ARG NODE_VERSION=16
|
ARG NODE_VERSION=16
|
||||||
ARG DOCKER_VERSION=20.10.22
|
ARG DOCKER_VERSION=20.10.22
|
||||||
ARG BUILDX_VERSION=0.10.0
|
ARG BUILDX_VERSION=0.10.0
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
group "default" {
|
group "default" {
|
||||||
targets = ["build"]
|
targets = ["build"]
|
||||||
}
|
}
|
||||||
@@ -7,7 +21,7 @@ group "pre-checkin" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group "validate" {
|
group "validate" {
|
||||||
targets = ["lint", "vendor-validate"]
|
targets = ["lint", "vendor-validate", "license-validate"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "build" {
|
target "build" {
|
||||||
@@ -69,3 +83,15 @@ target "publish" {
|
|||||||
output = ["type=cacheonly"]
|
output = ["type=cacheonly"]
|
||||||
secret = ["id=NODE_AUTH_TOKEN,env=NODE_AUTH_TOKEN"]
|
secret = ["id=NODE_AUTH_TOKEN,env=NODE_AUTH_TOKEN"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target "license-validate" {
|
||||||
|
dockerfile = "./hack/dockerfiles/license.Dockerfile"
|
||||||
|
target = "validate"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
|
}
|
||||||
|
|
||||||
|
target "license-update" {
|
||||||
|
dockerfile = "./hack/dockerfiles/license.Dockerfile"
|
||||||
|
target = "update"
|
||||||
|
output = ["."]
|
||||||
|
}
|
||||||
|
|||||||
47
hack/dockerfiles/license.Dockerfile
Normal file
47
hack/dockerfiles/license.Dockerfile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
ARG LICENSE_HOLDER="actions-toolkit authors"
|
||||||
|
ARG LICENSE_TYPE="apache"
|
||||||
|
ARG LICENSE_FILES=".*\(Dockerfile\|Makefile\|\.js\|\.ts\|\.hcl\|\.sh\)"
|
||||||
|
ARG ADDLICENSE_VERSION="v1.0.0"
|
||||||
|
|
||||||
|
FROM ghcr.io/google/addlicense:${ADDLICENSE_VERSION} AS addlicense
|
||||||
|
|
||||||
|
FROM alpine:3.17 AS base
|
||||||
|
WORKDIR /src
|
||||||
|
RUN apk add --no-cache cpio findutils git
|
||||||
|
|
||||||
|
FROM base AS set
|
||||||
|
ARG LICENSE_HOLDER
|
||||||
|
ARG LICENSE_TYPE
|
||||||
|
ARG LICENSE_FILES
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=from=addlicense,source=/app/addlicense,target=/usr/bin/addlicense \
|
||||||
|
find . -regex "${LICENSE_FILES}" -not -path "./.yarn/*" -not -path "./node_modules/*" | xargs addlicense -c "$LICENSE_HOLDER" -l "$LICENSE_TYPE" && \
|
||||||
|
mkdir /out && \
|
||||||
|
find . -regex "${LICENSE_FILES}" -not -path "./.yarn/*" -not -path "./node_modules/*" | cpio -pdm /out
|
||||||
|
|
||||||
|
FROM scratch AS update
|
||||||
|
COPY --from=set /out /
|
||||||
|
|
||||||
|
FROM base AS validate
|
||||||
|
ARG LICENSE_HOLDER
|
||||||
|
ARG LICENSE_TYPE
|
||||||
|
ARG LICENSE_FILES
|
||||||
|
RUN --mount=type=bind,target=. \
|
||||||
|
--mount=from=addlicense,source=/app/addlicense,target=/usr/bin/addlicense \
|
||||||
|
find . -regex "${LICENSE_FILES}" -not -path "./.yarn/*" -not -path "./node_modules/*" | xargs addlicense -check -c "$LICENSE_HOLDER" -l "$LICENSE_TYPE"
|
||||||
@@ -1,7 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* 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 fs from 'fs';
|
||||||
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-')).split(path.sep).join(path.posix.sep);
|
||||||
|
|
||||||
process.env = Object.assign({}, process.env, {
|
process.env = Object.assign({}, process.env, {
|
||||||
|
TEMP: tmpDir,
|
||||||
GITHUB_REPOSITORY: 'docker/actions-toolkit',
|
GITHUB_REPOSITORY: 'docker/actions-toolkit',
|
||||||
RUNNER_TEMP: '/tmp/github_runner',
|
RUNNER_TEMP: path.join(tmpDir, 'runner-temp').split(path.sep).join(path.posix.sep),
|
||||||
RUNNER_TOOL_CACHE: '/tmp/github_tool_cache'
|
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache').split(path.sep).join(path.posix.sep)
|
||||||
}) as {
|
}) as {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
|
|||||||
13
package.json
13
package.json
@@ -3,8 +3,12 @@
|
|||||||
"description": "Toolkit for Docker (GitHub) Actions",
|
"description": "Toolkit for Docker (GitHub) Actions",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
"lint": "yarn run prettier && yarn run eslint",
|
||||||
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
|
"format": "yarn run prettier:fix && yarn run eslint:fix",
|
||||||
|
"eslint": "eslint --max-warnings=0 .",
|
||||||
|
"eslint:fix": "eslint --fix .",
|
||||||
|
"prettier": "prettier --check \"./**/*.ts\"",
|
||||||
|
"prettier:fix": "prettier --write \"./**/*.ts\"",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test-coverage": "jest --coverage"
|
"test-coverage": "jest --coverage"
|
||||||
},
|
},
|
||||||
@@ -40,7 +44,9 @@
|
|||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^5.1.1",
|
"@actions/github": "^5.1.1",
|
||||||
"csv-parse": "^5.3.3",
|
"@actions/http-client": "^2.0.1",
|
||||||
|
"@actions/tool-cache": "^2.0.1",
|
||||||
|
"csv-parse": "^5.3.4",
|
||||||
"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"
|
||||||
@@ -56,6 +62,7 @@
|
|||||||
"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",
|
||||||
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-jest": "^26.9.0",
|
"eslint-plugin-jest": "^26.9.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
|
|||||||
@@ -1,11 +1,29 @@
|
|||||||
import fs from 'fs';
|
/**
|
||||||
|
* 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 core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
|
||||||
import {Context} from './context';
|
import {Context} from '../context';
|
||||||
import {Buildx} from './buildx';
|
import {Buildx} from '../buildx/buildx';
|
||||||
import {Builder, BuilderInfo} from './builder';
|
import {Builder} from '../buildx/builder';
|
||||||
|
import {Config} from './config';
|
||||||
|
|
||||||
|
import {BuilderInfo} from '../types/builder';
|
||||||
|
|
||||||
export interface BuildKitOpts {
|
export interface BuildKitOpts {
|
||||||
context: Context;
|
context: Context;
|
||||||
@@ -17,8 +35,11 @@ export class BuildKit {
|
|||||||
private readonly buildx: Buildx;
|
private readonly buildx: Buildx;
|
||||||
private containerNamePrefix = 'buildx_buildkit_';
|
private containerNamePrefix = 'buildx_buildkit_';
|
||||||
|
|
||||||
|
public readonly config: Config;
|
||||||
|
|
||||||
constructor(opts: BuildKitOpts) {
|
constructor(opts: BuildKitOpts) {
|
||||||
this.context = opts.context;
|
this.context = opts.context;
|
||||||
|
this.config = new Config(this.context);
|
||||||
this.buildx =
|
this.buildx =
|
||||||
opts?.buildx ||
|
opts?.buildx ||
|
||||||
new Buildx({
|
new Buildx({
|
||||||
@@ -26,14 +47,6 @@ export class BuildKit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getBuilderInfo(name: string): Promise<BuilderInfo> {
|
|
||||||
const builder = new Builder({
|
|
||||||
context: this.context,
|
|
||||||
buildx: this.buildx
|
|
||||||
});
|
|
||||||
return builder.inspect(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getVersion(builderName: string): Promise<string | undefined> {
|
public async getVersion(builderName: string): Promise<string | undefined> {
|
||||||
const builderInfo = await this.getBuilderInfo(builderName);
|
const builderInfo = await this.getBuilderInfo(builderName);
|
||||||
if (builderInfo.nodes.length == 0) {
|
if (builderInfo.nodes.length == 0) {
|
||||||
@@ -102,23 +115,11 @@ export class BuildKit {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public generateConfigInline(s: string): string {
|
private async getBuilderInfo(name: string): Promise<BuilderInfo> {
|
||||||
return this.generateConfig(s, false);
|
const builder = new Builder({
|
||||||
}
|
context: this.context,
|
||||||
|
buildx: this.buildx
|
||||||
public generateConfigFile(s: string): string {
|
});
|
||||||
return this.generateConfig(s, true);
|
return builder.inspect(name);
|
||||||
}
|
|
||||||
|
|
||||||
private generateConfig(s: string, file: boolean): string {
|
|
||||||
if (file) {
|
|
||||||
if (!fs.existsSync(s)) {
|
|
||||||
throw new Error(`config file ${s} not found`);
|
|
||||||
}
|
|
||||||
s = fs.readFileSync(s, {encoding: 'utf-8'});
|
|
||||||
}
|
|
||||||
const configFile = this.context.tmpName({tmpdir: this.context.tmpDir()});
|
|
||||||
fs.writeFileSync(configFile, s);
|
|
||||||
return configFile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
47
src/buildkit/config.ts
Normal file
47
src/buildkit/config.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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 fs from 'fs';
|
||||||
|
|
||||||
|
import {Context} from '../context';
|
||||||
|
|
||||||
|
export class Config {
|
||||||
|
private readonly context: Context;
|
||||||
|
|
||||||
|
constructor(context: Context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateFromString(s: string): string {
|
||||||
|
return this.generate(s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateFromFile(s: string): string {
|
||||||
|
return this.generate(s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generate(s: string, file: boolean): string {
|
||||||
|
if (file) {
|
||||||
|
if (!fs.existsSync(s)) {
|
||||||
|
throw new Error(`config file ${s} not found`);
|
||||||
|
}
|
||||||
|
s = fs.readFileSync(s, {encoding: 'utf-8'});
|
||||||
|
}
|
||||||
|
const configFile = this.context.tmpName({tmpdir: this.context.tmpDir()});
|
||||||
|
fs.writeFileSync(configFile, s);
|
||||||
|
return configFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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 exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
import {Buildx} from './buildx';
|
import {Buildx} from './buildx';
|
||||||
import {Context} from './context';
|
import {Context} from '../context';
|
||||||
|
|
||||||
export interface BuilderInfo {
|
import {BuilderInfo, NodeInfo} from '../types/builder';
|
||||||
name?: string;
|
|
||||||
driver?: string;
|
|
||||||
lastActivity?: Date;
|
|
||||||
nodes: NodeInfo[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NodeInfo {
|
|
||||||
name?: string;
|
|
||||||
endpoint?: string;
|
|
||||||
driverOpts?: Array<string>;
|
|
||||||
status?: string;
|
|
||||||
buildkitdFlags?: string;
|
|
||||||
buildkitVersion?: string;
|
|
||||||
platforms?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BuilderOpts {
|
export interface BuilderOpts {
|
||||||
context: Context;
|
context: Context;
|
||||||
120
src/buildx/buildx.ts
Normal file
120
src/buildx/buildx.ts
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* 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 exec from '@actions/exec';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
|
||||||
|
import {Docker} from '../docker';
|
||||||
|
import {Context} from '../context';
|
||||||
|
import {Inputs} from './inputs';
|
||||||
|
import {Install} from './install';
|
||||||
|
|
||||||
|
export interface BuildxOpts {
|
||||||
|
context: Context;
|
||||||
|
standalone?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Buildx {
|
||||||
|
private readonly context: Context;
|
||||||
|
private _version: string | undefined;
|
||||||
|
|
||||||
|
public readonly inputs: Inputs;
|
||||||
|
public readonly install: Install;
|
||||||
|
public readonly standalone: boolean;
|
||||||
|
|
||||||
|
constructor(opts: BuildxOpts) {
|
||||||
|
this.context = opts.context;
|
||||||
|
this.inputs = new Inputs(this.context);
|
||||||
|
this.install = new Install({standalone: opts.standalone});
|
||||||
|
this.standalone = opts?.standalone ?? !Docker.isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCommand(args: Array<string>) {
|
||||||
|
return {
|
||||||
|
command: this.standalone ? 'buildx' : 'docker',
|
||||||
|
args: this.standalone ? args : ['buildx', ...args]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async isAvailable(): Promise<boolean> {
|
||||||
|
const cmd = this.getCommand([]);
|
||||||
|
return await exec
|
||||||
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return res.exitCode == 0;
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
.catch(error => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async printInspect(name: string): Promise<void> {
|
||||||
|
const cmd = this.getCommand(['inspect', name]);
|
||||||
|
await exec.exec(cmd.command, cmd.args, {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get version() {
|
||||||
|
return (async () => {
|
||||||
|
if (!this._version) {
|
||||||
|
const cmd = this.getCommand(['version']);
|
||||||
|
this._version = await exec
|
||||||
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr.trim());
|
||||||
|
}
|
||||||
|
return Buildx.parseVersion(res.stdout.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this._version;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async printVersion() {
|
||||||
|
const cmd = this.getCommand(['version']);
|
||||||
|
await exec.exec(cmd.command, cmd.args, {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async versionSatisfies(range: string, version?: string): Promise<boolean> {
|
||||||
|
const ver = version ?? (await this.version);
|
||||||
|
if (!ver) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,95 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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 fs from 'fs';
|
import fs from 'fs';
|
||||||
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 {parse} from 'csv-parse/sync';
|
import {parse} from 'csv-parse/sync';
|
||||||
import * as semver from 'semver';
|
|
||||||
|
|
||||||
import {Docker} from './docker';
|
import {Context} from '../context';
|
||||||
import {Context} from './context';
|
|
||||||
|
|
||||||
export interface BuildxOpts {
|
export class Inputs {
|
||||||
context: Context;
|
|
||||||
standalone?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Buildx {
|
|
||||||
private readonly context: Context;
|
private readonly context: Context;
|
||||||
public standalone: boolean;
|
|
||||||
public version: Promise<string>;
|
|
||||||
|
|
||||||
constructor(opts: BuildxOpts) {
|
constructor(context: Context) {
|
||||||
this.context = opts.context;
|
this.context = context;
|
||||||
this.standalone = opts?.standalone ?? !Docker.isAvailable();
|
|
||||||
this.version = this.getVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCommand(args: Array<string>) {
|
|
||||||
return {
|
|
||||||
command: this.standalone ? 'buildx' : 'docker',
|
|
||||||
args: this.standalone ? args : ['buildx', ...args]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public async isAvailable(): Promise<boolean> {
|
|
||||||
const cmd = this.getCommand([]);
|
|
||||||
return await exec
|
|
||||||
.getExecOutput(cmd.command, cmd.args, {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return res.exitCode == 0;
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
.catch(error => {
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async printInspect(name: string): Promise<void> {
|
|
||||||
const cmd = this.getCommand(['inspect', name]);
|
|
||||||
await exec.exec(cmd.command, cmd.args, {
|
|
||||||
failOnStdErr: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getVersion(): Promise<string> {
|
|
||||||
const cmd = this.getCommand(['version']);
|
|
||||||
return await exec
|
|
||||||
.getExecOutput(cmd.command, cmd.args, {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
if (res.stderr.length > 0 && res.exitCode != 0) {
|
|
||||||
throw new Error(res.stderr.trim());
|
|
||||||
}
|
|
||||||
return Buildx.parseVersion(res.stdout.trim());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async printVersion() {
|
|
||||||
const cmd = this.getCommand(['version']);
|
|
||||||
await exec.exec(cmd.command, cmd.args, {
|
|
||||||
failOnStdErr: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async versionSatisfies(range: string, version?: string): Promise<boolean> {
|
|
||||||
const ver = version ?? (await this.version);
|
|
||||||
return semver.satisfies(ver, range) || /^[0-9a-f]{7}$/.exec(ver) !== null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBuildImageIDFilePath(): string {
|
public getBuildImageIDFilePath(): string {
|
||||||
@@ -197,15 +133,15 @@ export class Buildx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static hasLocalExporter(exporters: string[]): boolean {
|
public static hasLocalExporter(exporters: string[]): boolean {
|
||||||
return Buildx.hasExporterType('local', exporters);
|
return Inputs.hasExporterType('local', exporters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static hasTarExporter(exporters: string[]): boolean {
|
public static hasTarExporter(exporters: string[]): boolean {
|
||||||
return Buildx.hasExporterType('tar', exporters);
|
return Inputs.hasExporterType('tar', exporters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static hasDockerExporter(exporters: string[], load?: boolean): boolean {
|
public static hasDockerExporter(exporters: string[], load?: boolean): boolean {
|
||||||
return load ?? Buildx.hasExporterType('docker', exporters);
|
return load ?? Inputs.hasExporterType('docker', exporters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static hasExporterType(name: string, exporters: string[]): boolean {
|
public static hasExporterType(name: string, exporters: string[]): boolean {
|
||||||
142
src/buildx/install.ts
Normal file
142
src/buildx/install.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* 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 fs from 'fs';
|
||||||
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as httpm from '@actions/http-client';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as util from 'util';
|
||||||
|
|
||||||
|
import {GitHubRelease} from '../types/github';
|
||||||
|
|
||||||
|
export interface InstallOpts {
|
||||||
|
standalone?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Install {
|
||||||
|
private readonly opts: InstallOpts;
|
||||||
|
|
||||||
|
constructor(opts?: InstallOpts) {
|
||||||
|
this.opts = opts || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async install(version: string, dest: string): Promise<string> {
|
||||||
|
const release: GitHubRelease = await Install.getRelease(version);
|
||||||
|
const fversion = release.tag_name.replace(/^v+|v+$/g, '');
|
||||||
|
let toolPath: string;
|
||||||
|
toolPath = tc.find('buildx', fversion, this.platform());
|
||||||
|
if (!toolPath) {
|
||||||
|
const c = semver.clean(fversion) || '';
|
||||||
|
if (!semver.valid(c)) {
|
||||||
|
throw new Error(`Invalid Buildx version "${fversion}".`);
|
||||||
|
}
|
||||||
|
toolPath = await this.download(fversion);
|
||||||
|
}
|
||||||
|
if (this.opts.standalone) {
|
||||||
|
return this.setStandalone(toolPath, dest);
|
||||||
|
}
|
||||||
|
return this.setPlugin(toolPath, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setStandalone(toolPath: string, dest: string): Promise<string> {
|
||||||
|
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||||
|
const binDir = path.join(dest, 'bin');
|
||||||
|
if (!fs.existsSync(binDir)) {
|
||||||
|
fs.mkdirSync(binDir, {recursive: true});
|
||||||
|
}
|
||||||
|
const filename: string = os.platform() == 'win32' ? 'buildx.exe' : 'buildx';
|
||||||
|
const buildxPath: string = path.join(binDir, filename);
|
||||||
|
fs.copyFileSync(toolBinPath, buildxPath);
|
||||||
|
fs.chmodSync(buildxPath, '0755');
|
||||||
|
core.addPath(binDir);
|
||||||
|
return buildxPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setPlugin(toolPath: string, dest: string): Promise<string> {
|
||||||
|
const toolBinPath = path.join(toolPath, os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx');
|
||||||
|
const pluginsDir: string = path.join(dest, 'cli-plugins');
|
||||||
|
if (!fs.existsSync(pluginsDir)) {
|
||||||
|
fs.mkdirSync(pluginsDir, {recursive: true});
|
||||||
|
}
|
||||||
|
const filename: string = os.platform() == 'win32' ? 'docker-buildx.exe' : 'docker-buildx';
|
||||||
|
const pluginPath: string = path.join(pluginsDir, filename);
|
||||||
|
fs.copyFileSync(toolBinPath, pluginPath);
|
||||||
|
fs.chmodSync(pluginPath, '0755');
|
||||||
|
return pluginPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async download(version: string): Promise<string> {
|
||||||
|
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 downloadPath = await tc.downloadTool(downloadURL);
|
||||||
|
core.debug(`downloadURL: ${downloadURL}`);
|
||||||
|
core.debug(`downloadPath: ${downloadPath}`);
|
||||||
|
return await tc.cacheFile(downloadPath, targetFile, 'buildx', version);
|
||||||
|
}
|
||||||
|
|
||||||
|
private platform(): string {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const arm_version = (process.config.variables as any).arm_version;
|
||||||
|
return `${os.platform()}-${os.arch()}${arm_version ? 'v' + arm_version : ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private filename(version: string): string {
|
||||||
|
let arch: string;
|
||||||
|
switch (os.arch()) {
|
||||||
|
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 = os.arch();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const platform: string = os.platform() == 'win32' ? 'windows' : os.platform();
|
||||||
|
const ext: string = os.platform() == 'win32' ? '.exe' : '';
|
||||||
|
return util.format('buildx-v%s.%s-%s%s', version, platform, arch, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getRelease(version: string): Promise<GitHubRelease> {
|
||||||
|
// FIXME: Use https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-releases.json when repo public
|
||||||
|
const url = `https://raw.githubusercontent.com/docker/buildx/master/.github/releases.json`;
|
||||||
|
const http: httpm.HttpClient = new httpm.HttpClient('docker-actions-toolkit');
|
||||||
|
const resp: httpm.HttpClientResponse = await http.get(url);
|
||||||
|
const body = await resp.readBody();
|
||||||
|
const statusCode = resp.message.statusCode || 500;
|
||||||
|
if (statusCode >= 400) {
|
||||||
|
throw new Error(`Failed to get Buildx release ${version} from ${url} with status code ${statusCode}: ${body}`);
|
||||||
|
}
|
||||||
|
const releases = <Record<string, GitHubRelease>>JSON.parse(body);
|
||||||
|
if (!releases[version]) {
|
||||||
|
throw new Error(`Cannot find Buildx release ${version} in ${url}`);
|
||||||
|
}
|
||||||
|
return releases[version];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 fs from 'fs';
|
import fs from 'fs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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 os from 'os';
|
||||||
|
import path from 'path';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
export class Docker {
|
export class Docker {
|
||||||
public static isAvailable(): boolean {
|
static get configDir(): string {
|
||||||
|
return process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
|
||||||
|
}
|
||||||
|
|
||||||
|
static get isAvailable(): boolean {
|
||||||
let dockerAvailable = false;
|
let dockerAvailable = false;
|
||||||
exec
|
exec
|
||||||
.getExecOutput('docker', undefined, {
|
.getExecOutput('docker', undefined, {
|
||||||
@@ -23,7 +45,7 @@ export class Docker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async printVersion(standalone?: boolean) {
|
public static async printVersion(standalone?: boolean) {
|
||||||
const noDocker = standalone ?? !Docker.isAvailable();
|
const noDocker = standalone ?? !Docker.isAvailable;
|
||||||
if (noDocker) {
|
if (noDocker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -33,7 +55,7 @@ export class Docker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async printInfo(standalone?: boolean) {
|
public static async printInfo(standalone?: boolean) {
|
||||||
const noDocker = standalone ?? !Docker.isAvailable();
|
const noDocker = standalone ?? !Docker.isAvailable;
|
||||||
if (noDocker) {
|
if (noDocker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/git.ts
16
src/git.ts
@@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
export class Git {
|
export class Git {
|
||||||
|
|||||||
@@ -1,41 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* 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 {GitHub as Octokit} from '@actions/github/lib/utils';
|
import {GitHub as Octokit} from '@actions/github/lib/utils';
|
||||||
import * as github from '@actions/github';
|
import * as github from '@actions/github';
|
||||||
import {components as OctoOpenApiTypes} from '@octokit/openapi-types';
|
|
||||||
import jwt_decode, {JwtPayload} from 'jwt-decode';
|
|
||||||
import {Context} from '@actions/github/lib/context';
|
import {Context} from '@actions/github/lib/context';
|
||||||
|
import jwt_decode from 'jwt-decode';
|
||||||
|
|
||||||
export type GitHubRepo = OctoOpenApiTypes['schemas']['repository'];
|
import {GitHubActionsRuntimeToken, GitHubRepo} from './types/github';
|
||||||
|
|
||||||
export interface GitHubActionsRuntimeToken extends JwtPayload {
|
|
||||||
ac?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GitHubOpts {
|
export interface GitHubOpts {
|
||||||
token?: string;
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GitHub {
|
export class GitHub {
|
||||||
public static readonly serverURL: string = process.env.GITHUB_SERVER_URL || 'https://github.com';
|
|
||||||
public readonly octokit: InstanceType<typeof Octokit>;
|
public readonly octokit: InstanceType<typeof Octokit>;
|
||||||
|
|
||||||
constructor(opts?: GitHubOpts) {
|
constructor(opts?: GitHubOpts) {
|
||||||
this.octokit = github.getOctokit(`${opts?.token}`);
|
this.octokit = github.getOctokit(`${opts?.token}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
get context(): Context {
|
|
||||||
return github.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
get serverURL(): string {
|
|
||||||
return process.env.GITHUB_SERVER_URL || 'https://github.com';
|
|
||||||
}
|
|
||||||
|
|
||||||
get actionsRuntimeToken(): GitHubActionsRuntimeToken {
|
|
||||||
const token = process.env['ACTIONS_RUNTIME_TOKEN'] || '';
|
|
||||||
return token ? jwt_decode<GitHubActionsRuntimeToken>(token) : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public repoData(): Promise<GitHubRepo> {
|
public repoData(): Promise<GitHubRepo> {
|
||||||
return this.octokit.rest.repos.get({...github.context.repo}).then(response => response.data as GitHubRepo);
|
return this.octokit.rest.repos.get({...github.context.repo}).then(response => response.data as GitHubRepo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get context(): Context {
|
||||||
|
return github.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get serverURL(): string {
|
||||||
|
return process.env.GITHUB_SERVER_URL || 'https://github.com';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get apiURL(): string {
|
||||||
|
return process.env.GITHUB_API_URL || 'https://api.github.com';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get actionsRuntimeToken(): GitHubActionsRuntimeToken {
|
||||||
|
const token = process.env['ACTIONS_RUNTIME_TOKEN'] || '';
|
||||||
|
return token ? jwt_decode<GitHubActionsRuntimeToken>(token) : {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
import {Context} from './context';
|
/**
|
||||||
import {Buildx} from './buildx';
|
* Copyright 2023 actions-toolkit authors
|
||||||
import {BuildKit} from './buildkit';
|
*
|
||||||
import {GitHub} from './github';
|
* 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 {Builder, BuilderOpts, BuilderInfo, NodeInfo} from './builder';
|
import {Context} from './context';
|
||||||
export {BuildKit, BuildKitOpts} from './buildkit';
|
import {Buildx} from './buildx/buildx';
|
||||||
export {Buildx, BuildxOpts} from './buildx';
|
import {BuildKit} from './buildkit/buildkit';
|
||||||
export {Context} from './context';
|
import {GitHub} from './github';
|
||||||
export {Docker} from './docker';
|
|
||||||
export {Git} from './git';
|
|
||||||
export {GitHub, GitHubRepo, GitHubActionsRuntimeToken} from './github';
|
|
||||||
export {Util} from './util';
|
|
||||||
|
|
||||||
export interface ToolkitOpts {
|
export interface ToolkitOpts {
|
||||||
/**
|
/**
|
||||||
|
|||||||
32
src/types/builder.ts
Normal file
32
src/types/builder.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 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 BuilderInfo {
|
||||||
|
name?: string;
|
||||||
|
driver?: string;
|
||||||
|
lastActivity?: Date;
|
||||||
|
nodes: NodeInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeInfo {
|
||||||
|
name?: string;
|
||||||
|
endpoint?: string;
|
||||||
|
driverOpts?: Array<string>;
|
||||||
|
status?: string;
|
||||||
|
buildkitdFlags?: string;
|
||||||
|
buildkitVersion?: string;
|
||||||
|
platforms?: string;
|
||||||
|
}
|
||||||
31
src/types/github.ts
Normal file
31
src/types/github.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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 {components as OctoOpenApiTypes} from '@octokit/openapi-types';
|
||||||
|
import {JwtPayload} from 'jwt-decode';
|
||||||
|
|
||||||
|
export interface GitHubRelease {
|
||||||
|
id: number;
|
||||||
|
tag_name: string;
|
||||||
|
html_url: string;
|
||||||
|
assets: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GitHubRepo = OctoOpenApiTypes['schemas']['repository'];
|
||||||
|
|
||||||
|
export interface GitHubActionsRuntimeToken extends JwtPayload {
|
||||||
|
ac?: string;
|
||||||
|
}
|
||||||
16
src/util.ts
16
src/util.ts
@@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 core from '@actions/core';
|
||||||
import {parse} from 'csv-parse/sync';
|
import {parse} from 'csv-parse/sync';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user