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

feat: Including Regular Expression filter when targeting Github Repositories #426

Merged
merged 26 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fd70c8f
Including Regular Expression checker when using Repository Search
josealdaco Oct 25, 2023
a87dec1
Removing unused comments
josealdaco Oct 25, 2023
5f08f6d
Including unit test
josealdaco Oct 25, 2023
e5b99af
organizing imports
josealdaco Oct 25, 2023
ebacb0a
Utilizing --repo-exclude to exclude certain repositories
josealdaco Oct 25, 2023
797f1ad
Removing unused comments
josealdaco Oct 25, 2023
3d3d49d
Removing extra comment
josealdaco Oct 25, 2023
72f8013
Refactor based on PR feedback
josealdaco Oct 27, 2023
970b04c
Merging current master of upstream branch
josealdaco Oct 27, 2023
b2ea5dd
Minor id change on RepoFilter test
josealdaco Oct 27, 2023
7583267
Adding nil statement in case a regularexpression was not used
josealdaco Oct 27, 2023
5909e8a
fix package import structure
josealdaco Oct 27, 2023
b5e70ed
feat: Modified repo-filter to repo-include and repo-exclude
josealdaco Oct 30, 2023
7d8d524
Using regex.Compile to raise regEx validation errors instead of panic
josealdaco Nov 6, 2023
ddf13b9
Merge branch 'master' of github.com:lindell/multi-gitter into regex_t…
josealdaco Nov 6, 2023
c2f8834
Minor syntax changes from golangci
josealdaco Nov 6, 2023
57fc008
Moving regex filtering away from github scm
josealdaco Nov 7, 2023
d1082cb
reverting sort duplication change
josealdaco Nov 7, 2023
a452b40
removing changes to .github.go file
josealdaco Nov 7, 2023
be71b2e
Including unit test for feature
josealdaco Nov 7, 2023
d368cc2
including more tests for regex & wrapping errors
josealdaco Nov 8, 2023
696d388
chore: minor style fixes
josealdaco Nov 9, 2023
b41d462
chore: remove changes to platform file
josealdaco Nov 9, 2023
06c8ad8
fix:moving regex compiling
josealdaco Nov 9, 2023
b4ff2b2
fix:undo removing unrelated linebreaks
josealdaco Nov 9, 2023
9ec4191
Added newline between sections
lindell Nov 9, 2023
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
64 changes: 44 additions & 20 deletions cmd/cmd-run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ package cmd

import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"regexp"
"strings"
"syscall"

"github.com/lindell/multi-gitter/internal/git"

"github.com/lindell/multi-gitter/internal/multigitter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -62,6 +63,8 @@ Available values:
cmd.Flags().StringSliceP("labels", "", nil, "Labels to be added to any created pull request.")
cmd.Flags().StringP("author-name", "", "", "Name of the committer. If not set, the global git config setting will be used.")
cmd.Flags().StringP("author-email", "", "", "Email of the committer. If not set, the global git config setting will be used.")
cmd.Flags().StringP("repo-include", "", "", "Include repositories that match with a given Regular Expression")
cmd.Flags().StringP("repo-exclude", "", "", "Exclude repositories that match with a given Regular Expression")
configureGit(cmd)
configurePlatform(cmd)
configureRunPlatform(cmd, true)
Expand Down Expand Up @@ -98,6 +101,8 @@ func run(cmd *cobra.Command, _ []string) error {
assignees, _ := flag.GetStringSlice("assignees")
draft, _ := flag.GetBool("draft")
labels, _ := flag.GetStringSlice("labels")
repoInclude, _ := flag.GetString("repo-include")
repoExclude, _ := flag.GetString("repo-exclude")

if concurrent < 1 {
return errors.New("concurrent runs can't be less than one")
Expand Down Expand Up @@ -144,6 +149,23 @@ func run(cmd *cobra.Command, _ []string) error {
}
}

var regExIncludeRepository *regexp.Regexp
var regExExcludeRepository *regexp.Regexp
if repoInclude != "" {
repoIncludeFilterCompile, err := regexp.Compile(repoInclude)
if err != nil {
return errors.WithMessage(err, "could not parse repo-include")
}
regExIncludeRepository = repoIncludeFilterCompile
}
if repoExclude != "" {
repoExcludeFilterCompile, err := regexp.Compile(repoExclude)
if err != nil {
return errors.WithMessage(err, "could not parse repo-exclude")
}
regExExcludeRepository = repoExcludeFilterCompile
}

vc, err := getVersionController(flag, true, false)
if err != nil {
return err
Expand Down Expand Up @@ -185,25 +207,27 @@ func run(cmd *cobra.Command, _ []string) error {

VersionController: vc,

CommitMessage: commitMessage,
PullRequestTitle: prTitle,
PullRequestBody: prBody,
Reviewers: reviewers,
TeamReviewers: teamReviewers,
MaxReviewers: maxReviewers,
MaxTeamReviewers: maxTeamReviewers,
Interactive: interactive,
DryRun: dryRun,
Fork: forkMode,
ForkOwner: forkOwner,
SkipPullRequest: skipPullRequest,
SkipRepository: skipRepository,
CommitAuthor: commitAuthor,
BaseBranch: baseBranchName,
Assignees: assignees,
ConflictStrategy: conflictStrategy,
Draft: draft,
Labels: labels,
CommitMessage: commitMessage,
PullRequestTitle: prTitle,
PullRequestBody: prBody,
Reviewers: reviewers,
TeamReviewers: teamReviewers,
MaxReviewers: maxReviewers,
MaxTeamReviewers: maxTeamReviewers,
Interactive: interactive,
DryRun: dryRun,
RegExIncludeRepository: regExIncludeRepository,
RegExExcludeRepository: regExExcludeRepository,
Fork: forkMode,
ForkOwner: forkOwner,
SkipPullRequest: skipPullRequest,
SkipRepository: skipRepository,
CommitAuthor: commitAuthor,
BaseBranch: baseBranchName,
Assignees: assignees,
ConflictStrategy: conflictStrategy,
Draft: draft,
Labels: labels,

Concurrent: concurrent,

Expand Down
40 changes: 32 additions & 8 deletions internal/multigitter/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"os"
"os/exec"
"regexp"
"sync"
"syscall"

Expand Down Expand Up @@ -54,9 +55,11 @@ type Runner struct {
BaseBranch string // The base branch of the PR, use default branch if not set
Assignees []string

Concurrent int
SkipPullRequest bool // If set, the script will run directly on the base-branch without creating any PR
SkipRepository []string // A list of repositories that run will skip
Concurrent int
SkipPullRequest bool // If set, the script will run directly on the base-branch without creating any PR
SkipRepository []string // A list of repositories that run will skip
RegExIncludeRepository *regexp.Regexp
RegExExcludeRepository *regexp.Regexp

Fork bool // If set, create a fork and make the pull request from it
ForkOwner string // The owner of the new fork. If empty, the fork should happen on the logged in user
Expand Down Expand Up @@ -98,7 +101,7 @@ func (r *Runner) Run(ctx context.Context) error {
return errors.Wrap(err, "could not fetch repositories")
}

repos = filterRepositories(repos, r.SkipRepository)
repos = filterRepositories(repos, r.SkipRepository, r.RegExIncludeRepository, r.RegExExcludeRepository)

if len(repos) == 0 {
log.Infof("No repositories found. Please make sure the user of the token has the correct access to the repos you want to change.")
Expand Down Expand Up @@ -152,18 +155,39 @@ func (r *Runner) Run(ctx context.Context) error {
return nil
}

func filterRepositories(repos []scm.Repository, skipRepositoryNames []string) []scm.Repository {
// Determines if Repository should be excluded based on provided Regular Expression
func excludeRepositoryFilter(repoName string, regExp *regexp.Regexp) bool {
if regExp == nil {
return false
}
return regExp.MatchString(repoName)
}

// Determines if Repository should be included based on provided Regular Expression
func matchesRepositoryFilter(repoName string, regExp *regexp.Regexp) bool {
if regExp == nil {
return true
}
return regExp.MatchString(repoName)
}

func filterRepositories(repos []scm.Repository, skipRepositoryNames []string, regExIncludeRepository *regexp.Regexp,
regExExcludeRepository *regexp.Regexp) []scm.Repository {
skipReposMap := map[string]struct{}{}
for _, skipRepo := range skipRepositoryNames {
skipReposMap[skipRepo] = struct{}{}
}

filteredRepos := make([]scm.Repository, 0, len(repos))
for _, r := range repos {
if _, shouldSkip := skipReposMap[r.FullName()]; !shouldSkip {
josealdaco marked this conversation as resolved.
Show resolved Hide resolved
filteredRepos = append(filteredRepos, r)
if _, shouldSkip := skipReposMap[r.FullName()]; shouldSkip {
log.Infof("Skipping %s since it is in exclusion list", r.FullName())
} else if !matchesRepositoryFilter(r.FullName(), regExIncludeRepository) {
log.Infof("Skipping %s since it does not match the inclusion regexp", r.FullName())
} else if excludeRepositoryFilter(r.FullName(), regExExcludeRepository) {
log.Infof("Skipping %s since it match the exclusion regexp", r.FullName())
} else {
log.Infof("Skipping %s", r.FullName())
filteredRepos = append(filteredRepos, r)
}
}
return filteredRepos
Expand Down
102 changes: 102 additions & 0 deletions tests/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,108 @@ func TestTable(t *testing.T) {
assert.False(t, branchExist(t, vcMock.Repositories[0].Path, "custom-branch-name"))
},
},
{
lindell marked this conversation as resolved.
Show resolved Hide resolved
name: "repo-include regex repository filtering",
vcCreate: func(t *testing.T) *vcmock.VersionController {
return &vcmock.VersionController{
Repositories: []vcmock.Repository{
createRepo(t, "owner", "repo1", "i like apples"),
createRepo(t, "owner", "repo-2", "i like oranges"),
createRepo(t, "owner", "repo-change", "i like carrots"),
createRepo(t, "owner", "repo-3", "i like carrots"),
},
}
},
args: []string{
"run",
"--repo-search", "repo",
"--repo-include", "^owner/repo-",
"--commit-message", "chore: foo",
"--dry-run",
changerBinaryPath,
},
verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) {
require.Len(t, vcMock.PullRequests, 0)
assert.Contains(t, runData.logOut, "Running on 3 repositories")
},
},
{
name: "repo-exclude regex repository filtering",
vcCreate: func(t *testing.T) *vcmock.VersionController {
return &vcmock.VersionController{
Repositories: []vcmock.Repository{
createRepo(t, "owner", "repo1", "i like apples"),
createRepo(t, "owner", "repo-2", "i like oranges"),
createRepo(t, "owner", "repo-change", "i like carrots"),
createRepo(t, "owner", "repo-3", "i like carrots"),
},
}
},
args: []string{
"run",
"--repo-search", "repo",
"--repo-exclude", "\\d$",
"--commit-message", "chore: foo",
"--dry-run",
changerBinaryPath,
},
verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) {
require.Len(t, vcMock.PullRequests, 0)
assert.Contains(t, runData.logOut, "Running on 1 repositories")
},
},
{
name: "invalid repo-include regex repository filtering",
vcCreate: func(t *testing.T) *vcmock.VersionController {
return &vcmock.VersionController{
Repositories: []vcmock.Repository{
createRepo(t, "owner", "repo1", "i like apples"),
createRepo(t, "owner", "repo-2", "i like oranges"),
createRepo(t, "owner", "repo-change", "i like carrots"),
createRepo(t, "owner", "repo-3", "i like carrots"),
},
}
},
args: []string{
"run",
"--repo-search", "repo",
"--repo-include", "(abc[def$",
"--commit-message", "chore: foo",
"--dry-run",
changerBinaryPath,
},
verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) {
require.Len(t, vcMock.PullRequests, 0)
assert.Contains(t, runData.cmdOut, "could not parse repo-include")
},
expectErr: true,
},
{
name: "invalid repo-exclude regex repository filtering",
vcCreate: func(t *testing.T) *vcmock.VersionController {
return &vcmock.VersionController{
Repositories: []vcmock.Repository{
createRepo(t, "owner", "repo1", "i like apples"),
createRepo(t, "owner", "repo-2", "i like oranges"),
createRepo(t, "owner", "repo-change", "i like carrots"),
createRepo(t, "owner", "repo-3", "i like carrots"),
},
}
},
args: []string{
"run",
"--repo-search", "repo",
"--repo-exclude", "(abc[def$",
"--commit-message", "chore: foo",
"--dry-run",
changerBinaryPath,
},
verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) {
require.Len(t, vcMock.PullRequests, 0)
assert.Contains(t, runData.cmdOut, "could not parse repo-exclude")
},
expectErr: true,
},

{
name: "parallel",
Expand Down