Skip to content

Commit 6c23a08

Browse files
authored
Merge pull request #1598 from joe-kimmel-vmw/1221-report-toml-for-the-peoples
adds flag for saving report toml to back build and rebase
2 parents d1024e9 + ac117c3 commit 6c23a08

10 files changed

Lines changed: 178 additions & 85 deletions

File tree

internal/build/lifecycle_execution.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ func (l *LifecycleExecution) Create(ctx context.Context, buildCache, launchCache
289289
If(l.opts.SBOMDestinationDir != "", WithPostContainerRunOperations(
290290
EnsureVolumeAccess(l.opts.Builder.UID(), l.opts.Builder.GID(), l.os, l.layersVolume, l.appVolume),
291291
CopyOutTo(l.mountPaths.sbomDir(), l.opts.SBOMDestinationDir))),
292+
If(l.opts.ReportDestinationDir != "", WithPostContainerRunOperations(
293+
EnsureVolumeAccess(l.opts.Builder.UID(), l.opts.Builder.GID(), l.os, l.layersVolume, l.appVolume),
294+
CopyOutTo(l.mountPaths.reportPath(), l.opts.ReportDestinationDir))),
292295
If(l.opts.Interactive, WithPostContainerRunOperations(
293296
EnsureVolumeAccess(l.opts.Builder.UID(), l.opts.Builder.GID(), l.os, l.layersVolume, l.appVolume),
294297
CopyOut(l.opts.Termui.ReadLayers, l.mountPaths.layersDir(), l.mountPaths.appDir()))),
@@ -652,6 +655,9 @@ func (l *LifecycleExecution) Export(ctx context.Context, buildCache, launchCache
652655
If(l.opts.SBOMDestinationDir != "", WithPostContainerRunOperations(
653656
EnsureVolumeAccess(l.opts.Builder.UID(), l.opts.Builder.GID(), l.os, l.layersVolume, l.appVolume),
654657
CopyOutTo(l.mountPaths.sbomDir(), l.opts.SBOMDestinationDir))),
658+
If(l.opts.ReportDestinationDir != "", WithPostContainerRunOperations(
659+
EnsureVolumeAccess(l.opts.Builder.UID(), l.opts.Builder.GID(), l.os, l.layersVolume, l.appVolume),
660+
CopyOutTo(l.mountPaths.reportPath(), l.opts.ReportDestinationDir))),
655661
If(l.opts.Interactive, WithPostContainerRunOperations(
656662
EnsureVolumeAccess(l.opts.Builder.UID(), l.opts.Builder.GID(), l.os, l.layersVolume, l.appVolume),
657663
CopyOut(l.opts.Termui.ReadLayers, l.mountPaths.layersDir(), l.mountPaths.appDir()))),

internal/build/lifecycle_execution_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,21 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) {
10071007
})
10081008
})
10091009

1010+
when("report destination directory is provided", func() {
1011+
lifecycleOps = append(lifecycleOps, func(opts *build.LifecycleOptions) {
1012+
opts.ReportDestinationDir = "a-destination-dir"
1013+
})
1014+
1015+
it("provides copy-sbom-func as a post container operation", func() {
1016+
h.AssertEq(t, fakePhase.CleanupCallCount, 1)
1017+
h.AssertEq(t, fakePhase.RunCallCount, 1)
1018+
1019+
h.AssertEq(t, len(configProvider.PostContainerRunOps()), 2)
1020+
h.AssertFunctionName(t, configProvider.PostContainerRunOps()[0], "EnsureVolumeAccess")
1021+
h.AssertFunctionName(t, configProvider.PostContainerRunOps()[1], "CopyOut")
1022+
})
1023+
})
1024+
10101025
when("--creation-time", func() {
10111026
when("platform < 0.9", func() {
10121027
platformAPI = api.MustParse("0.8")
@@ -1970,6 +1985,18 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) {
19701985
})
19711986
})
19721987

1988+
when("report destination directory is provided", func() {
1989+
lifecycleOps = append(lifecycleOps, func(opts *build.LifecycleOptions) {
1990+
opts.ReportDestinationDir = "a-destination-dir"
1991+
})
1992+
1993+
it("provides copy-sbom-func as a post container operation", func() {
1994+
h.AssertEq(t, len(configProvider.PostContainerRunOps()), 2)
1995+
h.AssertFunctionName(t, configProvider.PostContainerRunOps()[0], "EnsureVolumeAccess")
1996+
h.AssertFunctionName(t, configProvider.PostContainerRunOps()[1], "CopyOut")
1997+
})
1998+
})
1999+
19732000
when("--creation-time", func() {
19742001
when("platform < 0.9", func() {
19752002
platformAPI = api.MustParse("0.8")

internal/build/lifecycle_executor.go

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -67,35 +67,36 @@ func init() {
6767
}
6868

6969
type LifecycleOptions struct {
70-
AppPath string
71-
Image name.Reference
72-
Builder Builder
73-
BuilderImage string // differs from Builder.Name() and Builder.Image().Name() in that it includes the registry context
74-
LifecycleImage string
75-
RunImage string
76-
ProjectMetadata platform.ProjectMetadata
77-
ClearCache bool
78-
Publish bool
79-
TrustBuilder bool
80-
UseCreator bool
81-
Interactive bool
82-
Termui Termui
83-
DockerHost string
84-
Cache cache.CacheOpts
85-
CacheImage string
86-
HTTPProxy string
87-
HTTPSProxy string
88-
NoProxy string
89-
Network string
90-
AdditionalTags []string
91-
Volumes []string
92-
DefaultProcessType string
93-
FileFilter func(string) bool
94-
Workspace string
95-
GID int
96-
PreviousImage string
97-
SBOMDestinationDir string
98-
CreationTime *time.Time
70+
AppPath string
71+
Image name.Reference
72+
Builder Builder
73+
BuilderImage string // differs from Builder.Name() and Builder.Image().Name() in that it includes the registry context
74+
LifecycleImage string
75+
RunImage string
76+
ProjectMetadata platform.ProjectMetadata
77+
ClearCache bool
78+
Publish bool
79+
TrustBuilder bool
80+
UseCreator bool
81+
Interactive bool
82+
Termui Termui
83+
DockerHost string
84+
Cache cache.CacheOpts
85+
CacheImage string
86+
HTTPProxy string
87+
HTTPSProxy string
88+
NoProxy string
89+
Network string
90+
AdditionalTags []string
91+
Volumes []string
92+
DefaultProcessType string
93+
FileFilter func(string) bool
94+
Workspace string
95+
GID int
96+
PreviousImage string
97+
ReportDestinationDir string
98+
SBOMDestinationDir string
99+
CreationTime *time.Time
99100
}
100101

101102
func NewLifecycleExecutor(logger logging.Logger, docker client.CommonAPIClient) *LifecycleExecutor {

internal/build/mount_paths.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (m mountPaths) projectPath() string {
4242
return m.join(m.layersDir(), "project-metadata.toml")
4343
}
4444

45+
func (m mountPaths) reportPath() string {
46+
return m.join(m.layersDir(), "report.toml")
47+
}
48+
4549
func (m mountPaths) appDirName() string {
4650
return m.workspace
4751
}

internal/commands/build.go

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,33 @@ import (
2222
)
2323

2424
type BuildFlags struct {
25-
Publish bool
26-
ClearCache bool
27-
TrustBuilder bool
28-
Interactive bool
29-
DockerHost string
30-
CacheImage string
31-
Cache cache.CacheOpts
32-
AppPath string
33-
Builder string
34-
Registry string
35-
RunImage string
36-
Policy string
37-
Network string
38-
DescriptorPath string
39-
DefaultProcessType string
40-
LifecycleImage string
41-
Env []string
42-
EnvFiles []string
43-
Buildpacks []string
44-
Volumes []string
45-
AdditionalTags []string
46-
Workspace string
47-
GID int
48-
PreviousImage string
49-
SBOMDestinationDir string
50-
DateTime string
25+
Publish bool
26+
ClearCache bool
27+
TrustBuilder bool
28+
Interactive bool
29+
DockerHost string
30+
CacheImage string
31+
Cache cache.CacheOpts
32+
AppPath string
33+
Builder string
34+
Registry string
35+
RunImage string
36+
Policy string
37+
Network string
38+
DescriptorPath string
39+
DefaultProcessType string
40+
LifecycleImage string
41+
Env []string
42+
EnvFiles []string
43+
Buildpacks []string
44+
Volumes []string
45+
AdditionalTags []string
46+
Workspace string
47+
GID int
48+
PreviousImage string
49+
SBOMDestinationDir string
50+
ReportDestinationDir string
51+
DateTime string
5152
}
5253

5354
// Build an image from source code
@@ -171,6 +172,7 @@ func Build(logger logging.Logger, cfg config.Config, packClient PackClient) *cob
171172
PreviousImage: flags.PreviousImage,
172173
Interactive: flags.Interactive,
173174
SBOMDestinationDir: flags.SBOMDestinationDir,
175+
ReportDestinationDir: flags.ReportDestinationDir,
174176
CreationTime: dateTime,
175177
}); err != nil {
176178
return errors.Wrap(err, "failed to build")
@@ -238,6 +240,7 @@ This option may set DOCKER_HOST environment variable for the build container if
238240
cmd.Flags().IntVar(&buildFlags.GID, "gid", 0, `Override GID of user's group in the stack's build and run images. The provided value must be a positive number`)
239241
cmd.Flags().StringVar(&buildFlags.PreviousImage, "previous-image", "", "Set previous image to a particular tag reference, digest reference, or (when performing a daemon build) image ID")
240242
cmd.Flags().StringVar(&buildFlags.SBOMDestinationDir, "sbom-output-dir", "", "Path to export SBoM contents.\nOmitting the flag will yield no SBoM content.")
243+
cmd.Flags().StringVar(&buildFlags.ReportDestinationDir, "report-output-dir", "", "Path to export build report.toml.\nOmitting the flag yield no report file.")
241244
cmd.Flags().BoolVar(&buildFlags.Interactive, "interactive", false, "Launch a terminal UI to depict the build process")
242245
if !cfg.Experimental {
243246
cmd.Flags().MarkHidden("interactive")

internal/commands/rebase.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func Rebase(logger logging.Logger, cfg config.Config, pack PackClient) *cobra.Co
4949
cmd.Flags().BoolVar(&opts.Publish, "publish", false, "Publish to registry")
5050
cmd.Flags().StringVar(&opts.RunImage, "run-image", "", "Run image to use for rebasing")
5151
cmd.Flags().StringVar(&policy, "pull-policy", "", "Pull policy to use. Accepted values are always, never, and if-not-present. The default is always")
52+
cmd.Flags().StringVar(&opts.ReportDestinationDir, "report-output-dir", "", "Path to export build report.toml.\nOmitting the flag yield no report file.")
5253

5354
AddHelpFlag(cmd, "rebase")
5455
return cmd

pkg/client/build.go

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ type BuildOptions struct {
175175
// Directory to output any SBOM artifacts
176176
SBOMDestinationDir string
177177

178+
// Directory to output the report.toml metadata artifact
179+
ReportDestinationDir string
180+
178181
// Desired create time in the output image config
179182
CreationTime *time.Time
180183
}
@@ -351,35 +354,36 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error {
351354
}
352355

353356
lifecycleOpts := build.LifecycleOptions{
354-
AppPath: appPath,
355-
Image: imageRef,
356-
Builder: ephemeralBuilder,
357-
BuilderImage: builderRef.Name(),
358-
LifecycleImage: ephemeralBuilder.Name(),
359-
RunImage: runImageName,
360-
ProjectMetadata: projectMetadata,
361-
ClearCache: opts.ClearCache,
362-
Publish: opts.Publish,
363-
TrustBuilder: opts.TrustBuilder(opts.Builder),
364-
UseCreator: false,
365-
DockerHost: opts.DockerHost,
366-
Cache: opts.Cache,
367-
CacheImage: opts.CacheImage,
368-
HTTPProxy: proxyConfig.HTTPProxy,
369-
HTTPSProxy: proxyConfig.HTTPSProxy,
370-
NoProxy: proxyConfig.NoProxy,
371-
Network: opts.ContainerConfig.Network,
372-
AdditionalTags: opts.AdditionalTags,
373-
Volumes: processedVolumes,
374-
DefaultProcessType: opts.DefaultProcessType,
375-
FileFilter: fileFilter,
376-
Workspace: opts.Workspace,
377-
GID: opts.GroupID,
378-
PreviousImage: opts.PreviousImage,
379-
Interactive: opts.Interactive,
380-
Termui: termui.NewTermui(imageRef.Name(), ephemeralBuilder, runImageName),
381-
SBOMDestinationDir: opts.SBOMDestinationDir,
382-
CreationTime: opts.CreationTime,
357+
AppPath: appPath,
358+
Image: imageRef,
359+
Builder: ephemeralBuilder,
360+
BuilderImage: builderRef.Name(),
361+
LifecycleImage: ephemeralBuilder.Name(),
362+
RunImage: runImageName,
363+
ProjectMetadata: projectMetadata,
364+
ClearCache: opts.ClearCache,
365+
Publish: opts.Publish,
366+
TrustBuilder: opts.TrustBuilder(opts.Builder),
367+
UseCreator: false,
368+
DockerHost: opts.DockerHost,
369+
Cache: opts.Cache,
370+
CacheImage: opts.CacheImage,
371+
HTTPProxy: proxyConfig.HTTPProxy,
372+
HTTPSProxy: proxyConfig.HTTPSProxy,
373+
NoProxy: proxyConfig.NoProxy,
374+
Network: opts.ContainerConfig.Network,
375+
AdditionalTags: opts.AdditionalTags,
376+
Volumes: processedVolumes,
377+
DefaultProcessType: opts.DefaultProcessType,
378+
FileFilter: fileFilter,
379+
Workspace: opts.Workspace,
380+
GID: opts.GroupID,
381+
PreviousImage: opts.PreviousImage,
382+
Interactive: opts.Interactive,
383+
Termui: termui.NewTermui(imageRef.Name(), ephemeralBuilder, runImageName),
384+
ReportDestinationDir: opts.ReportDestinationDir,
385+
SBOMDestinationDir: opts.SBOMDestinationDir,
386+
CreationTime: opts.CreationTime,
383387
}
384388

385389
lifecycleVersion := ephemeralBuilder.LifecycleDescriptor().Info.Version

pkg/client/build_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,17 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
25162516
})
25172517
})
25182518

2519+
when("report destination dir option", func() {
2520+
it("passthroughs to lifecycle", func() {
2521+
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
2522+
Builder: defaultBuilderName,
2523+
Image: "example.com/some/repo:tag",
2524+
ReportDestinationDir: "a-destination-dir",
2525+
}))
2526+
h.AssertEq(t, fakeLifecycle.Opts.ReportDestinationDir, "a-destination-dir")
2527+
})
2528+
})
2529+
25192530
when("there are extensions", func() {
25202531
withExtensionsLabel = true
25212532

pkg/client/rebase.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package client
22

33
import (
44
"context"
5+
"os"
6+
"path/filepath"
57

8+
"github.com/BurntSushi/toml"
69
"github.com/buildpacks/lifecycle"
710
"github.com/buildpacks/lifecycle/platform"
811
"github.com/pkg/errors"
@@ -34,6 +37,9 @@ type RebaseOptions struct {
3437
// AdditionalMirrors gives us inputs to recalculate the 'best' run image
3538
// based on the registry we are publishing to.
3639
AdditionalMirrors map[string][]string
40+
41+
// If provided, directory to which report.toml will be copied
42+
ReportDestinationDir string
3743
}
3844

3945
// Rebase updates the run image layers in an app image.
@@ -80,7 +86,7 @@ func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error {
8086

8187
c.logger.Infof("Rebasing %s on run image %s", style.Symbol(appImage.Name()), style.Symbol(baseImage.Name()))
8288
rebaser := &lifecycle.Rebaser{Logger: c.logger, PlatformAPI: build.SupportedPlatformAPIVersions.Latest()}
83-
_, err = rebaser.Rebase(appImage, baseImage, nil)
89+
report, err := rebaser.Rebase(appImage, baseImage, nil)
8490
if err != nil {
8591
return err
8692
}
@@ -91,5 +97,21 @@ func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error {
9197
}
9298

9399
c.logger.Infof("Rebased Image: %s", style.Symbol(appImageIdentifier.String()))
100+
101+
if opts.ReportDestinationDir != "" {
102+
reportPath := filepath.Join(opts.ReportDestinationDir, "report.toml")
103+
reportFile, err := os.OpenFile(reportPath, os.O_RDWR|os.O_CREATE, 0644)
104+
if err != nil {
105+
c.logger.Warnf("unable to open %s for writing rebase report", reportPath)
106+
return err
107+
}
108+
109+
defer reportFile.Close()
110+
err = toml.NewEncoder(reportFile).Encode(report)
111+
if err != nil {
112+
c.logger.Warnf("unable to write rebase report to %s", reportPath)
113+
return err
114+
}
115+
}
94116
return nil
95117
}

pkg/client/rebase_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package client
33
import (
44
"bytes"
55
"context"
6+
"os"
7+
"path/filepath"
68
"testing"
79

810
"github.com/buildpacks/imgutil/fakes"
@@ -200,6 +202,18 @@ func testRebase(t *testing.T, when spec.G, it spec.S) {
200202
})
201203
})
202204

205+
when("report directory is set", func() {
206+
it("writes the report", func() {
207+
tmpdir := t.TempDir()
208+
h.AssertNil(t, subject.Rebase(context.TODO(), RebaseOptions{
209+
RepoName: "some/app",
210+
ReportDestinationDir: tmpdir,
211+
}))
212+
_, err := os.Stat(filepath.Join(tmpdir, "report.toml"))
213+
h.AssertNil(t, err)
214+
})
215+
})
216+
203217
when("is true", func() {
204218
it.Before(func() {
205219
fakeImageFetcher.RemoteImages["some/app"] = fakeAppImage

0 commit comments

Comments
 (0)