Merge pull request #29484 from ellieayla/artifact-list-json-output

feat: Add output format: podman artifact ls --format=json
This commit is contained in:
Jan Rodák 2026-08-19 17:41:01 +02:00 • committed by GitHub
commit 4edc8d68e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 78 additions and 6 deletions

View file

@ -1,6 +1,7 @@
package artifact
import (
"encoding/json"
"fmt"
"os"
"time"
@ -41,6 +42,7 @@ type artifactListOutput struct {
Digest string
Repository string
Size string
sizeBytes int64
Tag string
created time.Time
VirtualSize string
@ -84,13 +86,8 @@ func list(cmd *cobra.Command, _ []string) error {
return err
}
return outputTemplate(cmd, reports)
}
func outputTemplate(cmd *cobra.Command, lrs []*entities.ArtifactListReport) error {
var err error
artifacts := make([]artifactListOutput, 0)
for _, lr := range lrs {
for _, lr := range reports {
var tag string
artifactName, err := lr.Artifact.GetName()
if err != nil {
@ -130,6 +127,7 @@ func outputTemplate(cmd *cobra.Command, lrs []*entities.ArtifactListReport) erro
Digest: artifactHash,
Repository: named.Name(),
Size: units.HumanSize(float64(lr.Artifact.TotalSizeBytes())),
sizeBytes: lr.Artifact.TotalSizeBytes(),
Tag: tag,
created: createdTime,
VirtualSize: fmt.Sprintf("%d", lr.Artifact.TotalSizeBytes()),
@ -137,6 +135,48 @@ func outputTemplate(cmd *cobra.Command, lrs []*entities.ArtifactListReport) erro
})
}
switch {
case report.IsJSON(listFlag.format):
return writeJSON(artifacts)
default:
return writeTemplate(cmd, artifacts)
}
}
func writeJSON(artifacts []artifactListOutput) error {
type artifact struct {
Repository string `json:"Repository,omitempty"`
CreatedAt string
Size int64
Tag string `json:"Tag,omitempty"`
Digest string
}
arti := make([]artifact, 0, len(artifacts))
for _, e := range artifacts {
var a artifact
a.Repository = e.Repository
a.CreatedAt = e.created.Format(time.RFC3339Nano)
a.Size = e.sizeBytes
a.Repository = e.Repository
a.Tag = e.Tag
a.Digest = e.Digest
arti = append(arti, a)
}
prettyJSON, err := json.MarshalIndent(arti, "", " ")
if err != nil {
return err
}
fmt.Println(string(prettyJSON))
return nil
}
func writeTemplate(cmd *cobra.Command, artifacts []artifactListOutput) error {
var err error
headers := report.Headers(artifactListOutput{}, map[string]string{
"REPOSITORY": "REPOSITORY",
"Tag": "TAG",

View file

@ -62,6 +62,19 @@ ab609fad386d 2.097GB
cd734b558ceb 12.58MB
```
List artifact details in json format
```
$ podman artifact ls --format json"
[
{
"Repository": "quay.io/artifact/foobar1",
"CreatedAt": "2026-06-16T00:00:57Z",
"Size": 12580000,
"Tag": "special",
"Digest": "cd734b558ceb"
}
]
```
## SEE ALSO

View file

@ -3,6 +3,7 @@
package integration
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
@ -51,6 +52,24 @@ var _ = Describe("Podman artifact", func() {
Expect(output).To(ContainElement(artifact1Name))
Expect(output).To(ContainElement(artifact2Name))
// --format=json should work, produce valid json
listFormatJsonSession := podmanTest.PodmanExitCleanly("artifact", "ls", "--format", "json")
Expect(listFormatJsonSession).Should(ExitCleanly())
jsonOutput := listFormatJsonSession.OutputToString()
Expect(jsonOutput).To(BeValidJSON())
// --format=json should contain repository and tag fields
jsonArtifactsList := []map[string]any{}
jsonUnmarshalErr := json.Unmarshal([]byte(jsonOutput), &jsonArtifactsList)
Expect(jsonUnmarshalErr).ToNot(HaveOccurred())
Expect(jsonArtifactsList).ToNot(BeEmpty())
for _, image := range jsonArtifactsList {
Expect(image).To(HaveKey("Repository"))
Expect(image).To(HaveKey("Tag"))
}
// Check default digest length (should be 12)
defaultFormatSession := podmanTest.PodmanExitCleanly("artifact", "ls", "--format", "{{.Digest}}")
defaultOutput := defaultFormatSession.OutputToStringArray()[0]