Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ ut/
*.tar

# Logs
*.log
*.log
2 changes: 2 additions & 0 deletions hack/release/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Release summary output
_output
10 changes: 5 additions & 5 deletions hack/release/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ var branchCutCommand = &cli.Command{
localFlag,
gitRemoteFlag,
},
Before: branchCutBefore,
Action: middleware.WithLogging(middleware.WithSummary("branch-cut", func(ctx context.Context, c *cli.Command) (string, map[string]any, error) {
Before: middleware.WithLogging(branchCutBefore),
Action: middleware.WithSummary("branch-cut", func(ctx context.Context, c *cli.Command) (string, map[string]any, error) {
stream := c.String(streamFlag.Name)
outputs, err := branchCutAction(ctx, c)
return stream, outputs, err
})),
}),
After: branchCutAfter,
}

Expand Down Expand Up @@ -463,8 +463,8 @@ var branchValidateCommand = &cli.Command{
},
githubTokenFlag,
},
Before: branchValidateBefore,
Action: middleware.WithLogging(middleware.WithSummary("branch-validate", branchValidateAction)),
Before: middleware.WithLogging(branchValidateBefore),
Action: middleware.WithSummary("branch-validate", branchValidateAction),
}

var branchValidateBefore = cli.BeforeFunc(func(ctx context.Context, c *cli.Command) (context.Context, error) {
Expand Down
24 changes: 11 additions & 13 deletions hack/release/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ var buildCommand = &cli.Command{
versionCheckFlag,
extensionTimeoutFlag,
},
Before: buildBefore,
Action: buildAction,
Before: middleware.WithLogging(buildBefore),
Action: middleware.WithSummary("release-build", buildAction),
After: buildAfter,
}

Expand All @@ -85,8 +85,6 @@ var buildCleanupFns []func(ctx context.Context) error

// Pre-action for release build command.
var buildBefore = cli.BeforeFunc(func(ctx context.Context, c *cli.Command) (context.Context, error) {
middleware.ConfigureLogging(c)

// Start with a clean slate for build cleanup functions.
buildCleanupFns = nil

Expand Down Expand Up @@ -183,13 +181,13 @@ var buildBefore = cli.BeforeFunc(func(ctx context.Context, c *cli.Command) (cont
})

// Action for release build command.
var buildAction = cli.ActionFunc(func(ctx context.Context, c *cli.Command) error {
var buildAction = func(ctx context.Context, c *cli.Command) (string, map[string]any, error) {
version := c.String(versionFlag.Name)
repoRootDir, err := command.GitDir()
if err != nil {
return fmt.Errorf("getting git directory: %w", err)
return version, nil, fmt.Errorf("getting git directory: %w", err)
}

version := c.String(versionFlag.Name)
buildLog := logrus.WithField("version", version)

// For hashrelease builds, skip if image is already published.
Expand All @@ -198,7 +196,7 @@ var buildAction = cli.ActionFunc(func(ctx context.Context, c *cli.Command) error
buildLog.WithError(err).Warn("Failed to check if image is already published, proceeding with build")
} else if published {
buildLog.Warn("Image is already published, skipping build")
return nil
return version, nil, nil
}
}

Expand Down Expand Up @@ -231,7 +229,7 @@ var buildAction = cli.ActionFunc(func(ctx context.Context, c *cli.Command) error
return nil
})
if err := setupHashreleaseBuild(ctx, c, repoRootDir); err != nil {
return fmt.Errorf("preparing hashrelease build environment: %w", err)
return version, nil, fmt.Errorf("preparing hashrelease build environment: %w", err)
}
} else {
buildLog = buildLog.WithField("release", true)
Expand All @@ -242,14 +240,14 @@ var buildAction = cli.ActionFunc(func(ctx context.Context, c *cli.Command) error
buildLog.Info("Building Operator")
if out, err := command.MakeInDir(repoRootDir, "release-build", buildEnv...); err != nil {
buildLog.Error(out)
return fmt.Errorf("building Operator: %w", err)
return version, nil, fmt.Errorf("building Operator: %w", err)
}
if err := assertOperatorImageVersion(registry, image, version); err != nil {
return fmt.Errorf("asserting operator image version: %w", err)
return version, nil, fmt.Errorf("asserting operator image version: %w", err)
}
listImages(registry, image, version)
return nil
})
return version, nil, nil
}

// runBuildCleanup runs all registered cleanup functions in reverse order (LIFO),
// logging each failure individually. It returns the joined errors and resets the slice.
Expand Down
4 changes: 1 addition & 3 deletions hack/release/from.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,12 @@ var releaseFromCommand = &cli.Command{
devTagSuffixFlag,
skipValidationFlag,
},
Before: releaseFromBefore,
Before: middleware.WithLogging(releaseFromBefore),
Action: releaseFromAction,
}

// Pre-action for "release from" command.
var releaseFromBefore = cli.BeforeFunc(func(ctx context.Context, c *cli.Command) (context.Context, error) {
middleware.ConfigureLogging(c)

if c.Bool(skipValidationFlag.Name) {
logrus.Warnf("Skipping %s validation as requested.", c.Name)
return ctx, nil
Expand Down
8 changes: 4 additions & 4 deletions hack/release/internal/middleware/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ func ConfigureLogging(c *cli.Command) {
logrus.AddHook(rotateFileHook)
}

// WithLogging wraps a cli.ActionFunc with automatic log file configuration
// WithLogging wraps a cli.BeforeFunc with automatic log file configuration
// derived from the command's full name (e.g. "release branch" -> "release-branch.log").
func WithLogging(action cli.ActionFunc) cli.ActionFunc {
return func(ctx context.Context, c *cli.Command) error {
func WithLogging(before cli.BeforeFunc) cli.BeforeFunc {
return func(ctx context.Context, c *cli.Command) (context.Context, error) {
ConfigureLogging(c)
return action(ctx, c)
return before(ctx, c)
}
}
29 changes: 19 additions & 10 deletions hack/release/internal/middleware/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import (
const ReleaseDir = "hack/release"

// StepSummary represents structured output for a release step.
// Written to <repoRoot>/hack/release/_output/summary/<version>/<step>.yaml.
// Written to <repoRoot>/hack/release/_output/summary/<key>/<step>.yaml,
// where <key> is a release version (e.g. v1.36.0) for release-* steps
// or a stream identifier (e.g. v1.36) for branch-* steps.
type StepSummary struct {
Status string `yaml:"status"`
Started time.Time `yaml:"started"`
Expand All @@ -44,9 +46,10 @@ func SummaryOutputDir(repoRootDir string) string {
return filepath.Join(repoRootDir, ReleaseDir, "_output")
}

// WriteSummary writes a summary YAML file to <baseDir>/summary/<version>/<step>.yaml.
func WriteSummary(baseDir, version, step string, s StepSummary) error {
dir := filepath.Join(baseDir, "summary", version)
// WriteSummary writes a summary YAML file to <baseDir>/summary/<key>/<step>.yaml.
// key is a release version or stream identifier; step is the step name.
func WriteSummary(baseDir, key, step string, s StepSummary) error {
dir := filepath.Join(baseDir, "summary", key)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("creating output dir: %w", err)
}
Expand All @@ -57,36 +60,42 @@ func WriteSummary(baseDir, version, step string, s StepSummary) error {
return os.WriteFile(filepath.Join(dir, step+".yaml"), data, 0o644)
}

// SummaryAction is a command action that returns a version string,
// SummaryAction is a command action that returns a key (version or stream),
// structured outputs, and an error.
type SummaryAction func(context.Context, *cli.Command) (string, map[string]any, error)

// WithSummary wraps a SummaryAction with timing, status, and summary file emission.
func WithSummary(step string, action SummaryAction) cli.ActionFunc {
return withSummary(step, action, command.GitDir)
}

// withSummary is the testable core of WithSummary, parameterized over the
// repo-root resolver so tests can inject a temp dir.
func withSummary(step string, action SummaryAction, repoRootFn func() (string, error)) cli.ActionFunc {
return func(ctx context.Context, c *cli.Command) error {
Comment thread
radTuti marked this conversation as resolved.
started := time.Now()
ver, outputsMap, actionErr := action(ctx, c)
key, outputsMap, actionErr := action(ctx, c)

status := "success"
if actionErr != nil {
status = "failure"
}
if ver == "" {
ver = "unknown"
if key == "" {
key = "unknown"
}
summary := StepSummary{
Status: status,
Started: started,
Completed: time.Now(),
Outputs: outputsMap,
}
repoRoot, err := command.GitDir()
repoRoot, err := repoRootFn()
if err != nil {
logrus.WithError(err).Warn("Failed to determine repo root for summary")
return actionErr
}
outputDir := SummaryOutputDir(repoRoot)
if err := WriteSummary(outputDir, ver, step, summary); err != nil {
if err := WriteSummary(outputDir, key, step, summary); err != nil {
logrus.WithError(err).Warn("Failed to write summary file")
}
Comment thread
radTuti marked this conversation as resolved.
return actionErr
Expand Down
Loading
Loading