Ryan Cragun 025a6d5071
[VAULT-34829] pipeline(backport): add github create backport command (#30713)
Add a new `github create backport` sub-command that can create a
backport of a given pull request. The command has been designed around a
Github Actions workflow where it is triggered on a closed pull request
event with a guard that checks for merges:

```yaml
pull_request_target:
  types: closed

jobs:
  backport:
    if: github.even.pull_request.merged
    runs-on: "..."
```

Eventually this sub-command (or another similar one) can be used to
implemente backporting a CE pull request to the corresponding ce/*
branch in vault-enterprise. This functionality will be implemented in
VAULT-34827.

This backport runner has several new behaviors not present in the
existing backport assistant:
  - If the source PR was made against an enterprise branch we'll assume
    that we want create a CE backport.
  - Enterprise only files will be automatically _removed_ from the CE
    backport for you. This will not guarantee a working CE pull request
    but does quite a bit of the heavy lifting for you.
  - If the change only contains enterprise files we'll skip creating a
    CE backport.
  - If the corresponding CE branch is inactive (as defined in
    .release/versions.hcl) then we will skip creating a backport in most
    cases. The exceptions are changes that include docs, README, or
    pipeline changes as we assume that even active branches will want
    those changes.
  - Backport labels still work but _only_ to enterprise PR's. It is
    assumed that when the subsequent PRs are merged that their
    corresponding CE backports will be created.
  - Backport labels no longer include editions. They will now use the
    same schema as active versions defined .release/verions.hcl. E.g.
    `backport/1.19.x`. `main` is always assumed to be active.
  - The runner will always try and update the source PR with a Github
    comment regarding the status of each individual backport. Even if
    one attempt at backporting fails we'll continue until we've
    attempted all backports.

Signed-off-by: Ryan Cragun <me@ryan.ec>
2025-05-23 14:02:24 -06:00

76 lines
1.7 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package cmd
import (
"fmt"
"log/slog"
"os"
"github.com/spf13/cobra"
slogctx "github.com/veqryn/slog-context"
)
type rootCmdCfg struct {
logLevel string
format string
}
var rootCfg = &rootCmdCfg{}
func newRootCmd() *cobra.Command {
rootCmd := &cobra.Command{
Use: "pipeline",
Short: "Execute pipeline tasks",
Long: "Pipeline automation tasks",
}
rootCmd.PersistentFlags().StringVar(&rootCfg.logLevel, "log", "warn", "Set the log level. One of 'debug', 'info', 'warn', 'error'")
rootCmd.PersistentFlags().StringVarP(&rootCfg.format, "format", "f", "table", "The output format. Can be 'json' or 'table'")
rootCmd.AddCommand(newGenerateCmd())
rootCmd.AddCommand(newGithubCmd())
rootCmd.AddCommand(newReleasesCmd())
rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
var ll slog.Level
switch rootCfg.logLevel {
case "debug":
ll = slog.LevelDebug
case "info":
ll = slog.LevelInfo
case "warn":
ll = slog.LevelWarn
case "error":
ll = slog.LevelError
default:
return fmt.Errorf("unsupported log level: %s", rootCfg.logLevel)
}
h := slogctx.NewHandler(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: ll}), nil)
slog.SetDefault(slog.New(h))
switch rootCfg.format {
case "json", "table":
default:
return fmt.Errorf("unsupported format: %s", rootCfg.format)
}
return nil
}
return rootCmd
}
// Execute executes the root pipeline command.
func Execute() {
cobra.EnableTraverseRunHooks = true // Automatically chain run hooks
rootCmd := newRootCmd()
rootCmd.SilenceErrors = true // We handle this below
if err := rootCmd.Execute(); err != nil {
slog.Default().Error(err.Error())
os.Exit(1)
}
}