vault/tools/pipeline/internal/cmd/github.go
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

71 lines
1.8 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package cmd
import (
"errors"
"fmt"
"os"
"path/filepath"
gh "github.com/google/go-github/v68/github"
"github.com/hashicorp/vault/tools/pipeline/internal/pkg/git"
"github.com/spf13/cobra"
)
type githubCommandState struct {
Github *gh.Client
Git *git.Client
}
var githubCmdState = &githubCommandState{
Github: gh.NewClient(nil),
Git: git.NewClient(git.WithLoadTokenFromEnv()),
}
func newGithubCmd() *cobra.Command {
github := &cobra.Command{
Use: "github",
Short: "Github commands",
Long: "Github commands",
}
github.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if token, set := os.LookupEnv("GITHUB_TOKEN"); set {
githubCmdState.Github = githubCmdState.Github.WithAuthToken(token)
} else {
fmt.Println("\x1b[1;33;49mWARNING\x1b[0m: GITHUB_TOKEN has not been set. While not always required for read actions on public repositories you're likely to get throttled without it")
}
return nil
}
github.AddCommand(newGithubCreateCmd())
github.AddCommand(newGithubListCmd())
return github
}
func writeToGithubOutput(key string, bytes []byte) error {
devPath, ok := os.LookupEnv("GITHUB_OUTPUT")
if !ok {
return errors.New("$GITHUB_OUTPUT has not been set. Cannot write changed files to it")
}
expanded, err := filepath.Abs(devPath)
if err != nil {
return fmt.Errorf("failed to expand $GITHUB_OUTPUT path: %w", err)
}
dev, err := os.OpenFile(expanded, os.O_APPEND|os.O_WRONLY, 0o644)
if err != nil {
return fmt.Errorf("failed to open $GITHUB_OUTPUT for writing: %w", err)
}
defer func() { _ = dev.Close() }()
_, err = dev.Write(append([]byte(key+"="), bytes...))
if err != nil {
return fmt.Errorf("failed to write key %s to $GITHUB_OUTPUT: %w", key, err)
}
return nil
}