diff --git a/commands/history/inspect.go b/commands/history/inspect.go index 432f8d26..e83298cd 100644 --- a/commands/history/inspect.go +++ b/commands/history/inspect.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" "text/tabwriter" + "text/template" "time" "github.com/containerd/containerd/v2/core/content" @@ -62,81 +63,83 @@ type inspectOptions struct { } type inspectOutput struct { - Name string `json:"name,omitempty"` - Context string `json:"context,omitempty"` - Dockerfile string `json:"dockerfile,omitempty"` - VCSRepository string `json:"vcs_repository,omitempty"` - VCSRevision string `json:"vcs_revision,omitempty"` - Target string `json:"target,omitempty"` - Platform []string `json:"platform,omitempty"` - KeepGitDir bool `json:"keep_git_dir,omitempty"` + Name string `json:",omitempty"` + Ref string - NamedContexts []keyValueOutput `json:"named_contexts,omitempty"` + Context string `json:",omitempty"` + Dockerfile string `json:",omitempty"` + VCSRepository string `json:",omitempty"` + VCSRevision string `json:",omitempty"` + Target string `json:",omitempty"` + Platform []string `json:",omitempty"` + KeepGitDir bool `json:",omitempty"` - StartedAt *time.Time `json:"started_at,omitempty"` - CompletedAt *time.Time `json:"complete_at,omitempty"` - Duration time.Duration `json:"duration,omitempty"` - Status statusT `json:"status,omitempty"` - Error *errorOutput `json:"error,omitempty"` + NamedContexts []keyValueOutput `json:",omitempty"` - NumCompletedSteps int32 `json:"num_completed_steps"` - NumTotalSteps int32 `json:"num_total_steps"` - NumCachedSteps int32 `json:"num_cached_steps"` + StartedAt *time.Time `json:",omitempty"` + CompletedAt *time.Time `json:",omitempty"` + Duration time.Duration `json:",omitempty"` + Status statusT `json:",omitempty"` + Error *errorOutput `json:",omitempty"` - BuildArgs []keyValueOutput `json:"build_args,omitempty"` - Labels []keyValueOutput `json:"labels,omitempty"` + NumCompletedSteps int32 + NumTotalSteps int32 + NumCachedSteps int32 - Config configOutput `json:"config,omitempty"` + BuildArgs []keyValueOutput `json:",omitempty"` + Labels []keyValueOutput `json:",omitempty"` - Materials []materialOutput `json:"materials,omitempty"` - Attachments []attachmentOutput `json:"attachments,omitempty"` + Config configOutput `json:",omitempty"` - Errors []string `json:"errors,omitempty"` + Materials []materialOutput `json:",omitempty"` + Attachments []attachmentOutput `json:",omitempty"` + + Errors []string `json:",omitempty"` } type configOutput struct { - Network string `json:"network,omitempty"` - ExtraHosts []string `json:"extra_hosts,omitempty"` - Hostname string `json:"hostname,omitempty"` - CgroupParent string `json:"cgroup_parent,omitempty"` - ImageResolveMode string `json:"image_resolve_mode,omitempty"` - MultiPlatform bool `json:"multi_platform,omitempty"` - NoCache bool `json:"no_cache,omitempty"` - NoCacheFilter []string `json:"no_cache_filter,omitempty"` + Network string `json:",omitempty"` + ExtraHosts []string `json:",omitempty"` + Hostname string `json:",omitempty"` + CgroupParent string `json:",omitempty"` + ImageResolveMode string `json:",omitempty"` + MultiPlatform bool `json:",omitempty"` + NoCache bool `json:",omitempty"` + NoCacheFilter []string `json:",omitempty"` - ShmSize string `json:"shm_size,omitempty"` - Ulimit string `json:"ulimit,omitempty"` - CacheMountNS string `json:"cache_mount_ns,omitempty"` - DockerfileCheckConfig string `json:"dockerfile_check_config,omitempty"` - SourceDateEpoch string `json:"source_date_epoch,omitempty"` - SandboxHostname string `json:"sandbox_hostname,omitempty"` + ShmSize string `json:",omitempty"` + Ulimit string `json:",omitempty"` + CacheMountNS string `json:",omitempty"` + DockerfileCheckConfig string `json:",omitempty"` + SourceDateEpoch string `json:",omitempty"` + SandboxHostname string `json:",omitempty"` - RestRaw []keyValueOutput `json:"rest_raw,omitempty"` + RestRaw []keyValueOutput `json:",omitempty"` } type materialOutput struct { - URI string `json:"uri,omitempty"` - Digests []string `json:"digests,omitempty"` + URI string `json:",omitempty"` + Digests []string `json:",omitempty"` } type attachmentOutput struct { - Digest string `json:"digest,omitempty"` - Platform string `json:"platform,omitempty"` - Type string `json:"type,omitempty"` + Digest string `json:",omitempty"` + Platform string `json:",omitempty"` + Type string `json:",omitempty"` } type errorOutput struct { - Code int `json:"code,omitempty"` - Message string `json:"message,omitempty"` - Name string `json:"name,omitempty"` - Logs []string `json:"logs,omitempty"` - Sources []byte `json:"sources,omitempty"` - Stack []byte `json:"stack,omitempty"` + Code int `json:",omitempty"` + Message string `json:",omitempty"` + Name string `json:",omitempty"` + Logs []string `json:",omitempty"` + Sources []byte `json:",omitempty"` + Stack []byte `json:",omitempty"` } type keyValueOutput struct { - Name string `json:"name,omitempty"` - Value string `json:"value,omitempty"` + Name string `json:",omitempty"` + Value string `json:",omitempty"` } func readAttr[T any](attrs map[string]string, k string, dest *T, f func(v string) (T, bool)) { @@ -259,6 +262,8 @@ workers0: delete(attrs, "filename") out.Name = buildName(rec.FrontendAttrs, st) + out.Ref = rec.Ref + out.Context = context out.Dockerfile = dockerfile @@ -467,11 +472,26 @@ workers0: enc.SetIndent("", " ") return enc.Encode(out) } else if opts.format != formatter.RawFormatKey { - return errors.Errorf("unsupported format %q", opts.format) + tmpl, err := template.New("inspect").Parse(opts.format) + if err != nil { + return errors.Wrapf(err, "failed to parse format template") + } + var buf bytes.Buffer + if err := tmpl.Execute(&buf, out); err != nil { + return errors.Wrapf(err, "failed to execute format template") + } + fmt.Fprintln(dockerCli.Out(), buf.String()) + return nil } tw := tabwriter.NewWriter(dockerCli.Out(), 1, 8, 1, '\t', 0) + if out.Name != "" { + fmt.Fprintf(tw, "Name:\t%s\n", out.Name) + } + if opts.ref == "" && out.Ref != "" { + fmt.Fprintf(tw, "Ref:\t%s\n", out.Ref) + } if out.Context != "" { fmt.Fprintf(tw, "Context:\t%s\n", out.Context) } diff --git a/docs/reference/buildx_history_inspect.md b/docs/reference/buildx_history_inspect.md index e6f54cdb..4af49f09 100644 --- a/docs/reference/buildx_history_inspect.md +++ b/docs/reference/buildx_history_inspect.md @@ -25,22 +25,25 @@ Inspect a build ### Format the output (--format) -Output format can be one of `raw`, `json`. +The formatting options (`--format`) pretty-prints the output to `raw` (default), +`json` or using a Go template. ```console -$ docker buildx history inspect --format raw +$ docker buildx history inspect +Name: buildx (binaries) Context: . Dockerfile: Dockerfile VCS Repository: https://github.com/crazy-max/buildx.git -VCS Revision: 04aab6958cb5feb012a3c607569573b5cab141e1 +VCS Revision: f15eaa1ee324ffbbab29605600d27a84cab86361 Target: binaries Platforms: linux/amd64 Keep Git Dir: true -Started: 2025-02-06 16:15:13 -Duration: 1m 3s +Started: 2025-02-07 11:56:24 +Duration: 1m 1s Build Steps: 16/16 (25% cached) +Image Resolve Mode: local Materials: URI DIGEST @@ -50,31 +53,65 @@ pkg:docker/tonistiigi/xx@1.6.1?platform=linux%2Famd64 sha256:923441d7c Attachments: DIGEST PLATFORM TYPE -sha256:1b44912514074d3e309d80f8a5886a4d89eeeb52bef4d3e57ced17d1781bfce1 https://slsa.dev/provenance/v0.2 +sha256:217329d2af959d4f02e3a96dcbe62bf100cab1feb8006a047ddfe51a5397f7e3 https://slsa.dev/provenance/v0.2 -Print build logs: docker buildx history logs qrdbfvaoarfz42ye54lzx9aoy +Print build logs: docker buildx history logs g9808bwrjrlkbhdamxklx660b ``` ```console $ docker buildx history inspect --format json { - "name": "buildx (binaries)", - "context": ".", - "dockerfile": "Dockerfile", - "vcs_repository": "https://github.com/crazy-max/buildx.git", - "vcs_revision": "04aab6958cb5feb012a3c607569573b5cab141e1", - "target": "binaries", - "platform": [ + "Name": "buildx (binaries)", + "Ref": "5w7vkqfi0rf59hw4hnmn627r9", + "Context": ".", + "Dockerfile": "Dockerfile", + "VCSRepository": "https://github.com/crazy-max/buildx.git", + "VCSRevision": "f15eaa1ee324ffbbab29605600d27a84cab86361", + "Target": "binaries", + "Platform": [ "linux/amd64" ], - "keep_git_dir": true, - "started_at": "2025-02-06T16:15:13.077644732+01:00", - "complete_at": "2025-02-06T16:16:17.046656296+01:00", - "duration": 63969011564, - "status": "completed", - "num_completed_steps": 16, - "num_total_steps": 16, - "num_cached_steps": 4, - "config": {} + "KeepGitDir": true, + "StartedAt": "2025-02-07T12:01:05.75807272+01:00", + "CompletedAt": "2025-02-07T12:02:07.991778875+01:00", + "Duration": 62233706155, + "Status": "completed", + "NumCompletedSteps": 16, + "NumTotalSteps": 16, + "NumCachedSteps": 4, + "Config": { + "ImageResolveMode": "local" + }, + "Materials": [ + { + "URI": "pkg:docker/docker/dockerfile@1", + "Digests": [ + "sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d801e66d25" + ] + }, + { + "URI": "pkg:docker/golang@1.23-alpine3.21?platform=linux%2Famd64", + "Digests": [ + "sha256:2c49857f2295e89b23b28386e57e018a86620a8fede5003900f2d138ba9c4037" + ] + }, + { + "URI": "pkg:docker/tonistiigi/xx@1.6.1?platform=linux%2Famd64", + "Digests": [ + "sha256:923441d7c25f1e2eb5789f82d987693c47b8ed987c4ab3b075d6ed2b5d6779a3" + ] + } + ], + "Attachments": [ + { + "Digest": "sha256:450fdd2e6b868fecd69e9891c2c404ba461aa38a47663b4805edeb8d2baf80b1", + "Type": "https://slsa.dev/provenance/v0.2" + } + ] } ``` + +```console +$ docker buildx history inspect --format "{{.Name}}: {{.VCSRepository}} ({{.VCSRevision}})" +buildx (binaries): https://github.com/crazy-max/buildx.git (f15eaa1ee324ffbbab29605600d27a84cab86361) +```