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

Add support for signed commits through the Github API #492

Draft
wants to merge 42 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
2caa810
Hello from GraphQL!
ChrisStatham Jul 9, 2024
8cf626f
adding commitonbranch
ChrisStatham Jul 9, 2024
a2c3803
checking in progress
ChrisStatham Jul 9, 2024
3ea2a0c
more progress
ChrisStatham Jul 9, 2024
80547c9
Update commit.go
ChrisStatham Jul 9, 2024
3c04b79
cleaning up my experimetation
ChrisStatham Jul 9, 2024
5feadf7
saving changes
ChrisStatham Jul 10, 2024
177f64a
Merge branch 'APPSEC-1108' of github.com:ChrisStatham/multi-gitter in…
ChrisStatham Jul 10, 2024
40361af
a bit more clenaup
ChrisStatham Jul 10, 2024
849afe3
correctly formatting graphql request (probably)
ChrisStatham Jul 10, 2024
42e9877
finishing hooking everything up
ChrisStatham Jul 10, 2024
f130b46
revert this after were done testing and add the environment variable
ChrisStatham Jul 10, 2024
9bdf4be
revert HEAD
ChrisStatham Jul 10, 2024
8bf07f4
run this
ChrisStatham Jul 10, 2024
113bced
its working
ChrisStatham Jul 11, 2024
f29253d
Adding a comment
ChrisStatham Jul 11, 2024
bce5f57
fixing stuff
ChrisStatham Jul 11, 2024
ddb6eca
adding proper json support
ChrisStatham Jul 11, 2024
bd94877
removing debugging lines
ChrisStatham Jul 11, 2024
e12c7bb
small improvement
ChrisStatham Jul 11, 2024
8cda390
unused variable removed
ChrisStatham Jul 11, 2024
bd93c5d
force run
ChrisStatham Jul 11, 2024
5aac59a
wrapping with a var
ChrisStatham Jul 11, 2024
57016fd
test
ChrisStatham Jul 11, 2024
25af300
use gh api
ChrisStatham Jul 11, 2024
da6ac1d
a small change
ChrisStatham Jul 12, 2024
ea87207
logging current work
ChrisStatham Jul 15, 2024
e6fe0ef
improve implementaiton a little bit
ChrisStatham Jul 15, 2024
083eb9f
creating branch with graphql
ChrisStatham Jul 15, 2024
96733f7
create branch through graphql
ChrisStatham Jul 16, 2024
fce4350
refactoring
ChrisStatham Jul 16, 2024
6bfe30d
insanity
ChrisStatham Jul 17, 2024
787ffd4
fixing more stuff
ChrisStatham Jul 17, 2024
04028cb
fix query
ChrisStatham Jul 17, 2024
891b12d
fix linter warnings
ChrisStatham Jul 17, 2024
b4ed9a9
Merge pull request #1 from ChrisStatham/APPSEC-1108
ChrisStatham Jul 17, 2024
d2ae4f8
docs: updated readme
github-actions[bot] Jul 17, 2024
3cb7edc
Updating documentation to reflect the new flag
ChrisStatham Jul 17, 2024
abd9846
Merge branch 'master' of github.com:ChrisStatham/multi-gitter
ChrisStatham Jul 17, 2024
b6ff701
remove debugging messages
ChrisStatham Jul 17, 2024
9ed677f
Cleanup branch
ChrisStatham Jul 17, 2024
3ee1097
docs: updated readme
github-actions[bot] Jul 17, 2024
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ token:
topic:
- example

# Attempt to commit and push through the Github API, rather than pushing through the git client.
use-gh-api: false

# The name of a user. All repositories owned by that user will be used.
user:
- example
Expand Down Expand Up @@ -699,6 +702,7 @@ Flags:
--team-reviewers strings Github team names of the reviewers, in format: 'org/team'
-T, --token string The personal access token for the targeting platform. Can also be set using the GITHUB_TOKEN/GITLAB_TOKEN/GITEA_TOKEN/BITBUCKET_SERVER_TOKEN environment variable.
--topic strings The topic of a GitHub/GitLab/Gitea repository. All repositories having at least one matching topic are targeted.
--use-gh-api Attempt to commit and push through the Github API, rather than pushing through the git client.
-U, --user strings The name of a user. All repositories owned by that user will be used.
-u, --username string The Bitbucket server username.
```
Expand Down
3 changes: 3 additions & 0 deletions cmd/cmd-run.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Available values:
_ = cmd.RegisterFlagCompletionFunc("conflict-strategy", func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
return []string{"skip", "replace"}, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().BoolP("use-gh-api", "", false, "Attempt to commit and push through the Github API, rather than pushing through the git client.")
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.")
Expand Down Expand Up @@ -92,6 +93,7 @@ func run(cmd *cobra.Command, _ []string) error {
concurrent, _ := flag.GetInt("concurrent")
skipPullRequest, _ := flag.GetBool("skip-pr")
pushOnly, _ := flag.GetBool("push-only")
useGHAPI, _ := flag.GetBool("use-gh-api")
skipRepository, _ := flag.GetStringSlice("skip-repo")
interactive, _ := flag.GetBool("interactive")
dryRun, _ := flag.GetBool("dry-run")
Expand Down Expand Up @@ -241,6 +243,7 @@ func run(cmd *cobra.Command, _ []string) error {
ForkOwner: forkOwner,
SkipPullRequest: skipPullRequest,
PushOnly: pushOnly,
UseGHAPI: useGHAPI,
SkipRepository: skipRepository,
CommitAuthor: commitAuthor,
BaseBranch: baseBranchName,
Expand Down
12 changes: 12 additions & 0 deletions internal/git/cmdgit/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,15 @@ func (g *Git) AddRemote(name, url string) error {
_, err := g.run(cmd)
return err
}

func (g *Git) Additions() map[string]string {
return make(map[string]string)
}

func (g *Git) Deletions() []string {
return make([]string, 0)
}

func (g *Git) OldHash() string {
return ""
}
58 changes: 56 additions & 2 deletions internal/git/gogit/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package gogit
import (
"bytes"
"context"
"encoding/base64"
"os"
"time"

"github.com/go-git/go-git/v5/config"
Expand All @@ -22,6 +24,10 @@ type Git struct {
FetchDepth int // Limit fetching to the specified number of commits

repo *git.Repository // The repository after the clone has been made

additions map[string]string // Files being added (used for GHAPI)
deletions []string // Files being remove (used for GHAPI)
oldHash plumbing.Hash
}

// Clone a repository
Expand Down Expand Up @@ -75,6 +81,37 @@ func (g *Git) Changes() (bool, error) {
return !status.IsClean(), nil
}

func (g *Git) GetFileChangesAsBase64(w git.Worktree) error {
treeStatus, err := w.Status()

if err != nil {
return err
}

g.additions = make(map[string]string)

for path, status := range treeStatus {
s := status.Worktree

if s == git.Deleted || s == git.Renamed || s == git.Copied {
g.deletions = append(g.deletions, path)
} else if s == git.Added || s == git.Modified || s == git.Untracked {
data, err := os.ReadFile(g.Directory + "/" + path)

if err != nil {
return err
}

output := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(output, data)

g.additions[path] = string(output)
}
}

return nil
}

// Commit and push all changes
func (g *Git) Commit(commitAuthor *internalgit.CommitAuthor, commitMessage string) error {
w, err := g.repo.Worktree()
Expand All @@ -89,6 +126,11 @@ func (g *Git) Commit(commitAuthor *internalgit.CommitAuthor, commitMessage strin
}
w.Excludes = patterns

err = g.GetFileChangesAsBase64(*w)
if err != nil {
return err
}

err = w.AddWithOptions(&git.AddOptions{
All: true,
})
Expand Down Expand Up @@ -117,7 +159,7 @@ func (g *Git) Commit(commitAuthor *internalgit.CommitAuthor, commitMessage strin
if err != nil {
return err
}
oldHash := oldHead.Hash()
g.oldHash = oldHead.Hash()

var author *object.Signature
if commitAuthor != nil {
Expand All @@ -140,7 +182,7 @@ func (g *Git) Commit(commitAuthor *internalgit.CommitAuthor, commitMessage strin
return err
}

_ = g.logDiff(oldHash, commit.Hash)
_ = g.logDiff(g.oldHash, commit.Hash)

return nil
}
Expand Down Expand Up @@ -210,6 +252,18 @@ func (g *Git) Push(ctx context.Context, remoteName string, force bool) error {
})
}

func (g *Git) Additions() map[string]string {
return g.additions
}

func (g *Git) Deletions() []string {
return g.deletions
}

func (g *Git) OldHash() string {
return g.oldHash.String()
}

// AddRemote adds a new remote
func (g *Git) AddRemote(name, url string) error {
_, err := g.repo.CreateRemote(&config.RemoteConfig{
Expand Down
34 changes: 33 additions & 1 deletion internal/multigitter/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type Runner struct {
ForkOwner string // The owner of the new fork. If empty, the fork should happen on the logged in user

ConflictStrategy ConflictStrategy // Defines what will happen if a branch already exists
UseGHAPI bool

Draft bool // If set, creates Pull Requests as draft

Expand Down Expand Up @@ -338,7 +339,38 @@ func (r *Runner) runSingleRepo(ctx context.Context, repo scm.Repository) (scm.Pu

log.Info("Pushing changes to remote")
forcePush := featureBranchExist && r.ConflictStrategy == ConflictStrategyReplace
err = sourceController.Push(ctx, remoteName, forcePush)
if r.UseGHAPI {
if ghapi, ok := r.VersionController.(interface {
CommitAndPushThoughGraphQL(ctx context.Context,
headline string,
featureBranch string,
cloneURL string,
oldHash string,
additions map[string]string,
deletions []string,
forcePush bool,
branchExist bool) error
}); ok {
err = ghapi.CommitAndPushThoughGraphQL(ctx,
r.CommitMessage,
r.FeatureBranch,
repo.CloneURL(),
sourceController.OldHash(),
sourceController.Additions(),
sourceController.Deletions(),
forcePush,
featureBranchExist)
if err != nil {
return nil, err
}
} else {
log.Info("Could not find CommitThroughAPI, falling back on default push")
err = sourceController.Push(ctx, remoteName, forcePush)
}
} else {
err = sourceController.Push(ctx, remoteName, forcePush)
}

if err != nil {
return nil, errors.Wrap(err, "could not push changes")
}
Expand Down
3 changes: 3 additions & 0 deletions internal/multigitter/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type Git interface {
BranchExist(remoteName, branchName string) (bool, error)
Push(ctx context.Context, remoteName string, force bool) error
AddRemote(name, url string) error
Additions() map[string]string
Deletions() []string
OldHash() string
}

type stackTracer interface {
Expand Down
Loading
Loading