diff --git a/__tests__/fixtures/lint.Dockerfile b/__tests__/fixtures/lint.Dockerfile new file mode 100644 index 0000000..c50f223 --- /dev/null +++ b/__tests__/fixtures/lint.Dockerfile @@ -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 diff --git a/__tests__/github.test.itg.ts b/__tests__/github.test.itg.ts index 12ce561..20858de 100644 --- a/__tests__/github.test.itg.ts +++ b/__tests__/github.test.itg.ts @@ -249,3 +249,40 @@ maybe('writeBuildSummary', () => { }); }); }); + +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); + }); +}); diff --git a/src/github.ts b/src/github.ts index 9cfeb01..add23fa 100644 --- a/src/github.ts +++ b/src/github.ts @@ -37,6 +37,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 { @@ -328,4 +329,39 @@ export class GitHub { core.info(`Writing summary`); await sum.addSeparator().write(); } + + public static async annotateBuildWarnings(source: string, warnings?: Array): Promise { + (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 + }); + }); + } }