mirror of
				https://gitea.com/docker/build-push-action.git
				synced 2025-10-31 09:08:18 +07:00 
			
		
		
		
	Merge pull request #746 from crazy-max/attests-sbom-provenance-inputs
add attests, provenance and sbom inputs
This commit is contained in:
		
						commit
						c40bf0fdf6
					
				
							
								
								
									
										148
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										148
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -84,7 +84,7 @@ jobs: | |||||||
|       - |       - | ||||||
|         name: Inspect |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 |           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' | ||||||
|       - |       - | ||||||
|         name: Check digest |         name: Check digest | ||||||
|         run: | |         run: | | ||||||
| @ -143,7 +143,7 @@ jobs: | |||||||
|       - |       - | ||||||
|         name: Inspect |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 |           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' | ||||||
|       - |       - | ||||||
|         name: Check digest |         name: Check digest | ||||||
|         run: | |         run: | | ||||||
| @ -190,7 +190,7 @@ jobs: | |||||||
|       - |       - | ||||||
|         name: Inspect |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 |           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' | ||||||
|       - |       - | ||||||
|         name: Check digest |         name: Check digest | ||||||
|         run: | |         run: | | ||||||
| @ -491,6 +491,97 @@ jobs: | |||||||
|           cache-from: type=gha,scope=nocachefilter |           cache-from: type=gha,scope=nocachefilter | ||||||
|           cache-to: type=gha,scope=nocachefilter,mode=max |           cache-to: type=gha,scope=nocachefilter,mode=max | ||||||
| 
 | 
 | ||||||
|  |   attests-compat: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         include: | ||||||
|  |           - buildx: latest | ||||||
|  |             buildkit: moby/buildkit:buildx-stable-1 | ||||||
|  |           - buildx: latest | ||||||
|  |             buildkit: moby/buildkit:v0.10.6 | ||||||
|  |           - buildx: v0.9.1 | ||||||
|  |             buildkit: moby/buildkit:buildx-stable-1 | ||||||
|  |     steps: | ||||||
|  |       - | ||||||
|  |         name: Checkout | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |       - | ||||||
|  |         name: Set up Docker Buildx | ||||||
|  |         uses: docker/setup-buildx-action@v2 | ||||||
|  |         with: | ||||||
|  |           version: ${{ matrix.buildx }} | ||||||
|  |           driver-opts: | | ||||||
|  |             network=host | ||||||
|  |             image=${{ matrix.buildkit }} | ||||||
|  |       - | ||||||
|  |         name: Build | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           context: ./test/go | ||||||
|  |           file: ./test/go/Dockerfile | ||||||
|  |           outputs: type=cacheonly | ||||||
|  | 
 | ||||||
|  |   sbom: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         include: | ||||||
|  |           - target: image | ||||||
|  |             output: type=image,name=localhost:5000/name/app:latest,push=true | ||||||
|  |           - target: binary | ||||||
|  |             output: /tmp/buildx-build | ||||||
|  |     services: | ||||||
|  |       registry: | ||||||
|  |         image: registry:2 | ||||||
|  |         ports: | ||||||
|  |           - 5000:5000 | ||||||
|  |     steps: | ||||||
|  |       - | ||||||
|  |         name: Checkout | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |       - | ||||||
|  |         name: Set up Docker Buildx | ||||||
|  |         uses: docker/setup-buildx-action@v2 | ||||||
|  |         with: | ||||||
|  |           version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} | ||||||
|  |           driver-opts: | | ||||||
|  |             network=host | ||||||
|  |             image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} | ||||||
|  |       - | ||||||
|  |         name: Build | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           context: ./test/go | ||||||
|  |           file: ./test/go/Dockerfile | ||||||
|  |           target: ${{ matrix.target }} | ||||||
|  |           outputs: ${{ matrix.output }} | ||||||
|  |           sbom: true | ||||||
|  |           cache-from: type=gha,scope=attests-${{ matrix.target }} | ||||||
|  |           cache-to: type=gha,scope=attests-${{ matrix.target }},mode=max | ||||||
|  |       - | ||||||
|  |         name: Inspect image | ||||||
|  |         if: matrix.target == 'image' | ||||||
|  |         run: | | ||||||
|  |           docker buildx imagetools inspect localhost:5000/name/app:latest --format '{{json .}}' | ||||||
|  |       - | ||||||
|  |         name: Check output folder | ||||||
|  |         if: matrix.target == 'binary' | ||||||
|  |         run: | | ||||||
|  |           tree /tmp/buildx-build | ||||||
|  |       - | ||||||
|  |         name: Print provenance | ||||||
|  |         if: matrix.target == 'binary' | ||||||
|  |         run: | | ||||||
|  |           cat /tmp/buildx-build/provenance.json | jq | ||||||
|  |       - | ||||||
|  |         name: Print SBOM | ||||||
|  |         if: matrix.target == 'binary' | ||||||
|  |         run: | | ||||||
|  |           cat /tmp/buildx-build/sbom.spdx.json | jq | ||||||
|  | 
 | ||||||
|   multi: |   multi: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     strategy: |     strategy: | ||||||
| @ -536,7 +627,7 @@ jobs: | |||||||
|       - |       - | ||||||
|         name: Inspect |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 |           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' | ||||||
|       - |       - | ||||||
|         name: Check digest |         name: Check digest | ||||||
|         run: | |         run: | | ||||||
| @ -649,7 +740,6 @@ jobs: | |||||||
|         uses: docker/setup-qemu-action@v2 |         uses: docker/setup-qemu-action@v2 | ||||||
|       - |       - | ||||||
|         name: Set up Docker Buildx |         name: Set up Docker Buildx | ||||||
|         id: buildx |  | ||||||
|         uses: docker/setup-buildx-action@v2 |         uses: docker/setup-buildx-action@v2 | ||||||
|         with: |         with: | ||||||
|           version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} |           version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} | ||||||
| @ -657,7 +747,7 @@ jobs: | |||||||
|             network=host |             network=host | ||||||
|             image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} |             image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} | ||||||
|       - |       - | ||||||
|         name: Build and push (1) |         name: Build and push | ||||||
|         id: docker_build |         id: docker_build | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
| @ -672,54 +762,16 @@ jobs: | |||||||
|           cache-from: type=registry,ref=localhost:5000/name/app |           cache-from: type=registry,ref=localhost:5000/name/app | ||||||
|           cache-to: type=inline |           cache-to: type=inline | ||||||
|       - |       - | ||||||
|         name: Inspect (1) |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:latest |           docker buildx imagetools inspect localhost:5000/name/app:latest --format '{{json .}}' | ||||||
|       - |       - | ||||||
|         name: Check digest (1) |         name: Check digest | ||||||
|         run: | |         run: | | ||||||
|           if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then |           if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then | ||||||
|             echo "::error::Digest should not be empty" |             echo "::error::Digest should not be empty" | ||||||
|             exit 1 |             exit 1 | ||||||
|           fi |           fi | ||||||
|       - |  | ||||||
|         name: Prune |  | ||||||
|         run: | |  | ||||||
|           docker buildx prune -a -f --verbose |  | ||||||
|       - |  | ||||||
|         name: Build and push (2) |  | ||||||
|         id: docker_build2 |  | ||||||
|         uses: ./ |  | ||||||
|         with: |  | ||||||
|           context: ./test |  | ||||||
|           file: ./test/multi.Dockerfile |  | ||||||
|           builder: ${{ steps.buildx.outputs.name }} |  | ||||||
|           platforms: linux/amd64,linux/arm64 |  | ||||||
|           push: true |  | ||||||
|           tags: | |  | ||||||
|             localhost:5000/name/app:latest |  | ||||||
|             localhost:5000/name/app:1.0.0 |  | ||||||
|           cache-from: type=registry,ref=localhost:5000/name/app |  | ||||||
|           cache-to: type=inline |  | ||||||
|       - |  | ||||||
|         name: Inspect (2) |  | ||||||
|         run: | |  | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:latest |  | ||||||
|       - |  | ||||||
|         name: Check digest (2) |  | ||||||
|         run: | |  | ||||||
|           if [ -z "${{ steps.docker_build2.outputs.digest }}" ]; then |  | ||||||
|             echo "::error::Digest should not be empty" |  | ||||||
|             exit 1 |  | ||||||
|           fi |  | ||||||
|       - |  | ||||||
|         name: Compare digests |  | ||||||
|         run: | |  | ||||||
|           echo Compare "${{ steps.docker_build.outputs.digest }}" with "${{ steps.docker_build2.outputs.digest }}" |  | ||||||
|           if [ "${{ steps.docker_build.outputs.digest }}" != "${{ steps.docker_build2.outputs.digest }}" ]; then |  | ||||||
|             echo "::error::Digests should be identical" |  | ||||||
|             exit 1 |  | ||||||
|           fi |  | ||||||
| 
 | 
 | ||||||
|   github-cache: |   github-cache: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
| @ -760,7 +812,7 @@ jobs: | |||||||
|       - |       - | ||||||
|         name: Inspect |         name: Inspect | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 |           docker buildx imagetools inspect localhost:5000/name/app:1.0.0 --format '{{json .}}' | ||||||
| 
 | 
 | ||||||
|   standalone: |   standalone: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							| @ -120,4 +120,4 @@ jobs: | |||||||
|         name: Check manifest |         name: Check manifest | ||||||
|         if: github.event_name != 'pull_request' |         if: github.event_name != 'pull_request' | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect ${{ matrix.slug }}:${{ steps.meta.outputs.version }} |           docker buildx imagetools inspect ${{ matrix.slug }}:${{ steps.meta.outputs.version }} --format '{{json .}}' | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/example.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/example.yml
									
									
									
									
										vendored
									
									
								
							| @ -71,4 +71,4 @@ jobs: | |||||||
|         name: Check manifest |         name: Check manifest | ||||||
|         if: github.event_name != 'pull_request' |         if: github.event_name != 'pull_request' | ||||||
|         run: | |         run: | | ||||||
|           docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }} |           docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }} --format '{{json .}}' | ||||||
|  | |||||||
| @ -191,9 +191,10 @@ Following inputs can be used as `step.with` keys | |||||||
| > ``` | > ``` | ||||||
| 
 | 
 | ||||||
| | Name               | Type        | Description                                                                                                                                                                       | | | Name               | Type        | Description                                                                                                                                                                       | | ||||||
| |--------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | |--------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||||
| | `add-hosts`        | List/CSV    | List of [customs host-to-IP mapping](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) (e.g., `docker:10.180.0.1`)      | | | `add-hosts`        | List/CSV    | List of [customs host-to-IP mapping](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) (e.g., `docker:10.180.0.1`)      | | ||||||
| | `allow`            | List/CSV    | List of [extra privileged entitlement](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow) (e.g., `network.host,security.insecure`)                         | | | `allow`            | List/CSV    | List of [extra privileged entitlement](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow) (e.g., `network.host,security.insecure`)                         | | ||||||
|  | | `attests`          | List        | List of [attestation](https://docs.docker.com/build/attestations/) parameters (e.g., `type=sbom,generator=image`)                                                                 |  | ||||||
| | `builder`          | String      | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action)                                                                                       | | | `builder`          | String      | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action)                                                                                       | | ||||||
| | `build-args`       | List        | List of [build-time variables](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-arg)                                                                      | | | `build-args`       | List        | List of [build-time variables](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-arg)                                                                      | | ||||||
| | `build-contexts`   | List        | List of additional [build contexts](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-context) (e.g., `name=path`)                                         | | | `build-contexts`   | List        | List of additional [build contexts](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-context) (e.g., `name=path`)                                         | | ||||||
| @ -209,8 +210,10 @@ Following inputs can be used as `step.with` keys | |||||||
| | `no-cache-filters` | List/CSV    | Do not cache specified stages                                                                                                                                                     | | | `no-cache-filters` | List/CSV    | Do not cache specified stages                                                                                                                                                     | | ||||||
| | `outputs`¹         | List        | List of [output destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#output) (format: `type=local,dest=path`)                                         | | | `outputs`¹         | List        | List of [output destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#output) (format: `type=local,dest=path`)                                         | | ||||||
| | `platforms`        | List/CSV    | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) for build                                                                 | | | `platforms`        | List/CSV    | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) for build                                                                 | | ||||||
|  | | `provenance`       | Bool/String | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build (shorthand for `--attest=type=provenance`)                           | | ||||||
| | `pull`             | Bool        | Always attempt to pull all referenced images (default `false`)                                                                                                                    | | | `pull`             | Bool        | Always attempt to pull all referenced images (default `false`)                                                                                                                    | | ||||||
| | `push`             | Bool        | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) is a shorthand for `--output=type=registry` (default `false`)                                     | | | `push`             | Bool        | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) is a shorthand for `--output=type=registry` (default `false`)                                     | | ||||||
|  | | `sbom`             | Bool/String | Generate [SBOM](https://docs.docker.com/build/attestations/sbom/) attestation for the build (shorthand for `--attest=type=sbom`)                                                  | | ||||||
| | `secrets`          | List        | List of [secrets](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`)                | | | `secrets`          | List        | List of [secrets](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`)                | | ||||||
| | `secret-files`     | List        | List of [secret files](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`)         | | | `secret-files`     | List        | List of [secret files](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`)         | | ||||||
| | `shm-size`         | String      | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`)                                                                    | | | `shm-size`         | String      | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`)                                                                    | | ||||||
|  | |||||||
| @ -13,6 +13,9 @@ inputs: | |||||||
|   allow: |   allow: | ||||||
|     description: "List of extra privileged entitlement (e.g., network.host,security.insecure)" |     description: "List of extra privileged entitlement (e.g., network.host,security.insecure)" | ||||||
|     required: false |     required: false | ||||||
|  |   attests: | ||||||
|  |     description: "List of attestation parameters (e.g., type=sbom,generator=image)" | ||||||
|  |     required: false | ||||||
|   build-args: |   build-args: | ||||||
|     description: "List of build-time variables" |     description: "List of build-time variables" | ||||||
|     required: false |     required: false | ||||||
| @ -60,6 +63,9 @@ inputs: | |||||||
|   platforms: |   platforms: | ||||||
|     description: "List of target platforms for build" |     description: "List of target platforms for build" | ||||||
|     required: false |     required: false | ||||||
|  |   provenance: | ||||||
|  |     description: "Generate provenance attestation for the build (shorthand for --attest=type=provenance)" | ||||||
|  |     required: false | ||||||
|   pull: |   pull: | ||||||
|     description: "Always attempt to pull all referenced images" |     description: "Always attempt to pull all referenced images" | ||||||
|     required: false |     required: false | ||||||
| @ -68,6 +74,9 @@ inputs: | |||||||
|     description: "Push is a shorthand for --output=type=registry" |     description: "Push is a shorthand for --output=type=registry" | ||||||
|     required: false |     required: false | ||||||
|     default: 'false' |     default: 'false' | ||||||
|  |   sbom: | ||||||
|  |     description: "Generate SBOM attestation for the build (shorthand for --attest=type=sbom)" | ||||||
|  |     required: false | ||||||
|   secrets: |   secrets: | ||||||
|     description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)" |     description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)" | ||||||
|     required: false |     required: false | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/index.js.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/index.js.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										123
									
								
								src/buildx.ts
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								src/buildx.ts
									
									
									
									
									
								
							| @ -3,9 +3,24 @@ import fs from 'fs'; | |||||||
| import path from 'path'; | import path from 'path'; | ||||||
| import * as semver from 'semver'; | import * as semver from 'semver'; | ||||||
| import * as exec from '@actions/exec'; | import * as exec from '@actions/exec'; | ||||||
| 
 |  | ||||||
| import * as context from './context'; | import * as context from './context'; | ||||||
| 
 | 
 | ||||||
|  | export type Builder = { | ||||||
|  |   name?: string; | ||||||
|  |   driver?: string; | ||||||
|  |   nodes: Node[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export type Node = { | ||||||
|  |   name?: string; | ||||||
|  |   endpoint?: string; | ||||||
|  |   'driver-opts'?: Array<string>; | ||||||
|  |   status?: string; | ||||||
|  |   'buildkitd-flags'?: string; | ||||||
|  |   buildkit?: string; | ||||||
|  |   platforms?: string; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export async function getImageIDFile(): Promise<string> { | export async function getImageIDFile(): Promise<string> { | ||||||
|   return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep); |   return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep); | ||||||
| } | } | ||||||
| @ -126,6 +141,112 @@ export async function isAvailable(standalone?: boolean): Promise<boolean> { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export async function satisfiesBuildKitVersion(builderName: string, range: string, standalone?: boolean): Promise<boolean> { | ||||||
|  |   const builderInspect = await inspect(builderName, standalone); | ||||||
|  |   for (const node of builderInspect.nodes) { | ||||||
|  |     if (!node.buildkit) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     // BuildKit version reported by moby is in the format of `v0.11.0-moby`
 | ||||||
|  |     if (builderInspect.driver == 'docker' && !node.buildkit.endsWith('-moby')) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     const version = node.buildkit.replace(/-moby$/, ''); | ||||||
|  |     if (!semver.satisfies(version, range)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function inspect(name: string, standalone?: boolean): Promise<Builder> { | ||||||
|  |   const cmd = getCommand(['inspect', name], standalone); | ||||||
|  |   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 parseInspect(res.stdout); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function parseInspect(data: string): Promise<Builder> { | ||||||
|  |   const builder: Builder = { | ||||||
|  |     nodes: [] | ||||||
|  |   }; | ||||||
|  |   let node: Node = {}; | ||||||
|  |   for (const line of data.trim().split(`\n`)) { | ||||||
|  |     const [key, ...rest] = line.split(':'); | ||||||
|  |     const value = rest.map(v => v.trim()).join(':'); | ||||||
|  |     if (key.length == 0 || value.length == 0) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     switch (key.toLowerCase()) { | ||||||
|  |       case 'name': { | ||||||
|  |         if (builder.name == undefined) { | ||||||
|  |           builder.name = value; | ||||||
|  |         } else { | ||||||
|  |           if (Object.keys(node).length > 0) { | ||||||
|  |             builder.nodes.push(node); | ||||||
|  |             node = {}; | ||||||
|  |           } | ||||||
|  |           node.name = value; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'driver': { | ||||||
|  |         builder.driver = value; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'endpoint': { | ||||||
|  |         node.endpoint = value; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'driver options': { | ||||||
|  |         node['driver-opts'] = (value.match(/(\w+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2')); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'status': { | ||||||
|  |         node.status = value; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'flags': { | ||||||
|  |         node['buildkitd-flags'] = value; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'buildkit': { | ||||||
|  |         node.buildkit = value; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       case 'platforms': { | ||||||
|  |         let platforms: Array<string> = []; | ||||||
|  |         // if a preferred platform is being set then use only these
 | ||||||
|  |         // https://docs.docker.com/engine/reference/commandline/buildx_inspect/#get-information-about-a-builder-instance
 | ||||||
|  |         if (value.includes('*')) { | ||||||
|  |           for (const platform of value.split(', ')) { | ||||||
|  |             if (platform.includes('*')) { | ||||||
|  |               platforms.push(platform.replace('*', '')); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           // otherwise set all platforms available
 | ||||||
|  |           platforms = value.split(', '); | ||||||
|  |         } | ||||||
|  |         node.platforms = platforms.join(','); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (Object.keys(node).length > 0) { | ||||||
|  |     builder.nodes.push(node); | ||||||
|  |   } | ||||||
|  |   return builder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export async function getVersion(standalone?: boolean): Promise<string> { | export async function getVersion(standalone?: boolean): Promise<string> { | ||||||
|   const cmd = getCommand(['version'], standalone); |   const cmd = getCommand(['version'], standalone); | ||||||
|   return await exec |   return await exec | ||||||
|  | |||||||
							
								
								
									
										102
									
								
								src/context.ts
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								src/context.ts
									
									
									
									
									
								
							| @ -13,6 +13,7 @@ let _defaultContext, _tmpDir: string; | |||||||
| export interface Inputs { | export interface Inputs { | ||||||
|   addHosts: string[]; |   addHosts: string[]; | ||||||
|   allow: string[]; |   allow: string[]; | ||||||
|  |   attests: string[]; | ||||||
|   buildArgs: string[]; |   buildArgs: string[]; | ||||||
|   buildContexts: string[]; |   buildContexts: string[]; | ||||||
|   builder: string; |   builder: string; | ||||||
| @ -28,8 +29,10 @@ export interface Inputs { | |||||||
|   noCacheFilters: string[]; |   noCacheFilters: string[]; | ||||||
|   outputs: string[]; |   outputs: string[]; | ||||||
|   platforms: string[]; |   platforms: string[]; | ||||||
|  |   provenance: string; | ||||||
|   pull: boolean; |   pull: boolean; | ||||||
|   push: boolean; |   push: boolean; | ||||||
|  |   sbom: string; | ||||||
|   secrets: string[]; |   secrets: string[]; | ||||||
|   secretFiles: string[]; |   secretFiles: string[]; | ||||||
|   shmSize: string; |   shmSize: string; | ||||||
| @ -69,6 +72,7 @@ export async function getInputs(defaultContext: string): Promise<Inputs> { | |||||||
|   return { |   return { | ||||||
|     addHosts: await getInputList('add-hosts'), |     addHosts: await getInputList('add-hosts'), | ||||||
|     allow: await getInputList('allow'), |     allow: await getInputList('allow'), | ||||||
|  |     attests: await getInputList('attests', true), | ||||||
|     buildArgs: await getInputList('build-args', true), |     buildArgs: await getInputList('build-args', true), | ||||||
|     buildContexts: await getInputList('build-contexts', true), |     buildContexts: await getInputList('build-contexts', true), | ||||||
|     builder: core.getInput('builder'), |     builder: core.getInput('builder'), | ||||||
| @ -84,8 +88,10 @@ export async function getInputs(defaultContext: string): Promise<Inputs> { | |||||||
|     noCacheFilters: await getInputList('no-cache-filters'), |     noCacheFilters: await getInputList('no-cache-filters'), | ||||||
|     outputs: await getInputList('outputs', true), |     outputs: await getInputList('outputs', true), | ||||||
|     platforms: await getInputList('platforms'), |     platforms: await getInputList('platforms'), | ||||||
|  |     provenance: core.getInput('provenance'), | ||||||
|     pull: core.getBooleanInput('pull'), |     pull: core.getBooleanInput('pull'), | ||||||
|     push: core.getBooleanInput('push'), |     push: core.getBooleanInput('push'), | ||||||
|  |     sbom: core.getInput('sbom'), | ||||||
|     secrets: await getInputList('secrets', true), |     secrets: await getInputList('secrets', true), | ||||||
|     secretFiles: await getInputList('secret-files', true), |     secretFiles: await getInputList('secret-files', true), | ||||||
|     shmSize: core.getInput('shm-size'), |     shmSize: core.getInput('shm-size'), | ||||||
| @ -97,17 +103,17 @@ export async function getInputs(defaultContext: string): Promise<Inputs> { | |||||||
|   }; |   }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> { | export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string, standalone?: boolean): Promise<Array<string>> { | ||||||
|   const context = handlebars.compile(inputs.context)({defaultContext}); |   const context = handlebars.compile(inputs.context)({defaultContext}); | ||||||
|   // prettier-ignore
 |   // prettier-ignore
 | ||||||
|   return [ |   return [ | ||||||
|     ...await getBuildArgs(inputs, defaultContext, context, buildxVersion), |     ...await getBuildArgs(inputs, defaultContext, context, buildxVersion, standalone), | ||||||
|     ...await getCommonArgs(inputs, buildxVersion), |     ...await getCommonArgs(inputs, buildxVersion), | ||||||
|     context |     context | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function getBuildArgs(inputs: Inputs, defaultContext: string, context: string, buildxVersion: string): Promise<Array<string>> { | async function getBuildArgs(inputs: Inputs, defaultContext: string, context: string, buildxVersion: string, standalone?: boolean): Promise<Array<string>> { | ||||||
|   const args: Array<string> = ['build']; |   const args: Array<string> = ['build']; | ||||||
|   await asyncForEach(inputs.addHosts, async addHost => { |   await asyncForEach(inputs.addHosts, async addHost => { | ||||||
|     args.push('--add-host', addHost); |     args.push('--add-host', addHost); | ||||||
| @ -115,6 +121,11 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str | |||||||
|   if (inputs.allow.length > 0) { |   if (inputs.allow.length > 0) { | ||||||
|     args.push('--allow', inputs.allow.join(',')); |     args.push('--allow', inputs.allow.join(',')); | ||||||
|   } |   } | ||||||
|  |   if (buildx.satisfies(buildxVersion, '>=0.10.0')) { | ||||||
|  |     await asyncForEach(inputs.attests, async attest => { | ||||||
|  |       args.push('--attest', attest); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|   await asyncForEach(inputs.buildArgs, async buildArg => { |   await asyncForEach(inputs.buildArgs, async buildArg => { | ||||||
|     args.push('--build-arg', buildArg); |     args.push('--build-arg', buildArg); | ||||||
|   }); |   }); | ||||||
| @ -150,6 +161,29 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, context: str | |||||||
|   if (inputs.platforms.length > 0) { |   if (inputs.platforms.length > 0) { | ||||||
|     args.push('--platform', inputs.platforms.join(',')); |     args.push('--platform', inputs.platforms.join(',')); | ||||||
|   } |   } | ||||||
|  |   if (buildx.satisfies(buildxVersion, '>=0.10.0')) { | ||||||
|  |     const prvBuilderID = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`; | ||||||
|  |     if (inputs.provenance) { | ||||||
|  |       args.push('--provenance', getProvenanceAttrs(inputs.provenance, prvBuilderID)); | ||||||
|  |     } else if ((await buildx.satisfiesBuildKitVersion(inputs.builder, '>=0.11.0', standalone)) && !hasDockerExport(inputs)) { | ||||||
|  |       // if provenance not specified and BuildKit version compatible for
 | ||||||
|  |       // attestation, set default provenance. Also needs to make sure user
 | ||||||
|  |       // doesn't want to explicitly load the image to docker.
 | ||||||
|  |       if (fromPayload('repository.private') !== false) { | ||||||
|  |         // if this is a private repository, we set the default provenance
 | ||||||
|  |         // attributes being set in buildx: https://github.com/docker/buildx/blob/fb27e3f919dcbf614d7126b10c2bc2d0b1927eb6/build/build.go#L603
 | ||||||
|  |         // along the builder-id attribute.
 | ||||||
|  |         args.push('--provenance', `mode=min,inline-only=true,builder-id=${prvBuilderID}`); | ||||||
|  |       } else { | ||||||
|  |         // for a public repository, we set max provenance mode and the
 | ||||||
|  |         // builder-id attribute.
 | ||||||
|  |         args.push('--provenance', `mode=max,builder-id=${prvBuilderID}`); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (inputs.sbom) { | ||||||
|  |       args.push('--sbom', inputs.sbom); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|   await asyncForEach(inputs.secrets, async secret => { |   await asyncForEach(inputs.secrets, async secret => { | ||||||
|     try { |     try { | ||||||
|       args.push('--secret', await buildx.getSecretString(secret)); |       args.push('--secret', await buildx.getSecretString(secret)); | ||||||
| @ -245,3 +279,65 @@ export const asyncForEach = async (array, callback) => { | |||||||
|     await callback(array[index], index, array); |     await callback(array[index], index, array); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||||
|  | function fromPayload(path: string): any { | ||||||
|  |   return select(github.context.payload, path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||||
|  | function select(obj: any, path: string): any { | ||||||
|  |   if (!obj) { | ||||||
|  |     return undefined; | ||||||
|  |   } | ||||||
|  |   const i = path.indexOf('.'); | ||||||
|  |   if (i < 0) { | ||||||
|  |     return obj[path]; | ||||||
|  |   } | ||||||
|  |   const key = path.slice(0, i); | ||||||
|  |   return select(obj[key], path.slice(i + 1)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getProvenanceAttrs(input: string, builderID: string): string { | ||||||
|  |   const fields = parse(input, { | ||||||
|  |     relaxColumnCount: true, | ||||||
|  |     skipEmptyLines: true | ||||||
|  |   })[0]; | ||||||
|  |   // check if builder-id attribute exists in the input
 | ||||||
|  |   for (const field of fields) { | ||||||
|  |     const parts = field | ||||||
|  |       .toString() | ||||||
|  |       .split(/(?<=^[^=]+?)=/) | ||||||
|  |       .map(item => item.trim()); | ||||||
|  |     if (parts[0] == 'builder-id') { | ||||||
|  |       return input; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   // if not add builder-id attribute
 | ||||||
|  |   return `${input},builder-id=${builderID}`; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function hasDockerExport(inputs: Inputs): boolean { | ||||||
|  |   if (inputs.load) { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |   for (const output of inputs.outputs) { | ||||||
|  |     const fields = parse(output, { | ||||||
|  |       relaxColumnCount: true, | ||||||
|  |       skipEmptyLines: true | ||||||
|  |     })[0]; | ||||||
|  |     for (const field of fields) { | ||||||
|  |       const parts = field | ||||||
|  |         .toString() | ||||||
|  |         .split(/(?<=^[^=]+?)=/) | ||||||
|  |         .map(item => item.trim()); | ||||||
|  |       if (parts.length != 2) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       if (parts[0] == 'type' && parts[1] == 'docker') { | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ async function run(): Promise<void> { | |||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     const args: string[] = await context.getArgs(inputs, defContext, buildxVersion); |     const args: string[] = await context.getArgs(inputs, defContext, buildxVersion, standalone); | ||||||
|     const buildCmd = buildx.getCommand(args, standalone); |     const buildCmd = buildx.getCommand(args, standalone); | ||||||
|     await exec |     await exec | ||||||
|       .getExecOutput(buildCmd.command, buildCmd.args, { |       .getExecOutput(buildCmd.command, buildCmd.args, { | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								test/go/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/go/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | FROM golang:1.19-alpine AS base | ||||||
|  | ENV CGO_ENABLED=0 | ||||||
|  | RUN apk add --no-cache file git | ||||||
|  | WORKDIR /src | ||||||
|  | 
 | ||||||
|  | FROM base as build | ||||||
|  | COPY go.mod go.sum ./ | ||||||
|  | RUN go mod download -x | ||||||
|  | COPY . . | ||||||
|  | RUN go build -ldflags "-s -w" -o /usr/bin/app . | ||||||
|  | 
 | ||||||
|  | FROM scratch AS binary | ||||||
|  | COPY --from=build /usr/bin/app /bin/app | ||||||
|  | 
 | ||||||
|  | FROM alpine:3.17 AS image | ||||||
|  | COPY --from=build /usr/bin/app /bin/app | ||||||
							
								
								
									
										19
									
								
								test/go/go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/go/go.mod
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | module github.com/docker/build-push-action/test/go | ||||||
|  | 
 | ||||||
|  | go 1.18 | ||||||
|  | 
 | ||||||
|  | require github.com/labstack/echo/v4 v4.9.1 | ||||||
|  | 
 | ||||||
|  | require ( | ||||||
|  | 	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | ||||||
|  | 	github.com/labstack/gommon v0.4.0 // indirect | ||||||
|  | 	github.com/mattn/go-colorable v0.1.11 // indirect | ||||||
|  | 	github.com/mattn/go-isatty v0.0.14 // indirect | ||||||
|  | 	github.com/valyala/bytebufferpool v1.0.0 // indirect | ||||||
|  | 	github.com/valyala/fasttemplate v1.2.1 // indirect | ||||||
|  | 	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect | ||||||
|  | 	golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect | ||||||
|  | 	golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect | ||||||
|  | 	golang.org/x/text v0.3.7 // indirect | ||||||
|  | 	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect | ||||||
|  | ) | ||||||
							
								
								
									
										38
									
								
								test/go/go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								test/go/go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|  | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||||
|  | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|  | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= | ||||||
|  | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= | ||||||
|  | github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y= | ||||||
|  | github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo= | ||||||
|  | github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= | ||||||
|  | github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= | ||||||
|  | github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= | ||||||
|  | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= | ||||||
|  | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= | ||||||
|  | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
|  | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||||||
|  | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
|  | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= | ||||||
|  | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | ||||||
|  | github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= | ||||||
|  | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | ||||||
|  | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= | ||||||
|  | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||||
|  | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= | ||||||
|  | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||||
|  | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4= | ||||||
|  | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= | ||||||
|  | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||||||
|  | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= | ||||||
|  | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
|  | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
							
								
								
									
										31
									
								
								test/go/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								test/go/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"os" | ||||||
|  | 
 | ||||||
|  | 	"github.com/labstack/echo/v4" | ||||||
|  | 	"github.com/labstack/echo/v4/middleware" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	e := echo.New() | ||||||
|  | 
 | ||||||
|  | 	e.Use(middleware.Logger()) | ||||||
|  | 	e.Use(middleware.Recover()) | ||||||
|  | 
 | ||||||
|  | 	e.GET("/", func(c echo.Context) error { | ||||||
|  | 		return c.HTML(http.StatusOK, "Hello World") | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	e.GET("/ping", func(c echo.Context) error { | ||||||
|  | 		return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"}) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	httpPort := os.Getenv("HTTP_PORT") | ||||||
|  | 	if httpPort == "" { | ||||||
|  | 		httpPort = "8080" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	e.Logger.Fatal(e.Start(":" + httpPort)) | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user