Merge pull request #62 from crazy-max/workflow

Enhance workflow
This commit is contained in:
CrazyMax 2021-04-02 11:23:21 +02:00 committed by GitHub
commit d3872b2920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 184 additions and 149 deletions

2
.dockerignore Normal file

@ -0,0 +1,2 @@
/coverage
/node_modules

@ -2,35 +2,24 @@
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license)
to the public under the [project's open source license](LICENSE).
## Submitting a pull request ## Submitting a pull request
1. [Fork](https://github.com/docker/setup-buildx-action/fork) and clone the repository 1. [Fork](https://github.com/docker/setup-buildx-action/fork) and clone the repository
2. Configure and install the dependencies: `yarn install` 2. Configure and install the dependencies: `yarn install`
3. Create a new branch: `git checkout -b my-branch-name` 3. Create a new branch: `git checkout -b my-branch-name`
4. Make your change, add tests, and make sure the tests still pass 4. Make your changes
5. Run pre-checkin: `yarn run pre-checkin` 5. Make sure the tests pass: `docker buildx bake test`
6. Push to your fork and [submit a pull request](https://github.com/docker/setup-buildx-action/compare) 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin`
7. Pat yourself on the back and wait for your pull request to be reviewed and merged. 7. Validate all code has correctly formatted and built: `docker buildx bake validate`
8. Push to your fork and [submit a pull request](https://github.com/docker/setup-buildx-action/compare)
## Container based developer flow 9. Pat your self on the back and wait for your pull request to be reviewed and merged.
If you don't want to maintain a Node developer environment that fits this project you can use containerized commands instead of invoking yarn directly.
```
# format code and build javascript artifacts
docker buildx bake pre-checkin
# validate all code has correctly formatted and built
docker buildx bake validate
# run tests
docker buildx bake test
```
Here are a few things you can do that will increase the likelihood of your pull request being accepted: Here are a few things you can do that will increase the likelihood of your pull request being accepted:
- Write tests.
- Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
- We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**. - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
@ -39,5 +28,5 @@ Here are a few things you can do that will increase the likelihood of your pull
## Resources ## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) - [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
- [GitHub Help](https://help.github.com) - [GitHub Help](https://docs.github.com/en)

@ -30,4 +30,5 @@ about: Create a report to help us improve
### Logs ### Logs
> Download the [log file of your build](https://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#downloading-logs) and [attach it](https://help.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue. > Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
> and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

@ -1,18 +1,18 @@
name: ci name: ci
on: on:
schedule:
- cron: '0 10 * * *' # everyday at 10am
push: push:
branches: branches:
- master - 'master'
- releases/v* - 'releases/v*'
paths-ignore: tags:
- "**.md" - 'v*'
pull_request: pull_request:
branches: branches:
- master - 'master'
- releases/v* - 'releases/v*'
paths-ignore:
- "**.md"
jobs: jobs:
main: main:

@ -3,28 +3,14 @@ name: test
on: on:
push: push:
branches: branches:
- master - 'master'
- releases/v* - 'releases/v*'
paths-ignore:
- "**.md"
pull_request: pull_request:
paths-ignore: branches:
- "**.md" - 'master'
- 'releases/v*'
jobs: jobs:
test-containerized:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Validate
run: docker buildx bake validate
-
name: Test
run: docker buildx bake test
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -32,15 +18,17 @@ jobs:
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
- -
name: Install name: Validate
run: yarn install uses: docker/bake-action@v1
with:
targets: validate
- -
name: Test name: Test
run: yarn run test uses: docker/bake-action@v1
with:
targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
if: success()
with: with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml file: ./coverage/clover.xml

@ -1,52 +0,0 @@
#syntax=docker/dockerfile:1.2
FROM node:14 AS deps
WORKDIR /src
COPY package.json yarn.lock ./
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \
yarn install
FROM scratch AS update-yarn
COPY --from=deps /src/yarn.lock /
FROM deps AS validate-yarn
COPY .git .git
RUN status=$(git status --porcelain -- yarn.lock); if [ -n "$status" ]; then echo $status; exit 1; fi
FROM deps AS base
COPY . .
FROM base AS build
RUN yarn build
FROM deps AS test
COPY --from=docker /usr/local/bin/docker /usr/bin/
ARG TARGETOS
ARG TARGETARCH
ARG BUILDX_VERSION=v0.4.2
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN mkdir -p /usr/local/lib/docker/cli-plugins && \
curl -fsSL https://github.com/docker/buildx/releases/download/$BUILDX_VERSION/buildx-$BUILDX_VERSION.$TARGETOS-$TARGETARCH > /usr/local/lib/docker/cli-plugins/docker-buildx && \
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx && \
docker buildx version
COPY . .
RUN yarn run test
FROM base AS run-format
RUN yarn run format
FROM scratch AS format
COPY --from=run-format /src/src/*.ts /src/
FROM base AS validate-format
RUN yarn run format-check
FROM scratch AS dist
COPY --from=build /src/dist/ /dist/
FROM build AS validate-build
RUN status=$(git status --porcelain -- dist); if [ -n "$status" ]; then echo $status; exit 1; fi
FROM base AS dev
ENTRYPOINT ["bash"]

18
dist/index.js generated vendored

@ -528,17 +528,17 @@ function run() {
const inputs = yield context.getInputs(); const inputs = yield context.getInputs();
const dockerConfigHome = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker'); const dockerConfigHome = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
if (!(yield buildx.isAvailable()) || inputs.version) { if (!(yield buildx.isAvailable()) || inputs.version) {
core.startGroup(`👉 Installing Buildx`); core.startGroup(`Installing buildx`);
yield buildx.install(inputs.version || 'latest', dockerConfigHome); yield buildx.install(inputs.version || 'latest', dockerConfigHome);
core.endGroup(); core.endGroup();
} }
const buildxVersion = yield buildx.getVersion(); const buildxVersion = yield buildx.getVersion();
core.info(`📣 Buildx version: ${buildxVersion}`); core.info(`Using buildx ${buildxVersion}`);
const builderName = inputs.driver == 'docker' ? 'default' : `builder-${__webpack_require__(840).v4()}`; const builderName = inputs.driver == 'docker' ? 'default' : `builder-${__webpack_require__(840).v4()}`;
core.setOutput('name', builderName); core.setOutput('name', builderName);
stateHelper.setBuilderName(builderName); stateHelper.setBuilderName(builderName);
if (inputs.driver !== 'docker') { if (inputs.driver !== 'docker') {
core.startGroup(`🔨 Creating a new builder instance`); core.startGroup(`Creating a new builder instance`);
let createArgs = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver]; let createArgs = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver];
if (semver.satisfies(buildxVersion, '>=0.3.0')) { if (semver.satisfies(buildxVersion, '>=0.3.0')) {
yield context.asyncForEach(inputs.driverOpts, (driverOpt) => __awaiter(this, void 0, void 0, function* () { yield context.asyncForEach(inputs.driverOpts, (driverOpt) => __awaiter(this, void 0, void 0, function* () {
@ -556,7 +556,7 @@ function run() {
} }
yield exec.exec('docker', createArgs); yield exec.exec('docker', createArgs);
core.endGroup(); core.endGroup();
core.startGroup(`🏃 Booting builder`); core.startGroup(`Booting builder`);
let bootstrapArgs = ['buildx', 'inspect', '--bootstrap']; let bootstrapArgs = ['buildx', 'inspect', '--bootstrap'];
if (semver.satisfies(buildxVersion, '>=0.4.0')) { if (semver.satisfies(buildxVersion, '>=0.4.0')) {
bootstrapArgs.push('--builder', builderName); bootstrapArgs.push('--builder', builderName);
@ -565,11 +565,11 @@ function run() {
core.endGroup(); core.endGroup();
} }
if (inputs.install) { if (inputs.install) {
core.startGroup(`🤝 Setting buildx as default builder`); core.startGroup(`Setting buildx as default builder`);
yield exec.exec('docker', ['buildx', 'install']); yield exec.exec('docker', ['buildx', 'install']);
core.endGroup(); core.endGroup();
} }
core.startGroup(`🛒 Extracting available platforms`); core.startGroup(`Extracting available platforms`);
const platforms = yield buildx.platforms(); const platforms = yield buildx.platforms();
core.info(`${platforms}`); core.info(`${platforms}`);
core.setOutput('platforms', platforms); core.setOutput('platforms', platforms);
@ -2185,7 +2185,7 @@ function install(inputVersion, dockerConfigHome) {
if (!release) { if (!release) {
throw new Error(`Cannot find buildx ${inputVersion} release`); throw new Error(`Cannot find buildx ${inputVersion} release`);
} }
core.debug(`Release found: ${release.tag_name}`); core.debug(`Release ${release.tag_name} found`);
const version = release.tag_name.replace(/^v+|v+$/g, ''); const version = release.tag_name.replace(/^v+|v+$/g, '');
let toolPath; let toolPath;
toolPath = tc.find('buildx', version); toolPath = tc.find('buildx', version);
@ -2205,7 +2205,7 @@ function install(inputVersion, dockerConfigHome) {
const pluginPath = path.join(pluginsDir, filename); const pluginPath = path.join(pluginsDir, filename);
core.debug(`Plugin path is ${pluginPath}`); core.debug(`Plugin path is ${pluginPath}`);
fs.copyFileSync(path.join(toolPath, filename), pluginPath); fs.copyFileSync(path.join(toolPath, filename), pluginPath);
core.info('🔨 Fixing perms...'); core.info('Fixing perms');
fs.chmodSync(pluginPath, '0755'); fs.chmodSync(pluginPath, '0755');
return pluginPath; return pluginPath;
}); });
@ -2217,7 +2217,7 @@ function download(version) {
const downloadUrl = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, yield filename(version)); const downloadUrl = util.format('https://github.com/docker/buildx/releases/download/v%s/%s', version, yield filename(version));
let downloadPath; let downloadPath;
try { try {
core.info(`⬇️ Downloading ${downloadUrl}...`); core.info(`Downloading ${downloadUrl}`);
downloadPath = yield tc.downloadTool(downloadUrl); downloadPath = yield tc.downloadTool(downloadUrl);
core.debug(`Downloaded to ${downloadPath}`); core.debug(`Downloaded to ${downloadPath}`);
} }

@ -1,42 +1,67 @@
variable "NODE_VERSION" {
default = "12"
}
target "node-version" {
args = {
NODE_VERSION = NODE_VERSION
}
}
group "default" { group "default" {
targets = ["build"] targets = ["build"]
} }
group "pre-checkin" { group "pre-checkin" {
targets = ["update-yarn", "format", "build"] targets = ["vendor-update", "format", "build"]
} }
group "validate" { group "validate" {
targets = ["validate-format", "validate-build", "validate-yarn"] targets = ["format-validate", "build-validate", "vendor-validate"]
}
target "update-yarn" {
target = "update-yarn"
output = ["."]
} }
target "build" { target "build" {
target = "dist" inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "build-update"
output = ["."] output = ["."]
} }
target "test" { target "build-validate" {
target = "test" inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "build-validate"
} }
target "format" { target "format" {
target = "format" inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "format-update"
output = ["."] output = ["."]
} }
target "validate-format" { target "format-validate" {
target = "validate-format" inherits = ["node-version"]
dockerfile = "./hack/build.Dockerfile"
target = "format-validate"
} }
target "validate-build" { target "vendor-update" {
target = "validate-build" inherits = ["node-version"]
dockerfile = "./hack/vendor.Dockerfile"
target = "update"
output = ["."]
} }
target "validate-yarn" { target "vendor-validate" {
target = "validate-yarn" inherits = ["node-version"]
dockerfile = "./hack/vendor.Dockerfile"
target = "validate"
}
target "test" {
inherits = ["node-version"]
dockerfile = "./hack/test.Dockerfile"
target = "test-coverage"
output = ["./coverage"]
} }

42
hack/build.Dockerfile Normal file

@ -0,0 +1,42 @@
# syntax=docker/dockerfile:1.2
ARG NODE_VERSION
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git
WORKDIR /src
FROM base AS deps
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn install
FROM deps AS build
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run build && mkdir /out && cp -Rf dist /out/
FROM scratch AS build-update
COPY --from=build /out /
FROM build AS build-validate
RUN --mount=type=bind,target=.,rw \
git add -A && cp -rf /out/* .; \
if [ -n "$(git status --porcelain -- dist)" ]; then \
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'; \
git status --porcelain -- dist; \
exit 1; \
fi
FROM deps AS format
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run format \
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
FROM scratch AS format-update
COPY --from=format /out /
FROM deps AS format-validate
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run format-check \

@ -1,6 +0,0 @@
#!/usr/bin/env bash
iidfile=$(mktemp -t docker-iidfile.XXXXXXXXXX)
DOCKER_BUILDKIT=1 docker build --iidfile $iidfile --progress=plain .
docker run -it --rm $(cat $iidfile)
docker rmi $(cat $iidfile)

23
hack/test.Dockerfile Normal file

@ -0,0 +1,23 @@
# syntax=docker/dockerfile:1.2
ARG NODE_VERSION
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache git
WORKDIR /src
FROM base AS deps
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn install
FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
--mount=type=bind,from=crazymax/docker,source=/usr/libexec/docker/cli-plugins/docker-buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
--mount=type=bind,from=crazymax/docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
yarn run test --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage /

23
hack/vendor.Dockerfile Normal file

@ -0,0 +1,23 @@
# syntax=docker/dockerfile:1.2
ARG NODE_VERSION
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache git
WORKDIR /src
FROM base AS vendored
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn install && mkdir /out && cp yarn.lock /out
FROM scratch AS update
COPY --from=vendored /out /
FROM vendored AS validate
RUN --mount=type=bind,target=.,rw \
git add -A && cp -rf /out/* .; \
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then \
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'; \
git status --porcelain -- yarn.lock; \
exit 1; \
fi

@ -52,7 +52,7 @@ export async function install(inputVersion: string, dockerConfigHome: string): P
if (!release) { if (!release) {
throw new Error(`Cannot find buildx ${inputVersion} release`); throw new Error(`Cannot find buildx ${inputVersion} release`);
} }
core.debug(`Release found: ${release.tag_name}`); core.debug(`Release ${release.tag_name} found`);
const version = release.tag_name.replace(/^v+|v+$/g, ''); const version = release.tag_name.replace(/^v+|v+$/g, '');
let toolPath: string; let toolPath: string;
@ -76,7 +76,7 @@ export async function install(inputVersion: string, dockerConfigHome: string): P
core.debug(`Plugin path is ${pluginPath}`); core.debug(`Plugin path is ${pluginPath}`);
fs.copyFileSync(path.join(toolPath, filename), pluginPath); fs.copyFileSync(path.join(toolPath, filename), pluginPath);
core.info('🔨 Fixing perms...'); core.info('Fixing perms');
fs.chmodSync(pluginPath, '0755'); fs.chmodSync(pluginPath, '0755');
return pluginPath; return pluginPath;
@ -92,7 +92,7 @@ async function download(version: string): Promise<string> {
let downloadPath: string; let downloadPath: string;
try { try {
core.info(`⬇️ Downloading ${downloadUrl}...`); core.info(`Downloading ${downloadUrl}`);
downloadPath = await tc.downloadTool(downloadUrl); downloadPath = await tc.downloadTool(downloadUrl);
core.debug(`Downloaded to ${downloadPath}`); core.debug(`Downloaded to ${downloadPath}`);
} catch (error) { } catch (error) {

@ -19,20 +19,20 @@ async function run(): Promise<void> {
const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker'); const dockerConfigHome: string = process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker');
if (!(await buildx.isAvailable()) || inputs.version) { if (!(await buildx.isAvailable()) || inputs.version) {
core.startGroup(`👉 Installing Buildx`); core.startGroup(`Installing buildx`);
await buildx.install(inputs.version || 'latest', dockerConfigHome); await buildx.install(inputs.version || 'latest', dockerConfigHome);
core.endGroup(); core.endGroup();
} }
const buildxVersion = await buildx.getVersion(); const buildxVersion = await buildx.getVersion();
core.info(`📣 Buildx version: ${buildxVersion}`); core.info(`Using buildx ${buildxVersion}`);
const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${require('uuid').v4()}`; const builderName: string = inputs.driver == 'docker' ? 'default' : `builder-${require('uuid').v4()}`;
core.setOutput('name', builderName); core.setOutput('name', builderName);
stateHelper.setBuilderName(builderName); stateHelper.setBuilderName(builderName);
if (inputs.driver !== 'docker') { if (inputs.driver !== 'docker') {
core.startGroup(`🔨 Creating a new builder instance`); core.startGroup(`Creating a new builder instance`);
let createArgs: Array<string> = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver]; let createArgs: Array<string> = ['buildx', 'create', '--name', builderName, '--driver', inputs.driver];
if (semver.satisfies(buildxVersion, '>=0.3.0')) { if (semver.satisfies(buildxVersion, '>=0.3.0')) {
await context.asyncForEach(inputs.driverOpts, async driverOpt => { await context.asyncForEach(inputs.driverOpts, async driverOpt => {
@ -51,7 +51,7 @@ async function run(): Promise<void> {
await exec.exec('docker', createArgs); await exec.exec('docker', createArgs);
core.endGroup(); core.endGroup();
core.startGroup(`🏃 Booting builder`); core.startGroup(`Booting builder`);
let bootstrapArgs: Array<string> = ['buildx', 'inspect', '--bootstrap']; let bootstrapArgs: Array<string> = ['buildx', 'inspect', '--bootstrap'];
if (semver.satisfies(buildxVersion, '>=0.4.0')) { if (semver.satisfies(buildxVersion, '>=0.4.0')) {
bootstrapArgs.push('--builder', builderName); bootstrapArgs.push('--builder', builderName);
@ -61,12 +61,12 @@ async function run(): Promise<void> {
} }
if (inputs.install) { if (inputs.install) {
core.startGroup(`🤝 Setting buildx as default builder`); core.startGroup(`Setting buildx as default builder`);
await exec.exec('docker', ['buildx', 'install']); await exec.exec('docker', ['buildx', 'install']);
core.endGroup(); core.endGroup();
} }
core.startGroup(`🛒 Extracting available platforms`); core.startGroup(`Extracting available platforms`);
const platforms = await buildx.platforms(); const platforms = await buildx.platforms();
core.info(`${platforms}`); core.info(`${platforms}`);
core.setOutput('platforms', platforms); core.setOutput('platforms', platforms);