Compare commits

..

39 Commits

Author SHA1 Message Date
CrazyMax
846cac2aa2 Merge pull request #396 from crazy-max/github-isghes
Some checks failed
publish / publish (push) Has been cancelled
github: isGHES func
2024-07-02 13:29:06 +02:00
CrazyMax
83d63d1cf1 github: isGHES func
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-07-02 13:21:26 +02:00
CrazyMax
931b62d64f Merge pull request #395 from crazy-max/bake-fix-resolveRefs
buildx: fix resolveRefs for bake
2024-07-02 12:52:09 +02:00
CrazyMax
16ecd76490 buildx: fix resolveRefs for bake
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-07-02 12:07:44 +02:00
CrazyMax
2cb2c5573f Merge pull request #391 from crazy-max/buildkit-git
buildkit: git parseURL and parseRef funcs
2024-07-01 14:20:29 +02:00
CrazyMax
f2de331691 Merge pull request #393 from docker/bot/docker-releases-json
Update `.github/docker-releases.json`
2024-07-01 14:20:08 +02:00
crazy-max
27254cb337 github: update .github/docker-releases.json
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-07-01 12:10:08 +00:00
CrazyMax
c8df3474bd buildkit: git parseURL and parseRef funcs
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-29 13:58:49 +02:00
CrazyMax
fe9937dd36 Merge pull request #390 from crazy-max/build-metadata
bake: align build metadata
2024-06-29 13:15:55 +02:00
CrazyMax
8785275da1 bake: align build metadata
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-29 12:00:21 +02:00
CrazyMax
7bd4fed6bc Merge pull request #388 from docker/bot/docker-releases-json
Some checks failed
publish / publish (push) Has been cancelled
Update `.github/docker-releases.json`
2024-06-27 10:37:34 +02:00
crazy-max
18fbe0cb64 github: update .github/docker-releases.json
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-27 00:23:11 +00:00
CrazyMax
7360d08bf9 Merge pull request #365 from crazy-max/build-checks-annotations
github: annotate build warnings
2024-06-26 21:58:50 +02:00
CrazyMax
644587f0d1 ci(test): use buildx master for build warnings
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-26 12:32:15 +02:00
CrazyMax
3a7b0a6080 github: annotate build warnings
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-26 12:32:15 +02:00
CrazyMax
2e70a0cac6 Merge pull request #384 from crazy-max/summary-learn-more-blogpost
Some checks failed
publish / publish (push) Has been cancelled
github(summary): update learn more link
2024-06-26 11:17:33 +02:00
CrazyMax
e600fe266c Merge pull request #383 from crazy-max/summary-rm-preview-title
github(summary): remove preview title and tidy download link
2024-06-26 11:17:14 +02:00
CrazyMax
52d663521a Merge pull request #386 from crazy-max/ci-bk-image
ci(test): set buildkit image for container builder
2024-06-26 09:51:41 +02:00
CrazyMax
dceb603792 ci(test): set buildkit image for container builder
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-26 09:45:33 +02:00
CrazyMax
77b8d647eb Merge pull request #362 from crazy-max/buildx-build-resolvestatus
buildx(build): resolveWarnings from metadata
2024-06-26 09:14:35 +02:00
CrazyMax
630b180101 buildx(build): resolveWarnings from metadata
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-26 09:06:42 +02:00
CrazyMax
2e536e4a37 Merge pull request #385 from docker/bot/docker-releases-json
Update `.github/docker-releases.json`
2024-06-25 14:09:47 +02:00
crazy-max
40f2a14d95 github: update .github/docker-releases.json
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-25 12:09:09 +00:00
CrazyMax
9853314413 github(summary): tidy download link
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-25 13:26:29 +02:00
CrazyMax
f2e65ab473 github(summary): update learn more link
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-25 12:04:09 +02:00
CrazyMax
e130c40c84 github(summary): remove preview title
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-25 12:01:54 +02:00
CrazyMax
bbf0a8d268 Merge pull request #382 from crazy-max/github-upload-artifact-ghes
Some checks failed
publish / publish (push) Has been cancelled
github(artifact): check upload artifact support for GHES
2024-06-25 09:39:16 +02:00
CrazyMax
4ce8a708c9 github(artifact): check upload artifact support for GHES
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-24 14:15:22 +02:00
CrazyMax
6f66565779 Merge pull request #381 from docker/bot/docker-releases-json
Update `.github/docker-releases.json`
2024-06-21 12:43:34 +02:00
crazy-max
504af69bd9 github: update .github/docker-releases.json
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-21 10:43:22 +00:00
CrazyMax
f3734ee134 Merge pull request #380 from docker/bot/buildx-lab-releases-json
Update `.github/buildx-lab-releases.json`
2024-06-21 12:42:56 +02:00
crazy-max
4183444df2 github: update .github/buildx-lab-releases.json
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-21 00:14:48 +00:00
CrazyMax
a5466523c1 Merge pull request #378 from crazy-max/summary-escape-html
Some checks failed
publish / publish (push) Has been cancelled
github(summary): escape HTML when printing build error
2024-06-20 18:56:27 +02:00
CrazyMax
e0007fb5cd github(summary): escape HTML when printing build error
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-20 18:44:25 +02:00
CrazyMax
c330895cef Merge pull request #377 from crazy-max/summary-collapsible
github(summary): add collapsible section for build inputs and bake def
2024-06-20 18:42:47 +02:00
CrazyMax
e7017a21b8 github(summary): add details to summary sections
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-20 16:21:16 +02:00
CrazyMax
b56d9771d7 util: countLines func
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-20 16:21:15 +02:00
CrazyMax
680ab5bdf1 Merge pull request #379 from crazy-max/ci-releases-json-pr-trigger
ci: only trigger releases json workflow on pr when changed
2024-06-20 16:21:03 +02:00
CrazyMax
5ea53e0090 ci: only trigger releases json workflow on pr when changed
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-06-20 16:17:35 +02:00
24 changed files with 1135 additions and 59 deletions

View File

@@ -40,6 +40,47 @@
"https://github.com/docker/buildx-desktop/releases/download/v0.14.1-desktop.1/checksums.txt"
]
},
"v0.15.1-desktop.1": {
"id": 161492089,
"tag_name": "v0.15.1-desktop.1",
"html_url": "https://github.com/docker/buildx-desktop/releases/tag/v0.15.1-desktop.1",
"assets": [
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-amd64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.darwin-arm64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-amd64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v6.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm-v7.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-arm64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-ppc64le.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-riscv64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.linux-s390x.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.exe",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-amd64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.exe",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.provenance.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/buildx-v0.15.1-desktop.1.windows-arm64.sbom.json",
"https://github.com/docker/buildx-desktop/releases/download/v0.15.1-desktop.1/checksums.txt"
]
},
"v0.15.0-desktop.1": {
"id": 160473592,
"tag_name": "v0.15.0-desktop.1",

View File

@@ -1,8 +1,38 @@
{
"latest": {
"id": 159031384,
"tag_name": "v26.1.4",
"html_url": "https://github.com/moby/moby/releases/tag/v26.1.4",
"id": 163311279,
"tag_name": "v27.0.3",
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.3",
"assets": []
},
"v27.0.3": {
"id": 163311279,
"tag_name": "v27.0.3",
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.3",
"assets": []
},
"v27.0.2": {
"id": 162600493,
"tag_name": "v27.0.2",
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.2",
"assets": []
},
"v27.0.1": {
"id": 162009909,
"tag_name": "v27.0.1",
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.1",
"assets": []
},
"v27.0.1-rc.1": {
"id": 161457618,
"tag_name": "v27.0.1-rc.1",
"html_url": "https://github.com/moby/moby/releases/tag/v27.0.1-rc.1",
"assets": []
},
"v23.0.13": {
"id": 161533551,
"tag_name": "v23.0.13",
"html_url": "https://github.com/moby/moby/releases/tag/v23.0.13",
"assets": []
},
"v27.0.0-rc.2": {

View File

@@ -12,8 +12,8 @@ on:
branches:
- 'main'
pull_request:
paths-ignore:
- '.github/*-releases.json'
paths:
- '.github/workflows/buildx-lab-releases-json.yml'
jobs:
generate:

View File

@@ -12,8 +12,8 @@ on:
branches:
- 'main'
pull_request:
paths-ignore:
- '.github/*-releases.json'
paths:
- '.github/workflows/buildx-releases-json.yml'
jobs:
generate:

View File

@@ -12,8 +12,8 @@ on:
branches:
- 'main'
pull_request:
paths-ignore:
- '.github/*-releases.json'
paths:
- '.github/workflows/docker-releases-json.yml'
jobs:
generate:

View File

@@ -15,7 +15,8 @@ on:
env:
NODE_VERSION: "20"
BUILDX_VERSION: "v0.15.1"
BUILDX_VERSION: "https://github.com/docker/buildx.git#d8c9ebde1fdcf659f1fa3efa6ccc27a28b0f1564" # https://github.com/docker/buildx/pull/2551
BUILDKIT_IMAGE: "moby/buildkit:v0.14.1"
jobs:
test:
@@ -138,6 +139,7 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
version: ${{ env.BUILDX_VERSION }}
driver-opts: image=${{ env.BUILDKIT_IMAGE }}
use: false
-
name: Install

View File

@@ -0,0 +1,344 @@
/**
* Copyright 2024 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, jest, test} from '@jest/globals';
import {Git} from '../../src/buildkit/git';
import {GitRef, GitURL} from '../../src/types/buildkit/git';
beforeEach(() => {
jest.restoreAllMocks();
});
describe('parseURL', () => {
// prettier-ignore
test.each([
[
'http://github.com/moby/buildkit',
{
scheme: 'http',
host: 'github.com',
path: '/moby/buildkit'
} as GitURL,
false
],
[
'https://github.com/moby/buildkit',
{
scheme: 'https',
host: 'github.com',
path: '/moby/buildkit'
} as GitURL,
false
],
[
'http://github.com/moby/buildkit#v1.0.0',
{
scheme: 'http',
host: 'github.com',
path: '/moby/buildkit',
fragment: {
ref: 'v1.0.0',
}
} as GitURL,
false
],
[
'http://github.com/moby/buildkit#v1.0.0:subdir',
{
scheme: 'http',
host: 'github.com',
path: '/moby/buildkit',
fragment: {
ref: 'v1.0.0',
subdir: 'subdir'
}
} as GitURL,
false
],
[
'http://foo:bar@github.com/moby/buildkit#v1.0.0',
{
scheme: 'http',
host: 'github.com',
path: '/moby/buildkit',
fragment: {
ref: 'v1.0.0',
},
user: {
username: 'foo',
password: 'bar',
passwordSet: true
}
} as GitURL,
false
],
[
'ssh://git@github.com/moby/buildkit.git',
{
scheme: 'ssh',
host: 'github.com',
path: '/moby/buildkit.git',
user: {
username: 'git',
password: '',
passwordSet: false
}
} as GitURL,
false
],
[
'ssh://git@github.com:22/moby/buildkit.git',
{
scheme: 'ssh',
host: 'github.com:22',
path: '/moby/buildkit.git',
user: {
username: 'git',
password: '',
passwordSet: false
}
} as GitURL,
false
],
// TODO: handle SCP-style URLs
// [
// 'git@github.com:moby/buildkit.git',
// {
// scheme: 'ssh',
// host: 'github.com:22',
// path: 'moby/buildkit.git',
// user: {
// username: 'git',
// password: '',
// passwordSet: false
// }
// } as GitURL,
// false
// ],
[
'ssh://root@subdomain.example.hostname:2222/root/my/really/weird/path/foo.git',
{
scheme: 'ssh',
host: 'subdomain.example.hostname:2222',
path: '/root/my/really/weird/path/foo.git',
user: {
username: 'root',
password: '',
passwordSet: false
}
} as GitURL,
false
],
[
'git://host.xz:1234/path/to/repo.git',
{
scheme: 'git',
host: 'host.xz:1234',
path: '/path/to/repo.git',
} as GitURL,
false
],
[
'ssh://someuser@192.168.0.123:456/~/repo-in-my-home-dir.git',
{
scheme: 'ssh',
host: '192.168.0.123:456',
path: '/~/repo-in-my-home-dir.git',
user: {
username: 'someuser',
password: '',
passwordSet: false
}
} as GitURL,
false
],
[
'httpx://github.com/moby/buildkit',
{} as GitURL,
true
],
[
'HTTP://github.com/moby/buildkit',
{
scheme: 'http',
host: 'github.com',
path: '/moby/buildkit'
} as GitURL,
false
],
])('given %p', async (ref: string, expected: GitURL, expectedErr: boolean) => {
try {
const got = Git.parseURL(ref);
expect(got.scheme).toEqual(expected.scheme);
expect(got.host).toEqual(expected.host);
expect(got.path).toEqual(expected.path);
expect(got.fragment).toEqual(expected.fragment);
expect(got.user?.username).toEqual(expected.user?.username);
expect(got.user?.password).toEqual(expected.user?.password);
expect(got.user?.passwordSet).toEqual(expected.user?.passwordSet);
} catch (err) {
if (!expectedErr) {
console.log(err);
}
// eslint-disable-next-line jest/no-conditional-expect
expect(expectedErr).toBeTruthy();
}
});
});
describe('parseRef', () => {
// prettier-ignore
test.each([
[
'https://example.com/',
undefined
],
[
'https://example.com/foo',
undefined
],
[
'https://example.com/foo.git',
{
remote: 'https://example.com/foo.git',
shortName: 'foo'
} as GitRef
],
[
'https://example.com/foo.git#deadbeef',
{
remote: 'https://example.com/foo.git',
shortName: 'foo',
commit: 'deadbeef'
} as GitRef
],
[
'https://example.com/foo.git#release/1.2',
{
remote: 'https://example.com/foo.git',
shortName: 'foo',
commit: 'release/1.2'
} as GitRef
],
[
'https://example.com/foo.git/',
undefined
],
[
'https://example.com/foo.git.bar',
undefined
],
[
'git://example.com/foo',
{
remote: 'git://example.com/foo',
shortName: 'foo',
unencryptedTCP: true
} as GitRef
],
[
'github.com/moby/buildkit',
{
remote: 'github.com/moby/buildkit',
shortName: 'buildkit',
indistinguishableFromLocal: true
} as GitRef
],
[
'custom.xyz/moby/buildkit.git',
undefined
],
[
'https://github.com/moby/buildkit',
undefined
],
[
'https://github.com/moby/buildkit.git',
{
remote: 'https://github.com/moby/buildkit.git',
shortName: 'buildkit',
} as GitRef
],
[
'https://foo:bar@github.com/moby/buildkit.git',
{
remote: 'https://foo:bar@github.com/moby/buildkit.git',
shortName: 'buildkit',
} as GitRef
],
// TODO handle SCP-style URLs
// [
// 'git@github.com:moby/buildkit',
// {
// remote: 'git@github.com:moby/buildkit',
// shortName: 'buildkit',
// } as GitRef
// ],
// [
// 'git@github.com:moby/buildkit.git',
// {
// remote: 'git@github.com:moby/buildkit',
// shortName: 'buildkit',
// } as GitRef
// ],
// [
// 'git@bitbucket.org:atlassianlabs/atlassian-docker.git',
// {
// remote: 'git@bitbucket.org:atlassianlabs/atlassian-docker.git',
// shortName: 'atlassian-docker',
// } as GitRef
// ],
[
'https://github.com/foo/bar.git#baz/qux:quux/quuz',
{
remote: 'https://github.com/foo/bar.git',
shortName: 'bar',
commit: 'baz/qux',
subDir: 'quux/quuz',
} as GitRef
],
[
'https://github.com/docker/docker.git#:myfolder',
{
remote: 'https://github.com/docker/docker.git',
shortName: 'docker',
subDir: 'myfolder',
commit: ''
} as GitRef
],
[
'./.git',
undefined
],
[
'.git',
undefined
],
])('given %p', async (ref: string, expected: GitRef | undefined) => {
try {
const got = Git.parseRef(ref);
expect(got).toEqual(expected);
} catch (err) {
if (expected) {
console.log(err);
}
// eslint-disable-next-line jest/no-conditional-expect
expect(expected).toBeUndefined();
}
});
});

View File

@@ -23,13 +23,14 @@ import {Bake} from '../../src/buildx/bake';
import {Context} from '../../src/context';
import {ExecOptions} from '@actions/exec';
import {BakeDefinition, BakeMetadata} from '../../src/types/buildx/bake';
import {BakeDefinition} from '../../src/types/buildx/bake';
import {BuildMetadata} from '../../src/types/buildx/build';
const fixturesDir = path.join(__dirname, '..', 'fixtures');
// prettier-ignore
const tmpDir = path.join(process.env.TEMP || '/tmp', 'buildx-inputs-jest');
const tmpName = path.join(tmpDir, '.tmpname-jest');
const metadata: BakeMetadata = {
const metadata: BuildMetadata = {
app: {
'buildx.build.ref': 'default/default/7frbdw1fmfozgtqavghowsepk'
},
@@ -57,7 +58,7 @@ describe('resolveMetadata', () => {
it('matches', async () => {
const bake = new Bake();
fs.writeFileSync(bake.getMetadataFilePath(), JSON.stringify(metadata));
expect(bake.resolveMetadata()).toEqual(metadata as BakeMetadata);
expect(bake.resolveMetadata()).toEqual(metadata as BuildMetadata);
});
});

View File

@@ -80,6 +80,16 @@ describe('resolveProvenance', () => {
});
});
describe('resolveWarnings', () => {
it('matches', async () => {
const build = new Build();
fs.writeFileSync(build.getMetadataFilePath(), JSON.stringify(metadata));
const warnings = build.resolveWarnings();
expect(warnings).toBeDefined();
expect(warnings?.length).toEqual(3);
});
});
describe('resolveDigest', () => {
it('matches', async () => {
const build = new Build();

View File

@@ -0,0 +1,19 @@
# syntax=docker/dockerfile:1
# Copyright 2024 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.
FROM busybox:latest
ARGGG NAME=foo
RUN echo "hello $NAME"

View File

@@ -0,0 +1,28 @@
# syntax=docker/dockerfile-upstream:master
# Copyright 2024 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.
frOM busybox as base
cOpy lint.Dockerfile .
from scratch
MAINTAINER moby@example.com
COPy --from=base \
/lint.Dockerfile \
/
CMD [ "echo", "Hello, Norway!" ]
CMD [ "echo", "Hello, Sweden!" ]
ENTRYPOINT my-program start

View File

@@ -40,6 +40,189 @@
}
},
"buildx.build.ref": "default/default/n6ibcp9b2pw108rrz7ywdznvo",
"buildx.build.warnings": [
{
"vertex": "sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0",
"level": 1,
"short": "Q29uc2lzdGVudEluc3RydWN0aW9uQ2FzaW5nOiBDb21tYW5kICdmck9NJyBzaG91bGQgYmUgY29uc2lzdGVudGx5IGNhc2VkIChsaW5lIDIp",
"detail": [
"SW5zdHJ1Y3Rpb25zIHNob3VsZCBiZSBpbiBjb25zaXN0ZW50IGNhc2luZyAoYWxsIGxvd2VyIG9yIGFsbCB1cHBlcik="
],
"url": "https://docs.docker.com/go/dockerfile/rule/consistent-instruction-casing/",
"sourceInfo": {
"filename": "Dockerfile",
"data": "IyBzeW50YXg9ZG9ja2VyL2RvY2tlcmZpbGUtdXBzdHJlYW06bWFzdGVyCmZyT00gYnVzeWJveCBhcyBiYXNlCmNPcHkgRG9ja2VyZmlsZSAuCgpmcm9tIHNjcmF0Y2gKQ09QeSAtLWZyb209YmFzZSBcCiAgL0RvY2tlcmZpbGUgXAogIC8K",
"definition": {
"def": [
"GsUBChJsb2NhbDovL2RvY2tlcmZpbGUSFAoMbG9jYWwuZGlmZmVyEgRub25lEkoKEWxvY2FsLmZvbGxvd3BhdGhzEjVbIkRvY2tlcmZpbGUiLCJEb2NrZXJmaWxlLmRvY2tlcmlnbm9yZSIsImRvY2tlcmZpbGUiXRIqCg1sb2NhbC5zZXNzaW9uEhkwN3A3MzJ6aGR4NXV1NnVsZDNzOGpteWo2EiEKE2xvY2FsLnNoYXJlZGtleWhpbnQSCmRvY2tlcmZpbGVaAA==",
"CkkKR3NoYTI1Njo3YjQ3N2FjNWRkM2E0YzRkMjUyM2Y3ZjdmMjA0MDZiNjI2Mzk1ZGUwODJmNDRmZDVmZjk5NjMyM2VjODI1N2Qw"
],
"metadata": {
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {
"description": {
"llb.customname": "[internal] load build definition from Dockerfile"
},
"caps": {
"source.local": true,
"source.local.followpaths": true,
"source.local.sessionid": true,
"source.local.sharedkeyhint": true
}
},
"sha256:a06279dbe062a3b181c9b918abfaf37ca8106f1f9745b9d42356b3195b205cd1": {
"caps": {
"constraints": true,
"meta.description": true,
"platform": true
}
}
},
"Source": {
"locations": {
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {}
}
}
},
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 2
},
"end": {
"line": 2
}
}
]
},
{
"vertex": "sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0",
"level": 1,
"short": "Q29uc2lzdGVudEluc3RydWN0aW9uQ2FzaW5nOiBDb21tYW5kICdjT3B5JyBzaG91bGQgYmUgY29uc2lzdGVudGx5IGNhc2VkIChsaW5lIDMp",
"detail": [
"SW5zdHJ1Y3Rpb25zIHNob3VsZCBiZSBpbiBjb25zaXN0ZW50IGNhc2luZyAoYWxsIGxvd2VyIG9yIGFsbCB1cHBlcik="
],
"url": "https://docs.docker.com/go/dockerfile/rule/consistent-instruction-casing/",
"sourceInfo": {
"filename": "Dockerfile",
"data": "IyBzeW50YXg9ZG9ja2VyL2RvY2tlcmZpbGUtdXBzdHJlYW06bWFzdGVyCmZyT00gYnVzeWJveCBhcyBiYXNlCmNPcHkgRG9ja2VyZmlsZSAuCgpmcm9tIHNjcmF0Y2gKQ09QeSAtLWZyb209YmFzZSBcCiAgL0RvY2tlcmZpbGUgXAogIC8K",
"definition": {
"def": [
"GsUBChJsb2NhbDovL2RvY2tlcmZpbGUSFAoMbG9jYWwuZGlmZmVyEgRub25lEkoKEWxvY2FsLmZvbGxvd3BhdGhzEjVbIkRvY2tlcmZpbGUiLCJEb2NrZXJmaWxlLmRvY2tlcmlnbm9yZSIsImRvY2tlcmZpbGUiXRIqCg1sb2NhbC5zZXNzaW9uEhkwN3A3MzJ6aGR4NXV1NnVsZDNzOGpteWo2EiEKE2xvY2FsLnNoYXJlZGtleWhpbnQSCmRvY2tlcmZpbGVaAA==",
"CkkKR3NoYTI1Njo3YjQ3N2FjNWRkM2E0YzRkMjUyM2Y3ZjdmMjA0MDZiNjI2Mzk1ZGUwODJmNDRmZDVmZjk5NjMyM2VjODI1N2Qw"
],
"metadata": {
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {
"description": {
"llb.customname": "[internal] load build definition from Dockerfile"
},
"caps": {
"source.local": true,
"source.local.followpaths": true,
"source.local.sessionid": true,
"source.local.sharedkeyhint": true
}
},
"sha256:a06279dbe062a3b181c9b918abfaf37ca8106f1f9745b9d42356b3195b205cd1": {
"caps": {
"constraints": true,
"meta.description": true,
"platform": true
}
}
},
"Source": {
"locations": {
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {}
}
}
},
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 3
},
"end": {
"line": 3
}
}
]
},
{
"vertex": "sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0",
"level": 1,
"short": "Q29uc2lzdGVudEluc3RydWN0aW9uQ2FzaW5nOiBDb21tYW5kICdDT1B5JyBzaG91bGQgYmUgY29uc2lzdGVudGx5IGNhc2VkIChsaW5lIDYp",
"detail": [
"SW5zdHJ1Y3Rpb25zIHNob3VsZCBiZSBpbiBjb25zaXN0ZW50IGNhc2luZyAoYWxsIGxvd2VyIG9yIGFsbCB1cHBlcik="
],
"url": "https://docs.docker.com/go/dockerfile/rule/consistent-instruction-casing/",
"sourceInfo": {
"filename": "Dockerfile",
"data": "IyBzeW50YXg9ZG9ja2VyL2RvY2tlcmZpbGUtdXBzdHJlYW06bWFzdGVyCmZyT00gYnVzeWJveCBhcyBiYXNlCmNPcHkgRG9ja2VyZmlsZSAuCgpmcm9tIHNjcmF0Y2gKQ09QeSAtLWZyb209YmFzZSBcCiAgL0RvY2tlcmZpbGUgXAogIC8K",
"definition": {
"def": [
"GsUBChJsb2NhbDovL2RvY2tlcmZpbGUSFAoMbG9jYWwuZGlmZmVyEgRub25lEkoKEWxvY2FsLmZvbGxvd3BhdGhzEjVbIkRvY2tlcmZpbGUiLCJEb2NrZXJmaWxlLmRvY2tlcmlnbm9yZSIsImRvY2tlcmZpbGUiXRIqCg1sb2NhbC5zZXNzaW9uEhkwN3A3MzJ6aGR4NXV1NnVsZDNzOGpteWo2EiEKE2xvY2FsLnNoYXJlZGtleWhpbnQSCmRvY2tlcmZpbGVaAA==",
"CkkKR3NoYTI1Njo3YjQ3N2FjNWRkM2E0YzRkMjUyM2Y3ZjdmMjA0MDZiNjI2Mzk1ZGUwODJmNDRmZDVmZjk5NjMyM2VjODI1N2Qw"
],
"metadata": {
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {
"description": {
"llb.customname": "[internal] load build definition from Dockerfile"
},
"caps": {
"source.local": true,
"source.local.followpaths": true,
"source.local.sessionid": true,
"source.local.sharedkeyhint": true
}
},
"sha256:a06279dbe062a3b181c9b918abfaf37ca8106f1f9745b9d42356b3195b205cd1": {
"caps": {
"constraints": true,
"meta.description": true,
"platform": true
}
}
},
"Source": {
"locations": {
"sha256:7b477ac5dd3a4c4d2523f7f7f20406b626395de082f44fd5ff996323ec8257d0": {}
}
}
},
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 6
},
"end": {
"line": 6
}
},
{
"start": {
"line": 7
},
"end": {
"line": 7
}
},
{
"start": {
"line": 8
},
"end": {
"line": 8
}
}
]
}
],
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167f369349fdc2ecc1f7bc092c2235cbf601a795fd",
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
}

View File

@@ -118,29 +118,20 @@ maybe('writeBuildSummary', () => {
test.each([
[
'single',
[
'bake',
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
'hello'
],
path.join(fixturesDir, 'hello-bake.hcl'),
'hello'
],
[
'group',
[
'bake',
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
'hello-all'
],
path.join(fixturesDir, 'hello-bake.hcl'),
'hello-all'
],
[
'matrix',
[
'bake',
'-f', path.join(fixturesDir, 'hello-bake.hcl'),
'hello-matrix'
],
path.join(fixturesDir, 'hello-bake.hcl'),
'hello-matrix'
]
])('write bake summary %p', async (_, bargs) => {
])('write bake summary %p', async (_, file, target) => {
const buildx = new Buildx();
const bake = new Bake({buildx: buildx});
@@ -150,7 +141,9 @@ maybe('writeBuildSummary', () => {
// prettier-ignore
const buildCmd = await buildx.getCommand([
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
...bargs,
'bake',
'-f', file,
target,
'--metadata-file', bake.getMetadataFilePath()
]);
await Exec.exec(buildCmd.command, buildCmd.args, {
@@ -159,6 +152,16 @@ maybe('writeBuildSummary', () => {
})()
).resolves.not.toThrow();
const definition = await bake.getDefinition(
{
files: [file],
targets: [target],
},
{
cwd: fixturesDir
}
);
const metadata = bake.resolveMetadata();
expect(metadata).toBeDefined();
const buildRefs = bake.resolveRefs(metadata);
@@ -186,7 +189,100 @@ maybe('writeBuildSummary', () => {
uploadRes: uploadRes,
inputs: {
files: path.join(fixturesDir, 'hello-bake.hcl')
},
bakeDefinition: definition
});
});
it('fails with dockerfile syntax issue', async () => {
const startedTime = new Date();
const buildx = new Buildx();
const build = new Build({buildx: buildx});
fs.mkdirSync(tmpDir, {recursive: true});
await expect(
(async () => {
// prettier-ignore
const buildCmd = await buildx.getCommand([
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
'build',
'-f', path.join(fixturesDir, 'hello-err.Dockerfile'),
fixturesDir,
'--metadata-file', build.getMetadataFilePath()
]);
await Exec.exec(buildCmd.command, buildCmd.args);
})()
).rejects.toThrow();
const refs = Buildx.refs({
dir: Buildx.refsDir,
builderName: process.env.CTN_BUILDER_NAME ?? 'default',
since: startedTime
});
expect(refs).toBeDefined();
expect(Object.keys(refs).length).toBeGreaterThan(0);
const history = new History({buildx: buildx});
const exportRes = await history.export({
refs: [Object.keys(refs)[0] ?? '']
});
expect(exportRes).toBeDefined();
expect(exportRes?.dockerbuildFilename).toBeDefined();
expect(exportRes?.dockerbuildSize).toBeDefined();
expect(exportRes?.summaries).toBeDefined();
const uploadRes = await GitHub.uploadArtifact({
filename: exportRes?.dockerbuildFilename,
mimeType: 'application/gzip',
retentionDays: 1
});
expect(uploadRes).toBeDefined();
expect(uploadRes?.url).toBeDefined();
await GitHub.writeBuildSummary({
exportRes: exportRes,
uploadRes: uploadRes,
inputs: {
context: fixturesDir,
file: path.join(fixturesDir, 'hello-err.Dockerfile')
}
});
});
});
maybe('annotateBuildWarnings', () => {
it('annoate lint issues', async () => {
const buildx = new Buildx();
const build = new Build({buildx: buildx});
fs.mkdirSync(tmpDir, {recursive: true});
await expect(
(async () => {
// prettier-ignore
const buildCmd = await buildx.getCommand([
'--builder', process.env.CTN_BUILDER_NAME ?? 'default',
'build',
'-f', path.join(fixturesDir, 'lint.Dockerfile'),
fixturesDir,
'--metadata-file', build.getMetadataFilePath()
]);
await Exec.exec(buildCmd.command, buildCmd.args, {
env: Object.assign({}, process.env, {
BUILDX_METADATA_WARNINGS: 'true'
}) as {
[key: string]: string;
}
});
})()
).resolves.not.toThrow();
const metadata = build.resolveMetadata();
expect(metadata).toBeDefined();
const buildRef = build.resolveRef(metadata);
expect(buildRef).toBeDefined();
const buildWarnings = build.resolveWarnings(metadata);
expect(buildWarnings).toBeDefined();
await GitHub.annotateBuildWarnings(path.join(fixturesDir, 'lint.Dockerfile'), buildWarnings);
});
});

View File

@@ -85,6 +85,28 @@ describe('apiURL', () => {
});
});
describe('isGHES', () => {
afterEach(() => {
process.env.GITHUB_SERVER_URL = '';
});
it('should return false when the request domain is github.com', () => {
process.env.GITHUB_SERVER_URL = 'https://github.com';
expect(GitHub.isGHES).toBe(false);
});
it('should return false when the request domain ends with ghe.com', () => {
process.env.GITHUB_SERVER_URL = 'https://my.domain.ghe.com';
expect(GitHub.isGHES).toBe(false);
});
it('should return false when the request domain ends with ghe.localhost', () => {
process.env.GITHUB_SERVER_URL = 'https://my.domain.ghe.localhost';
expect(GitHub.isGHES).toBe(false);
});
it('should return true when the request domain is specific to an enterprise', () => {
process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com';
expect(GitHub.isGHES).toBe(true);
});
});
describe('repository', () => {
it('returns GitHub repository', async () => {
expect(GitHub.repository).toEqual('docker/actions-toolkit');

View File

@@ -380,6 +380,42 @@ describe('stringToUnicodeEntities', () => {
});
});
describe('countLines', () => {
it('counts total number of lines correctly', () => {
const text = `This
is
a
sample
text
with
multiple
lines`;
const result = Util.countLines(text);
expect(result).toEqual(10); // Including empty lines
});
it('handles edge case with empty string', () => {
const text = '';
const result = Util.countLines(text);
expect(result).toEqual(1); // Empty string should have 1 line
});
it('handles edge case with single line', () => {
const text = 'Single line text';
const result = Util.countLines(text);
expect(result).toEqual(1); // Single line should have 1 line
});
it('handles multiple types of line breaks', () => {
const text = `Line 1\r\nLine 2\rLine 3\nLine 4`;
const result = Util.countLines(text);
expect(result).toEqual(4); // Different line break types should be counted correctly
});
});
// See: https://github.com/actions/toolkit/blob/a1b068ec31a042ff1e10a522d8fdf0b8869d53ca/packages/core/src/core.ts#L89
function getInputName(name: string): string {
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;

View File

@@ -60,6 +60,7 @@
"csv-parse": "^5.5.6",
"gunzip-maybe": "^1.4.2",
"handlebars": "^4.7.8",
"he": "^1.2.0",
"js-yaml": "^4.1.0",
"jwt-decode": "^4.0.0",
"semver": "^7.6.2",
@@ -69,6 +70,7 @@
"devDependencies": {
"@types/csv-parse": "^1.2.2",
"@types/gunzip-maybe": "^1.4.2",
"@types/he": "^1.2.3",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.12.10",
"@types/semver": "^7.5.8",

113
src/buildkit/git.ts Normal file
View File

@@ -0,0 +1,113 @@
/**
* Copyright 2024 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 {GitRef, GitURL, GitURLFragment, URLUserInfo} from '../types/buildkit/git';
export class Git {
private static protoRegexp = new RegExp('^[a-zA-Z0-9]+://');
private static supportedProtos = {
http: {},
https: {},
ssh: {},
git: {}
};
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_url.go#L79
public static parseURL(remote: string): GitURL {
const match = remote.match(Git.protoRegexp);
if (match && match.length > 0) {
let proto = match[0].toLowerCase();
proto = proto.slice(0, proto.lastIndexOf('://'));
if (!(proto in Git.supportedProtos)) {
throw new Error(`Invalid protocol: ${proto}`);
}
return Git.fromURL(new URL(remote));
}
throw new Error('Unknown protocol');
}
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_url.go#L108
private static fromURL(url: URL): GitURL {
const withoutFragment = new URL(url.toString());
withoutFragment.hash = '';
let user: URLUserInfo | undefined;
if (url.username || url.password) {
user = {
username: url.username,
password: url.password,
passwordSet: url.password !== ''
};
}
// TODO: handle SCP-style URLs
return {
scheme: url.protocol.slice(0, -1),
user: user,
host: `${url.hostname}${url.port ? ':' + url.port : ''}`,
path: url.pathname,
fragment: Git.splitGitFragment(url.hash),
remote: withoutFragment.toString()
};
}
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_url.go#L69
private static splitGitFragment(fragment: string): GitURLFragment | undefined {
if (fragment === '') {
return undefined;
}
const [ref, subdir] = fragment.slice(1).split(':');
return {
ref: ref,
subdir: subdir
};
}
// https://github.com/moby/buildkit/blob/2ec1338fc13f73b43f0b1b4f4678d7cd654bc86c/util/gitutil/git_ref.go#L52
public static parseRef(ref: string): GitRef | undefined {
const res: GitRef = {};
let remote: GitURL;
if (ref.startsWith('./') || ref.startsWith('../')) {
throw new Error('Invalid argument');
} else if (ref.startsWith('github.com/')) {
res.indistinguishableFromLocal = true; // Deprecated
remote = Git.fromURL(new URL('https://' + ref));
} else {
remote = Git.parseURL(ref);
if (['http', 'git'].includes(remote.scheme)) {
res.unencryptedTCP = true; // Discouraged, but not deprecated
}
if (['http', 'https'].includes(remote.scheme) && !remote.path.endsWith('.git')) {
throw new Error('Invalid argument');
}
}
res.remote = remote.remote;
if (res.indistinguishableFromLocal) {
res.remote = res.remote.split('://')[1];
}
if (remote.fragment) {
res.commit = remote.fragment.ref;
res.subDir = remote.fragment.subdir;
}
const repoSplitBySlash = res.remote.split('/');
res.shortName = repoSplitBySlash[repoSplitBySlash.length - 1].replace('.git', '');
return res;
}
}

View File

@@ -24,7 +24,8 @@ import {Exec} from '../exec';
import {Util} from '../util';
import {ExecOptions} from '@actions/exec';
import {BakeDefinition, BakeMetadata} from '../types/buildx/bake';
import {BakeDefinition} from '../types/buildx/bake';
import {BuildMetadata} from '../types/buildx/build';
export interface BakeOpts {
buildx?: Buildx;
@@ -57,7 +58,7 @@ export class Bake {
return path.join(Context.tmpDir(), this.metadataFilename);
}
public resolveMetadata(): BakeMetadata | undefined {
public resolveMetadata(): BuildMetadata | undefined {
const metadataFile = this.getMetadataFilePath();
if (!fs.existsSync(metadataFile)) {
return undefined;
@@ -66,10 +67,10 @@ export class Bake {
if (content === 'null') {
return undefined;
}
return <BakeMetadata>JSON.parse(content);
return <BuildMetadata>JSON.parse(content);
}
public resolveRefs(metadata?: BakeMetadata): Array<string> | undefined {
public resolveRefs(metadata?: BuildMetadata): Array<string> | undefined {
if (!metadata) {
metadata = this.resolveMetadata();
if (!metadata) {
@@ -82,7 +83,7 @@ export class Bake {
refs.push(metadata[key]['buildx.build.ref']);
}
}
return refs;
return refs.length > 0 ? refs : undefined;
}
public async getDefinition(cmdOpts: BakeCmdOpts, execOptions?: ExecOptions): Promise<BakeDefinition> {

View File

@@ -25,6 +25,7 @@ import {GitHub} from '../github';
import {Util} from '../util';
import {BuildMetadata} from '../types/buildx/build';
import {VertexWarning} from '../types/buildkit/client';
import {ProvenancePredicate} from '../types/intoto/slsa_provenance/v0.2/provenance';
export interface BuildOpts {
@@ -96,6 +97,19 @@ export class Build {
return undefined;
}
public resolveWarnings(metadata?: BuildMetadata): Array<VertexWarning> | undefined {
if (!metadata) {
metadata = this.resolveMetadata();
if (!metadata) {
return undefined;
}
}
if ('buildx.build.warnings' in metadata) {
return metadata['buildx.build.warnings'] as Array<VertexWarning>;
}
return undefined;
}
public resolveDigest(metadata?: BuildMetadata): string | undefined {
if (!metadata) {
metadata = this.resolveMetadata();

View File

@@ -16,6 +16,7 @@
import crypto from 'crypto';
import fs from 'fs';
import he from 'he';
import jsyaml from 'js-yaml';
import os from 'os';
import path from 'path';
@@ -35,6 +36,7 @@ import {jwtDecode, JwtPayload} from 'jwt-decode';
import {Util} from './util';
import {VertexWarning} from './types/buildkit/client';
import {BuildSummaryOpts, GitHubActionsRuntimeToken, GitHubActionsRuntimeTokenAC, GitHubRepo, UploadArtifactOpts, UploadArtifactResponse} from './types/github';
export interface GitHubOpts {
@@ -64,6 +66,14 @@ export class GitHub {
return process.env.GITHUB_API_URL || 'https://api.github.com';
}
static get isGHES(): boolean {
const serverURL = new URL(GitHub.serverURL);
const hostname = serverURL.hostname.trimEnd().toUpperCase();
const isGitHubHost = hostname === 'GITHUB.COM';
const isGHESHost = hostname.endsWith('.GHE.COM') || hostname.endsWith('.GHE.LOCALHOST');
return !isGitHubHost && !isGHESHost;
}
static get repository(): string {
return `${github.context.repo.owner}/${github.context.repo.repo}`;
}
@@ -121,6 +131,10 @@ export class GitHub {
}
public static async uploadArtifact(opts: UploadArtifactOpts): Promise<UploadArtifactResponse> {
if (GitHub.isGHES) {
throw new Error('@actions/artifact v2.0.0+ is currently not supported on GHES.');
}
const artifactName = path.basename(opts.filename);
const backendIds = getBackendIdsFromToken();
const artifactClient = internalArtifactTwirpClient();
@@ -229,25 +243,23 @@ export class GitHub {
// prettier-ignore
const sum = core.summary
.addHeading('Docker Build summary', 1)
.addHeading('Docker Build summary', 2)
.addRaw(`<p>`)
.addRaw(`For a detailed look at the build, download the following build record archive and import it into Docker Desktop's Builds view. `)
.addBreak()
.addRaw(`Build records include details such as timing, dependencies, results, logs, traces, and other information about a build. `)
.addRaw(addLink('Learn more', 'https://docs.docker.com/go/build-summary/'))
.addRaw(addLink('Learn more', 'https://www.docker.com/blog/new-beta-feature-deep-dive-into-github-actions-docker-builds-with-docker-desktop/?utm_source=github&utm_medium=actions'))
.addRaw('</p>')
.addRaw(`<p>`)
.addRaw(`:arrow_down: ${addLink(`<strong>${Util.stringToUnicodeEntities(opts.uploadRes.filename)}</strong>`, artifactRelativeURL)} (${Util.formatFileSize(opts.uploadRes.size)})`)
.addBreak()
.addRaw(`This file includes <strong>${refsSize} build record${refsSize > 1 ? 's' : ''}</strong>.`)
.addRaw(`:arrow_down: ${addLink(`<strong>${Util.stringToUnicodeEntities(opts.uploadRes.filename)}</strong>`, artifactRelativeURL)} (${Util.formatFileSize(opts.uploadRes.size)} - includes <strong>${refsSize} build record${refsSize > 1 ? 's' : ''}</strong>)`)
.addRaw(`</p>`)
.addRaw(`<p>`)
.addRaw(`Find this useful? `)
.addRaw(addLink('Let us know', 'https://docs.docker.com/feedback/gha-build-summary'))
.addRaw('</p>');
sum.addHeading('Preview', 2);
// Preview
sum.addRaw('<p>');
const summaryTableData: Array<Array<SummaryTableCell>> = [
[
{header: true, data: 'ID'},
@@ -257,7 +269,7 @@ export class GitHub {
{header: true, data: 'Duration'}
]
];
let summaryError: string | undefined;
let buildError: string | undefined;
for (const ref in opts.exportRes.summaries) {
if (Object.prototype.hasOwnProperty.call(opts.exportRes.summaries, ref)) {
const summary = opts.exportRes.summaries[ref];
@@ -270,31 +282,91 @@ export class GitHub {
{data: summary.duration}
]);
if (summary.error) {
summaryError = summary.error;
buildError = summary.error;
}
}
}
sum.addTable([...summaryTableData]);
if (summaryError) {
sum.addHeading('Error', 4);
sum.addCodeBlock(summaryError, 'text');
sum.addRaw(`</p>`);
// Build error
if (buildError) {
sum.addRaw(`<blockquote>`);
if (Util.countLines(buildError) > 10) {
// prettier-ignore
sum
.addRaw(`<details><summary><strong>Error</strong></summary>`)
.addCodeBlock(he.encode(buildError), 'text')
.addRaw(`</details>`);
} else {
// prettier-ignore
sum
.addRaw(`<strong>Error</strong>`)
.addBreak()
.addRaw(`<p>`)
.addCodeBlock(he.encode(buildError), 'text')
.addRaw(`</p>`);
}
sum.addRaw(`</blockquote>`);
}
// Build inputs
if (opts.inputs) {
sum.addHeading('Build inputs', 2).addCodeBlock(
jsyaml.dump(opts.inputs, {
indent: 2,
lineWidth: -1
}),
'yaml'
);
// prettier-ignore
sum.addRaw(`<details><summary><strong>Build inputs</strong></summary>`)
.addCodeBlock(
jsyaml.dump(opts.inputs, {
indent: 2,
lineWidth: -1
}), 'yaml'
)
.addRaw(`</details>`);
}
// Bake definition
if (opts.bakeDefinition) {
sum.addHeading('Bake definition', 2).addCodeBlock(JSON.stringify(opts.bakeDefinition, null, 2), 'json');
// prettier-ignore
sum.addRaw(`<details><summary><strong>Bake definition</strong></summary>`)
.addCodeBlock(JSON.stringify(opts.bakeDefinition, null, 2), 'json')
.addRaw(`</details>`);
}
core.info(`Writing summary`);
await sum.addSeparator().write();
}
public static async annotateBuildWarnings(source: string, warnings?: Array<VertexWarning>): Promise<void> {
(warnings ?? []).forEach(warning => {
if (!warning.detail || !warning.short) {
return;
}
const title = warning.detail.map(encoded => atob(encoded)).join(' ');
let message = atob(warning.short).replace(/\s\(line \d+\)$/, '');
if (warning.url) {
// https://github.com/docker/buildx/blob/d8c9ebde1fdcf659f1fa3efa6ccc27a28b0f1564/commands/build.go#L854
message += `\nMore info: ${warning.url}`;
}
// GitHub annotations don't clearly show ranges of lines, so we'll just
// show the first line
const startLine = warning.range && warning.range.length > 0 ? warning.range[0]?.start.line : undefined;
// TODO: When GitHub annotations support showing ranges properly, we can use this code
// let startLine: number | undefined, endLine: number | undefined;
// for (const range of warning.range ?? []) {
// if (range.start.line && (!startLine || range.start.line < startLine)) {
// startLine = range.start.line;
// }
// if (range.end.line && (!endLine || range.end.line > endLine)) {
// endLine = range.end.line;
// }
// }
core.warning(message, {
title: title,
file: source,
startLine: startLine
});
});
}
}

44
src/types/buildkit/git.ts Normal file
View File

@@ -0,0 +1,44 @@
/**
* Copyright 2024 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 GitURL {
scheme: string;
host: string;
path: string;
user?: URLUserInfo;
fragment?: GitURLFragment;
remote: string;
}
export interface GitURLFragment {
ref: string;
subdir: string;
}
export interface GitRef {
remote?: string;
shortName?: string;
commit?: string;
subDir?: string;
indistinguishableFromLocal?: boolean;
unencryptedTCP?: boolean;
}
export interface URLUserInfo {
username: string;
password: string;
passwordSet: boolean;
}

View File

@@ -19,10 +19,6 @@ export interface BakeDefinition {
target: Record<string, Target>;
}
export interface BakeMetadata {
[target: string]: Record<string, string>;
}
export interface Group {
targets: Array<string>;
}

View File

@@ -185,4 +185,8 @@ export class Util {
.map(char => `&#x${char.charCodeAt(0).toString(16)};`)
.join('');
}
public static countLines(input: string): number {
return input.split(/\r\n|\r|\n/).length;
}
}

View File

@@ -1112,6 +1112,7 @@ __metadata:
"@octokit/plugin-rest-endpoint-methods": ^10.4.0
"@types/csv-parse": ^1.2.2
"@types/gunzip-maybe": ^1.4.2
"@types/he": ^1.2.3
"@types/js-yaml": ^4.0.9
"@types/node": ^20.12.10
"@types/semver": ^7.5.8
@@ -1129,6 +1130,7 @@ __metadata:
eslint-plugin-prettier: ^5.1.3
gunzip-maybe: ^1.4.2
handlebars: ^4.7.8
he: ^1.2.0
jest: ^29.7.0
js-yaml: ^4.1.0
jwt-decode: ^4.0.0
@@ -2175,6 +2177,13 @@ __metadata:
languageName: node
linkType: hard
"@types/he@npm:^1.2.3":
version: 1.2.3
resolution: "@types/he@npm:1.2.3"
checksum: e77851c73dd7b9902d92fe0118a26246a7f3676a3a1c6eb1408305187ef73b57c22550b1435946b983267f961d935554d5d0e1b458416932552f31e763e1aa41
languageName: node
linkType: hard
"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1":
version: 2.0.3
resolution: "@types/istanbul-lib-coverage@npm:2.0.3"
@@ -4923,6 +4932,15 @@ __metadata:
languageName: node
linkType: hard
"he@npm:^1.2.0":
version: 1.2.0
resolution: "he@npm:1.2.0"
bin:
he: bin/he
checksum: 3d4d6babccccd79c5c5a3f929a68af33360d6445587d628087f39a965079d84f18ce9c3d3f917ee1e3978916fc833bb8b29377c3b403f919426f91bc6965e7a7
languageName: node
linkType: hard
"html-escaper@npm:^2.0.0":
version: 2.0.2
resolution: "html-escaper@npm:2.0.2"