Skip to content

Commit

Permalink
feat: assignable downstream commits
Browse files Browse the repository at this point in the history
  • Loading branch information
GavinPJK committed Jan 15, 2025
1 parent 6a8818a commit ed59744
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 1 deletion.
6 changes: 6 additions & 0 deletions pkg/apis/updatebot/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ type Rule struct {
// SparseCheckout governs if sparse checkout is made of repository. Only possible with regex and go changes.
// Note: Not all git servers support this.
SparseCheckout bool `json:"sparseCheckout,omitempty"`

// PullRequestAssignees
PullRequestAssignees []string `json:"pullRequestAssignees,omitempty"`

// AssignAuthorToPullRequests governs if downstream pull requests are automatically assigned to the upstream author
AssignAuthorToPullRequests bool `json:"assignAuthorToPullRequests,omitempty"`
}

// Change the kind of change to make on a repository
Expand Down
47 changes: 47 additions & 0 deletions pkg/cmd/pr/pr.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pr

import (
"context"
"fmt"
"os"
"path/filepath"
Expand All @@ -14,6 +15,7 @@ import (

"github.com/jenkins-x-plugins/jx-promote/pkg/environments"
"github.com/jenkins-x-plugins/jx-updatebot/pkg/apis/updatebot/v1alpha1"
"github.com/jenkins-x/go-scm/scm"
"github.com/jenkins-x/jx-helpers/v3/pkg/cobras/helper"
"github.com/jenkins-x/jx-helpers/v3/pkg/cobras/templates"
"github.com/jenkins-x/jx-helpers/v3/pkg/files"
Expand Down Expand Up @@ -46,9 +48,11 @@ type Options struct {
AddChangelog string
GitCommitUsername string
GitCommitUserEmail string
PipelineCommitSha string
AutoMerge bool
NoVersion bool
GitCredentials bool
PRAssignees []string
Labels []string
TemplateData map[string]interface{}
PullRequestSHAs map[string]string
Expand Down Expand Up @@ -81,7 +85,9 @@ func NewCmdPullRequest() (*cobra.Command, *Options) {
cmd.Flags().StringVar(&o.CommitMessage, "pull-request-body", "", "the PR body")
cmd.Flags().StringVarP(&o.GitCommitUsername, "git-user-name", "", "", "the user name to git commit")
cmd.Flags().StringVarP(&o.GitCommitUserEmail, "git-user-email", "", "", "the user email to git commit")
cmd.Flags().StringVarP(&o.PipelineCommitSha, "pipeline-commit-sha", "", os.Getenv("PULL_BASE_SHA"), "the git SHA of the commit that triggered the pipeline")
cmd.Flags().StringSliceVar(&o.Labels, "labels", []string{}, "a list of labels to apply to the PR")
cmd.Flags().StringSliceVar(&o.PRAssignees, "pull-request-assign", []string{}, "Assignees of created PRs")
cmd.Flags().BoolVarP(&o.AutoMerge, "auto-merge", "", true, "should we automatically merge if the PR pipeline is green")
cmd.Flags().BoolVarP(&o.NoVersion, "no-version", "", false, "disables validation on requiring a '--version' option or environment variable to be required")
cmd.Flags().BoolVarP(&o.GitCredentials, "git-credentials", "", false, "ensures the git credentials are setup so we can push to git")
Expand Down Expand Up @@ -129,6 +135,10 @@ func (o *Options) Run() error {
if err != nil {
return fmt.Errorf("failed to create Pull Requests: %w", err)
}
err = o.AssignUsersToPullRequests(rule, pullRequests, gitURL)
if err != nil {
return fmt.Errorf("failed to set assignees: %w", err)
}
}
return nil
}
Expand Down Expand Up @@ -317,6 +327,43 @@ func (o *Options) SetChangeLog(addChangeLog string) error {
return nil
}

// FindCommitAuthor finds the commit author for the given SHA
func (o *Options) FindCommitAuthor(gitURL string, sha string) (string, error) {
ctx := context.Background()
scmClient, repoFullName, err := o.GetScmClient(gitURL, o.GitKind)
if err != nil {
return "", fmt.Errorf("failed to create ScmClient: %w", err)
}
commit, _, err := scmClient.Git.FindCommit(ctx, repoFullName, sha)
if err != nil {
return "", fmt.Errorf("failed to find commit %s: %w", sha, err)
}

author := commit.Author.Login
if author == "" {
return "", fmt.Errorf("no user found for author of commit %s", sha)
}

return author, nil
}

// AssignUsersToCommit adds users as an assignee to the PR Issue
func (o *Options) AssignUsersToCommit(pr *scm.PullRequest, users []string, gitURL string) error {
ctx := context.Background()
scmClient, repoFullName, err := o.GetScmClient(gitURL, o.GitKind)
if err != nil {
return fmt.Errorf("failed to create ScmClient: %w", err)
}
fmt.Printf("Debug: Successfully created ScmClient. repoFullName=%s\n", repoFullName)

fmt.Printf("Debug: Assigning users=%v to PR=%d...\n", users, pr.Number)
_, err = scmClient.PullRequests.AssignIssue(ctx, repoFullName, pr.Number, users)
if err != nil {
return fmt.Errorf("failed to assign user to PR %d: %w", pr.Number, err)
}
return nil
}

// SetCommitDetails discovers the git URL, and sets the application name, commit message and title
func (o *Options) SetCommitDetails(dir, commitMessage, commitTitle, application string) error {
if commitMessage == "" || commitTitle == "" || application == "" {
Expand Down
71 changes: 70 additions & 1 deletion pkg/cmd/pr/pr_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pr_test

import (
"github.com/jenkins-x/go-scm/scm"
"os"
"path/filepath"
"strings"
Expand All @@ -20,7 +21,7 @@ import (
func TestCreate(t *testing.T) {
ev := os.Getenv("JX_EXCLUDE_TEST")
if ev == "" {
ev = "go"
ev = "go,assignauthor"
}
excludeTests := strings.Split(ev, ",")
runner := &fakerunner.FakeRunner{
Expand Down Expand Up @@ -85,3 +86,71 @@ func TestCreate(t *testing.T) {

}
}

func TestAssignAuthorToCommit(t *testing.T) {
fileNames, err := os.ReadDir("test_data")
assert.NoError(t, err)

for _, f := range fileNames {
if !f.IsDir() || f.Name() != "assignauthor" {
continue
}

t.Logf("Running test for %s\n", f.Name())

dir := filepath.Join("test_data", f.Name())
fakeScmClient, fakeData := fake.NewDefault()

// Prepopulate fake data
fakeData.Commits["dummy-sha"] = &scm.Commit{
Sha: "dummy-sha",
Author: scm.Signature{
Login: "test-author",
},
}
fakeData.PullRequests[1] = &scm.PullRequest{
Number: 1,
Title: "Test PR",
}

fakeData.AssigneesAdded = []string{}

runner := &fakerunner.FakeRunner{
CommandRunner: func(c *cmdrunner.Command) (string, error) {
if c.Name == "git" && len(c.Args) > 0 && c.Args[0] == "push" {
t.Logf("faking command %s in dir %s\n", c.CLI(), c.Dir)
return "", nil
}
return cmdrunner.DefaultCommandRunner(c)
},
}

// Configure the Options object
_, o := pr.NewCmdPullRequest()
o.Dir = dir
o.CommandRunner = runner.Run
o.ScmClient = fakeScmClient
o.ScmClientFactory.ScmClient = fakeScmClient
o.ScmClientFactory.NoWriteGitCredentialsFile = true
o.Version = "1.2.3"
o.PipelineCommitSha = "dummy-sha"
o.EnvironmentPullRequestOptions.ScmClientFactory.GitServerURL = "https://github.com"
o.EnvironmentPullRequestOptions.ScmClientFactory.GitToken = "dummytoken"
o.EnvironmentPullRequestOptions.ScmClientFactory.GitUsername = "dummyuser"

// Run the command
err = o.Run()
require.NoError(t, err, "failed to run command for test %s", f.Name())

// Validate the assignments
expectedAssignees := []string{"foo", "bar", "test-author"}
actualAssignees := []string{}
for _, assignee := range fakeData.AssigneesAdded {
parts := strings.Split(assignee, ":")
actualAssignees = append(actualAssignees, parts[1])
}

assert.ElementsMatch(t, expectedAssignees, actualAssignees, "PR should include all specified assignees")
t.Logf("PR created successfully with assignees: %v\n", actualAssignees)
}
}
19 changes: 19 additions & 0 deletions pkg/cmd/pr/test_data/assignauthor/.jx/updatebot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: updatebot.jenkins-x.io/v1alpha1
kind: UpdateConfig
spec:
rules:
- urls:
- https://github.com/jx3-gitops-repositories/jx3-kubernetes
changes:
- command:
name: sh
args:
- -c
- "echo $CHEESE > cheese.txt"
env:
- name: CHEESE
value: Edam
pullRequestAssignees:
- foo
- bar
assignAuthorToPullRequests: true

0 comments on commit ed59744

Please sign in to comment.