diff --git a/internal/osbuild/result.go b/internal/osbuild/result.go index dee4b8c51..fe917983c 100644 --- a/internal/osbuild/result.go +++ b/internal/osbuild/result.go @@ -6,33 +6,74 @@ import ( "io" ) -type assembler struct { +type rawAssemblerResult struct { Name string `json:"name"` Options json.RawMessage `json:"options"` Success bool `json:"success"` Output string `json:"output"` } -type stage struct { - Name string `json:"name"` - Options json.RawMessage `json:"options"` - Success bool `json:"success"` - Output string `json:"output"` +type StageResult struct { + Name string `json:"name"` + Options json.RawMessage `json:"options"` + Success bool `json:"success"` + Output string `json:"output"` + Metadata StageMetadata `json:"metadata"` } -type build struct { - Stages []stage `json:"stages"` - TreeID string `json:"tree_id"` - Success bool `json:"success"` +// StageMetadata specify the metadata of a given stage-type. +type StageMetadata interface { + isStageMetadata() +} + +type rawStageResult struct { + Name string `json:"name"` + Options json.RawMessage `json:"options"` + Success bool `json:"success"` + Output string `json:"output"` + Metadata json.RawMessage `json:"metadata"` +} + +type buildResult struct { + Stages []StageResult `json:"stages"` + TreeID string `json:"tree_id"` + Success bool `json:"success"` } type Result struct { - TreeID string `json:"tree_id"` - OutputID string `json:"output_id"` - Build *build `json:"build"` - Stages []stage `json:"stages"` - Assembler *assembler `json:"assembler"` - Success bool `json:"success"` + TreeID string `json:"tree_id"` + OutputID string `json:"output_id"` + Build *buildResult `json:"build"` + Stages []StageResult `json:"stages"` + Assembler *rawAssemblerResult `json:"assembler"` + Success bool `json:"success"` +} + +func (result *StageResult) UnmarshalJSON(data []byte) error { + var rawStageResult rawStageResult + err := json.Unmarshal(data, &rawStageResult) + if err != nil { + return err + } + var metadata StageMetadata + switch rawStageResult.Name { + case "org.osbuild.rpm": + metadata = new(RPMStageMetadata) + err = json.Unmarshal(rawStageResult.Metadata, metadata) + if err != nil { + return err + } + default: + metadata = nil + } + + result.Name = rawStageResult.Name + result.Options = rawStageResult.Options + result.Success = rawStageResult.Success + result.Output = rawStageResult.Output + result.Metadata = metadata + + return nil } func (cr *Result) Write(writer io.Writer) error { diff --git a/internal/osbuild/result_test.go b/internal/osbuild/result_test.go index 9ffba32ef..98fed411b 100644 --- a/internal/osbuild/result_test.go +++ b/internal/osbuild/result_test.go @@ -2,29 +2,101 @@ package osbuild import ( "bytes" + "encoding/json" "testing" "github.com/stretchr/testify/assert" ) +func TestUnmarshall(t *testing.T) { + resultRaw := `{ + "success": true, + "build": { + "success": true, + "stages": [ + { + "name": "org.osbuild.rpm", + "id": "9eb0a6f6fd6e2995e107f5bcc6aa3b19643b02ec133bdc8a8ac614860b1bbf2d", + "success": true, + "output": "Building...", + "metadata": { + "packages": [ + { + "name": "libgcc", + "version": "10.0.1", + "release": "0.11.fc32", + "epoch": null, + "arch": "x86_64", + "sigmd5": "84fc907a5047aeebaf8da1642925a417" + }, + { + "name": "whois-nls", + "version": "5.5.6", + "release": "1.fc32", + "epoch": null, + "arch": "noarch", + "sigmd5": "f868cd02046630c8ce3a9c48820e2437" + } + ] + } + } + ] + } + }` + + var result Result + err := json.Unmarshal([]byte(resultRaw), &result) + assert.NoError(t, err) + + assert.Equal(t, result.Build.Stages[0].Name, "org.osbuild.rpm") + metadata, ok := result.Build.Stages[0].Metadata.(*RPMStageMetadata) + assert.True(t, ok) + package1 := metadata.Packages[0] + assert.Equal(t, package1.Name, "libgcc") + assert.Nil(t, package1.Epoch) + assert.Equal(t, package1.Version, "10.0.1") + assert.Equal(t, package1.Release, "0.11.fc32") + assert.Equal(t, package1.Arch, "x86_64") + assert.Equal(t, package1.SigMD5, "84fc907a5047aeebaf8da1642925a417") +} + func TestWriteFull(t *testing.T) { const testOptions = `{"msg": "test"}` - testStage := stage{ - Name: "testStage", + dnfStage := StageResult{ + Name: "org.osbuild.rpm", + Options: []byte(testOptions), + Success: true, + Output: "Finished", + Metadata: RPMStageMetadata{ + Packages: []RPMPackageMetadata{ + { + Name: "foobar", + Epoch: nil, + Version: "1", + Release: "1", + Arch: "noarch", + SigMD5: "deadbeef", + }, + }, + }, + } + + testStage := StageResult{ + Name: "org.osbuild.test", Options: []byte(testOptions), Success: true, Output: "Finished", } - testBuild := build{ - Stages: []stage{testStage}, + testBuild := buildResult{ + Stages: []StageResult{testStage}, TreeID: "treeID", Success: true, } - testAssembler := assembler{ + testAssembler := rawAssemblerResult{ Name: "testAssembler", Options: []byte(testOptions), Success: true, @@ -35,7 +107,7 @@ func TestWriteFull(t *testing.T) { TreeID: "TreeID", OutputID: "OutputID", Build: &testBuild, - Stages: []stage{testStage}, + Stages: []StageResult{dnfStage}, Assembler: &testAssembler, Success: true, } @@ -44,7 +116,7 @@ func TestWriteFull(t *testing.T) { assert.NoError(t, testComposeResult.Write(&b)) expectedMessage := `Build pipeline: -Stage testStage +Stage org.osbuild.test { "msg": "test" } @@ -52,7 +124,7 @@ Stage testStage Output: Finished Stages: -Stage: testStage +Stage: org.osbuild.rpm { "msg": "test" } diff --git a/internal/osbuild/rpm_stage.go b/internal/osbuild/rpm_stage.go index 71cbcd20f..b4979cf4d 100644 --- a/internal/osbuild/rpm_stage.go +++ b/internal/osbuild/rpm_stage.go @@ -28,3 +28,20 @@ func NewRPMStage(options *RPMStageOptions) *Stage { Options: options, } } + +// RPMStageMetadata gives the set of packages installed by the RPM stage +type RPMStageMetadata struct { + Packages []RPMPackageMetadata `json:"packages"` +} + +// RPMPackageMetadata contains the metadata extracted from one RPM header +type RPMPackageMetadata struct { + Name string `json:"name"` + Version string `json:"version"` + Release string `json:"release"` + Epoch *string `json:"epoch"` + Arch string `json:"arch"` + SigMD5 string `json:"sigmd5"` +} + +func (RPMStageMetadata) isStageMetadata() {}