Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update batching #53

Merged
merged 4 commits into from
Sep 26, 2020
Merged
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
This action checks for available dependency updates to a go project, and opens individual pull requests proposing each available update.

* Ignores dependencies not released with semver
* Ignores dependencies if the initial PR is closed
* Go module major version updates (e.g. `github.com/foo/bar/v2`)
* Vendoring detection and support
* Can multiple multiple base branches
* Update batching

Suggested triggers: `schedule`, `workflow_dispatch`.

Expand Down
35 changes: 22 additions & 13 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,28 @@ inputs:
log_level:
description: 'Control debug/info/warn/error output'
required: false
batches:
description: >
Configuration for grouping updates together, newline separated following format:
label:prefix1,prefix2
e.g.
internal:github.com/thepwagner/
aws:github.com/aws
required: false
runs:
using: "composite"
steps:
- name: Verify Go SDK
run: which go || echo "Go required, please use actions/setup-go before me"
shell: bash
- name: Compile action-update-go
run: cd "${{github.action_path}}" && go build -o ./action-update-go .
shell: bash
- name: Run action-update-go
run: pwd && "${{github.action_path}}/action-update-go"
shell: bash
env:
INPUT_BRANCHES: ${{ inputs.branches }}
INPUT_TOKEN: ${{ inputs.token }}
INPUT_LOG_LEVEL: ${{ inputs.log_level }}
- name: Verify Go SDK
run: which go || echo "Go required, please use actions/setup-go before me"
shell: bash
- name: Compile action-update-go
run: cd "${{github.action_path}}" && go build -o ./action-update-go .
shell: bash
- name: Run action-update-go
run: pwd && "${{github.action_path}}/action-update-go"
shell: bash
env:
INPUT_BRANCHES: ${{ inputs.branches }}
INPUT_BATCHES: ${{ inputs.batches }}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This took ~10 minutes of WTF to rediscover. The slow kind where you have to push + trigger a workflow each iteration, and everything "just works" outside of Actions.

Tracked in actions/runner#665

INPUT_TOKEN: ${{ inputs.token }}
INPUT_LOG_LEVEL: ${{ inputs.log_level }}
24 changes: 24 additions & 0 deletions cmd/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
"github.com/caarlos0/env/v5"
"github.com/google/go-github/v32/github"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
)

type Environment struct {
GitHubEventName string `env:"GITHUB_EVENT_NAME"`
GitHubEventPath string `env:"GITHUB_EVENT_PATH"`
GitHubRepository string `env:"GITHUB_REPOSITORY"`

InputBatches string `env:"INPUT_BATCHES"`
InputBranches string `env:"INPUT_BRANCHES"`
GitHubToken string `env:"INPUT_TOKEN"`
InputLogLevel string `env:"INPUT_LOG_LEVEL" envDefault:"debug"`
Expand Down Expand Up @@ -56,6 +58,28 @@ func (e *Environment) Branches() (branches []string) {
return
}

func (e *Environment) Batches() (map[string][]string, error) {
raw := map[string]interface{}{}
if err := yaml.Unmarshal([]byte(e.InputBatches), &raw); err != nil {
return nil, fmt.Errorf("decoding batches yaml: %w", err)
}

m := make(map[string][]string, len(raw))
for key, value := range raw {
var prefixes []string
switch v := value.(type) {
case []interface{}:
for _, s := range v {
prefixes = append(prefixes, fmt.Sprintf("%v", s))
}
case string:
prefixes = append(prefixes, v)
}
m[key] = prefixes
}
return m, nil
}

func (e *Environment) LogLevel() logrus.Level {
if e.InputLogLevel == "" {
return logrus.InfoLevel
Expand Down
41 changes: 41 additions & 0 deletions cmd/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestEnvironment_LogLevel(t *testing.T) {
Expand All @@ -22,3 +23,43 @@ func TestEnvironment_LogLevel(t *testing.T) {
})
}
}

func TestEnvironment_Batches(t *testing.T) {
cases := []struct {
input string
batches map[string][]string
}{
{
input: `foo: [bar, baz]`,
batches: map[string][]string{"foo": {"bar", "baz"}},
},
{
input: `---
foo: bar
foz: baz`,
batches: map[string][]string{
"foo": {"bar"},
"foz": {"baz"},
},
},
{
input: `foo:
- bar
- baz`,
batches: map[string][]string{
"foo": {"bar", "baz"},
},
},
{
input: "",
batches: map[string][]string{},
},
}

for _, tc := range cases {
e := Environment{InputBatches: tc.input}
b, err := e.Batches()
require.NoError(t, err)
assert.Equal(t, tc.batches, b)
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require (
github.com/stretchr/testify v1.6.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/yaml.v2 v2.3.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
)

replace github.com/containerd/containerd => github.com/containerd/containerd v1.4.0
Expand Down
4 changes: 2 additions & 2 deletions handler/pullrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ func PullRequest(ctx context.Context, env *cmd.Environment, evt interface{}) err
}

func prReopened(ctx context.Context, env *cmd.Environment, pr *github.PullRequestEvent) error {
repo, updater, err := getRepoUpdater(env)
_, updater, err := getRepoUpdater(env)
if err != nil {
return err
}

prRef := pr.GetPullRequest().GetHead().GetRef()
logrus.WithField("ref", prRef).Info("PR reopened, recreating update")

base, update := repo.Parse(prRef)
base, update := updater.Parse(prRef)
if update == nil {
logrus.Info("not an update PR")
return nil
Expand Down
7 changes: 6 additions & 1 deletion handler/schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package handler

import (
"context"
"fmt"

"github.com/go-git/go-git/v5"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -62,6 +63,10 @@ func getRepoUpdater(env *cmd.Environment) (updater.Repo, *updater.RepoUpdater, e
}

gomodUpdater := gomod.NewUpdater(modRepo.Root())
repoUpdater := updater.NewRepoUpdater(modRepo, gomodUpdater)
batches, err := env.Batches()
if err != nil {
return nil, nil, fmt.Errorf("parsing batches")
}
repoUpdater := updater.NewRepoUpdater(modRepo, gomodUpdater, updater.WithBatches(batches))
return gitRepo, repoUpdater, nil
}
46 changes: 9 additions & 37 deletions repo/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ type GitRepo struct {
branch string
author GitIdentity
remotes bool

branchNamer UpdateBranchNamer
}

var _ updater.Repo = (*GitRepo)(nil)
Expand Down Expand Up @@ -67,12 +65,11 @@ func NewGitRepo(repo *git.Repository) (*GitRepo, error) {
branch = head.Name().Short()
}
return &GitRepo{
repo: repo,
wt: wt,
branch: branch,
remotes: len(remotes) > 0,
author: DefaultGitIdentity,
branchNamer: DefaultUpdateBranchNamer{},
repo: repo,
wt: wt,
branch: branch,
remotes: len(remotes) > 0,
author: DefaultGitIdentity,
}, nil
}

Expand Down Expand Up @@ -122,22 +119,21 @@ func (t *GitRepo) setBranch(refName plumbing.ReferenceName) error {
return nil
}

func (t *GitRepo) NewBranch(baseBranch string, update updater.Update) error {
branch := t.branchNamer.Format(baseBranch, update)
func (t *GitRepo) NewBranch(base, branch string) error {
log := logrus.WithFields(logrus.Fields{
"base": baseBranch,
"base": base,
"branch": branch,
})
log.Debug("creating branch")

// Map string to a ref:
baseRef, err := t.repo.Reference(plumbing.NewBranchReferenceName(baseBranch), true)
baseRef, err := t.repo.Reference(plumbing.NewBranchReferenceName(base), true)
if err != nil {
if err != plumbing.ErrReferenceNotFound {
return fmt.Errorf("querying branch ref: %w", err)
}
log.Debug("not found locally, checking remote")
remoteRef, err := t.repo.Reference(plumbing.NewRemoteReferenceName(RemoteName, baseBranch), true)
remoteRef, err := t.repo.Reference(plumbing.NewRemoteReferenceName(RemoteName, base), true)
if err != nil {
return fmt.Errorf("querying remote branch ref: %w", err)
}
Expand Down Expand Up @@ -238,27 +234,3 @@ func (t *GitRepo) push(ctx context.Context) error {
logrus.Debug("pushed to remote")
return nil
}

func (t *GitRepo) Updates(_ context.Context) (updater.UpdatesByBranch, error) {
branches, err := t.repo.Branches()
if err != nil {
return nil, fmt.Errorf("iterating branches: %w", err)
}
defer branches.Close()

ret := updater.UpdatesByBranch{}
addToIndex := func(ref *plumbing.Reference) error {
if base, update := t.branchNamer.Parse(ref.Name().Short()); update != nil {
ret.AddOpen(base, *update)
}
return nil
}
if err := branches.ForEach(addToIndex); err != nil {
return nil, fmt.Errorf("indexing branches: %w", err)
}
return ret, nil
}

func (t *GitRepo) Parse(b string) (string, *updater.Update) {
return t.branchNamer.Parse(b)
}
16 changes: 5 additions & 11 deletions repo/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@ const (
updateBranch = "action-update-go/main/github.com/foo/bar/v1.0.0"
)

var (
fileData = []byte{1, 2, 3, 4}
fakeUpdate = updater.Update{
Path: "github.com/foo/bar",
Next: "v1.0.0",
}
)
var fileData = []byte{1, 2, 3, 4}

func TestNewGitRepo(t *testing.T) {
gr := initGitRepo(t, plumbing.NewBranchReferenceName(branchName))
Expand Down Expand Up @@ -79,21 +73,21 @@ func TestGitRepo_SetBranch_NotFound(t *testing.T) {

func TestGitRepo_NewBranch(t *testing.T) {
gr := initGitRepo(t, plumbing.NewBranchReferenceName(branchName))
err := gr.NewBranch(branchName, fakeUpdate)
err := gr.NewBranch(branchName, updateBranch)
assert.NoError(t, err)
assert.Equal(t, updateBranch, gr.Branch())
}

func TestGitRepo_NewBranch_FromRemote(t *testing.T) {
gr := initGitRepo(t, plumbing.NewRemoteReferenceName(repo.RemoteName, branchName))
err := gr.NewBranch(branchName, fakeUpdate)
err := gr.NewBranch(branchName, updateBranch)
assert.NoError(t, err)
assert.Equal(t, updateBranch, gr.Branch())
}

func TestGitRepo_Push(t *testing.T) {
gr := initGitRepo(t, plumbing.NewRemoteReferenceName(repo.RemoteName, branchName))
err := gr.NewBranch(branchName, fakeUpdate)
err := gr.NewBranch(branchName, updateBranch)
require.NoError(t, err)
tmpFile := addTempFile(t, gr)

Expand Down Expand Up @@ -144,7 +138,7 @@ func TestGitRepo_Push_WithRemote(t *testing.T) {

gr, err := repo.NewGitRepo(downstream)
require.NoError(t, err)
err = gr.NewBranch(branchName, fakeUpdate)
err = gr.NewBranch(branchName, updateBranch)
require.NoError(t, err)
addTempFile(t, gr)

Expand Down
Loading