Skip to content

Commit 4544c25

Browse files
Merge pull request #3 from Harry-Moore-dev/dev
Add support for creating pull requests
2 parents 4f1b662 + aa3b6ad commit 4544c25

1,157 files changed

Lines changed: 377093 additions & 25 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
github-committer
8+
9+
# Test binary, built with `go test -c`
10+
*.test
11+
12+
# Output of the go coverage tool, specifically when used with LiteIDE
13+
*.out
14+
15+
# Dependency directories (remove the comment below to include it)
16+
# vendor/
17+
18+
# Go workspace file
19+
go.work

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ It uses the `GITHUB_TOKEN` environment variable with an action to authenticate.
66
## Installation
77

88
```
9-
go install github.com/iwarapter/github-commiter@latest
9+
go install github.com/Harry-Moore-dev/github-committer@latest
1010
```
1111

1212
## Usage
@@ -17,8 +17,9 @@ github-committer [OPTIONS]
1717
1818
Application Options:
1919
-r, --repository= the repository to push commits to
20-
-b, --branch= the branch to push commits to
20+
-b, --branch= the branch to push commits to (creates new branch if named branch doesn't exist)
2121
-m, --message= the commit message to use (default: updated with github-signer)
22+
-p, --prmake= automatically raises a pull request if set (default: false)
2223
2324
Help Options:
2425
-h, --help Show this help message
@@ -27,5 +28,5 @@ Help Options:
2728
## Example
2829

2930
```
30-
github-committer -r iwarapter/example -b main -m 'example commit message'
31+
github-committer -r Harry-Moore-dev/github-committer -b branchname -m 'example commit' -p
3132
```

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
module github.com/iwarapter/github-commiter
1+
module github.com/Harry-Moore-dev/github-committer
22

3-
go 1.19
3+
go 1.20
44

55
require (
66
github.com/go-git/go-git/v5 v5.5.2

main.go

Lines changed: 165 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@ package main
33
import (
44
"context"
55
"encoding/base64"
6+
"log"
7+
"os"
8+
"strings"
9+
610
"github.com/go-git/go-git/v5"
11+
"github.com/go-git/go-git/v5/plumbing"
712
"github.com/jessevdk/go-flags"
813
"github.com/shurcooL/githubv4"
914
"golang.org/x/oauth2"
10-
"log"
11-
"os"
1215
)
1316

17+
type Opts struct {
18+
Repository string `short:"r" long:"repository" description:"the repository to push commits to" required:"true"`
19+
BranchName string `short:"b" long:"branch" description:"the branch to push commits to" required:"true"`
20+
Message string `short:"m" long:"message" description:"the commit message to use" default:"updated with github-signer"`
21+
PullRequest bool `short:"p" long:"prmake" description:"automatically raises a pull request if set"`
22+
}
23+
1424
func main() {
15-
var opts struct {
16-
Repository string `short:"r" long:"repository" description:"the repository to push commits to" required:"true"`
17-
BranchName string `short:"b" long:"branch" description:"the branch to push commits to" required:"true"`
18-
Message string `short:"m" long:"message" description:"the commit message to use" default:"updated with github-signer"`
19-
}
20-
_, err := flags.Parse(&opts)
25+
ctx := context.Background()
26+
27+
var opts Opts
28+
parser := flags.NewParser(&opts, flags.Default)
29+
_, err := parser.Parse()
2130
switch e := err.(type) {
2231
case *flags.Error:
2332
if e.Type == flags.ErrHelp {
@@ -31,26 +40,60 @@ func main() {
3140
log.Fatal(err)
3241
}
3342

34-
r, err := git.PlainOpen(".")
43+
repo, err := git.PlainOpen(".")
3544
if err != nil {
3645
log.Fatalf("unable to open repository: %s", err)
3746
}
38-
39-
w, err := r.Worktree()
47+
worktree, err := repo.Worktree()
4048
if err != nil {
4149
log.Fatalf("unable to open repository: %s", err)
4250
}
43-
rev, err := r.Head()
51+
revision, err := repo.Head()
4452
if err != nil {
4553
log.Fatalf("unable to find HEAD revision: %s", err)
4654
}
47-
s, err := w.Status()
55+
status, err := worktree.Status()
4856
if err != nil {
4957
log.Fatalf("unable to open repository: %s", err)
5058
}
59+
changes := AddChanges(status)
60+
61+
client := createGhClient()
62+
63+
oid, repoId, err := getMainOid(ctx, client, opts)
64+
if err != nil {
65+
log.Fatalf("unable to lookup oid: %s", err)
66+
}
67+
68+
branchExists, err := CheckBranchExists(ctx, client, opts)
69+
if err != nil {
70+
log.Fatalf("unable to lookup branch: %s", err)
71+
}
72+
73+
if !branchExists {
74+
err = CreateBranch(ctx, client, opts, repoId, oid)
75+
if err != nil {
76+
log.Fatalf("unable to create branch: %s", err)
77+
}
78+
}
79+
80+
err = DoCommit(ctx, client, changes, opts, revision)
81+
if err != nil {
82+
log.Fatalf("unable to commit: %s", err)
83+
}
84+
85+
if opts.PullRequest {
86+
CreatePullRequest(ctx, client, opts, repoId)
87+
if err != nil {
88+
log.Fatalf("unable to create PR: %s", err)
89+
}
90+
}
91+
}
92+
93+
func AddChanges(status git.Status) *[]githubv4.FileAddition {
5194
changes := &[]githubv4.FileAddition{}
52-
for name, status := range s {
53-
if status.Worktree == git.Modified || status.Staging == git.Added || status.Staging == git.Modified {
95+
for name, status := range status {
96+
if status.Worktree == git.Modified || status.Staging == git.Added || status.Staging == git.Modified || status.Staging == git.Untracked {
5497
log.Printf("adding %s", name)
5598
b, _ := os.ReadFile(name)
5699
content := base64.StdEncoding.EncodeToString(b)
@@ -64,14 +107,21 @@ func main() {
64107
log.Printf("no changes to commit, exiting")
65108
os.Exit(0)
66109
}
110+
return changes
111+
}
112+
113+
func createGhClient() *githubv4.Client {
67114
src := oauth2.StaticTokenSource(
68115
&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
69116
)
70117
httpClient := oauth2.NewClient(context.Background(), src)
71118

72119
client := githubv4.NewClient(httpClient)
120+
return client
121+
}
73122

74-
var m struct {
123+
func DoCommit(ctx context.Context, client *githubv4.Client, changes *[]githubv4.FileAddition, opts Opts, revision *plumbing.Reference) error {
124+
var mutation struct {
75125
CreateCommitOnBranch struct {
76126
Commit struct {
77127
Url githubv4.ID
@@ -87,12 +137,107 @@ func main() {
87137
FileChanges: &githubv4.FileChanges{
88138
Additions: changes,
89139
},
90-
ExpectedHeadOid: githubv4.GitObjectID(rev.Hash().String()),
140+
ExpectedHeadOid: githubv4.GitObjectID(revision.Hash().String()),
141+
}
142+
143+
err := client.Mutate(ctx, &mutation, input, nil)
144+
if err != nil {
145+
return err
146+
}
147+
log.Printf("mutation complete: %s", mutation.CreateCommitOnBranch.Commit.Url)
148+
return nil
149+
}
150+
151+
func CheckBranchExists(ctx context.Context, client *githubv4.Client, opts Opts) (bool, error) {
152+
var query struct {
153+
Repository struct {
154+
Ref struct {
155+
Name string
156+
} `graphql:"ref(qualifiedName: $branchName)"`
157+
} `graphql:"repository(owner: $owner, name: $name)"`
158+
}
159+
variables := map[string]interface{}{
160+
"owner": githubv4.String(strings.Split(opts.Repository, "/")[0]),
161+
"name": githubv4.String(strings.Split(opts.Repository, "/")[1]),
162+
"branchName": githubv4.String("refs/heads/" + opts.BranchName),
163+
}
164+
165+
err := client.Query(ctx, &query, variables)
166+
if err != nil {
167+
return false, err
168+
}
169+
170+
if query.Repository.Ref.Name != "" {
171+
log.Printf("branch found: %s", query.Repository.Ref.Name)
172+
return true, nil
173+
} else {
174+
log.Printf("a branch with the name %s was not found", opts.BranchName)
175+
return false, nil
176+
}
177+
}
178+
179+
func getMainOid(ctx context.Context, client *githubv4.Client, opts Opts) (githubv4.GitObjectID, githubv4.ID, error) {
180+
var query struct {
181+
Repository struct {
182+
ID githubv4.ID
183+
Ref struct {
184+
Target struct {
185+
Oid githubv4.GitObjectID
186+
}
187+
} `graphql:"ref(qualifiedName: \"refs/heads/main\")"`
188+
} `graphql:"repository(owner: $owner, name: $name)"`
189+
}
190+
variables := map[string]interface{}{
191+
"owner": githubv4.String(strings.Split(opts.Repository, "/")[0]),
192+
"name": githubv4.String(strings.Split(opts.Repository, "/")[1]),
193+
}
194+
195+
err := client.Query(ctx, &query, variables)
196+
if err != nil {
197+
return "", "", err
198+
}
199+
return query.Repository.Ref.Target.Oid, query.Repository.ID, nil
200+
}
201+
202+
func CreateBranch(ctx context.Context, client *githubv4.Client, opts Opts, repoId githubv4.ID, oid githubv4.GitObjectID) error {
203+
var mutation struct {
204+
CreateRef struct {
205+
ClientMutationID githubv4.String
206+
} `graphql:"createRef(input: $input)"`
207+
}
208+
input := githubv4.CreateRefInput{
209+
RepositoryID: repoId,
210+
Name: githubv4.String("refs/heads/" + opts.BranchName),
211+
Oid: oid,
212+
}
213+
214+
err := client.Mutate(ctx, &mutation, input, nil)
215+
if err != nil {
216+
return err
217+
}
218+
log.Printf("%s branch created\n", opts.BranchName)
219+
return nil
220+
}
221+
222+
func CreatePullRequest(ctx context.Context, client *githubv4.Client, opts Opts, repoId githubv4.ID) error {
223+
var mutation struct {
224+
CreatePullRequest struct {
225+
PullRequest struct {
226+
ID githubv4.ID
227+
}
228+
} `graphql:"createPullRequest(input: $input)"`
229+
}
230+
input := githubv4.CreatePullRequestInput{
231+
RepositoryID: repoId,
232+
BaseRefName: "main",
233+
HeadRefName: githubv4.String(opts.BranchName),
234+
Title: githubv4.String(opts.Message),
91235
}
92236

93-
err = client.Mutate(context.Background(), &m, input, nil)
237+
err := client.Mutate(ctx, &mutation, input, nil)
94238
if err != nil {
95-
log.Fatalf("unable to mutate: %s", err)
239+
return err
96240
}
97-
log.Printf("mutation complete: %s", m.CreateCommitOnBranch.Commit.Url)
241+
log.Printf("pull request created %s\n", opts.BranchName)
242+
return nil
98243
}

vendor/github.com/Microsoft/go-winio/.gitignore

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/Microsoft/go-winio/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/Microsoft/go-winio/LICENSE

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/Microsoft/go-winio/README.md

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)