github.com/mentimeter/morty@v1.2.2-0.20221012065510-5596adecd154/mortems/git_service.go (about) 1 package mortems 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/google/go-github/v35/github" 10 "golang.org/x/oauth2" 11 ) 12 13 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . RepoFileService 14 15 type RepoFileService interface { 16 GetFiles() (*RepoFiles, error) 17 CommitNewFiles(*RepoFiles) error 18 } 19 20 type GitHub struct { 21 client *github.Client 22 ref string 23 owner string 24 repository string 25 currentTree *github.Tree 26 currentCommit *github.Commit 27 currentRef *github.Reference 28 } 29 30 func NewGitHubService(token, fullRepository, ref string) RepoFileService { 31 ctx := context.Background() 32 ts := oauth2.StaticTokenSource( 33 &oauth2.Token{AccessToken: token}, 34 ) 35 tc := oauth2.NewClient(ctx, ts) 36 client := github.NewClient(tc) 37 repositoryArgs := strings.Split(fullRepository, "/") 38 39 return &GitHub{ 40 client: client, 41 ref: ref, 42 owner: repositoryArgs[0], 43 repository: repositoryArgs[1], 44 } 45 } 46 47 func (g *GitHub) GetFiles() (*RepoFiles, error) { 48 ctx := context.Background() 49 50 ref, _, err := g.client.Git.GetRef(ctx, g.owner, g.repository, g.ref) 51 if err != nil { 52 return nil, fmt.Errorf("could not get ref: %w", err) 53 } 54 55 g.currentRef = ref 56 57 commit, _, err := g.client.Git.GetCommit(ctx, g.owner, g.repository, ref.Object.GetSHA()) 58 if err != nil { 59 return nil, fmt.Errorf("could not get commit: %w", err) 60 } 61 62 g.currentCommit = commit 63 64 tree, _, err := g.client.Git.GetTree(ctx, g.owner, g.repository, commit.GetTree().GetSHA(), true) 65 if err != nil { 66 return nil, fmt.Errorf("could not get tree: %w", err) 67 } 68 69 g.currentTree = tree 70 71 var files []*File 72 73 for _, entry := range tree.Entries { 74 if entry.GetType() == "blob" { 75 content, _, err := g.client.Git.GetBlobRaw(ctx, g.owner, g.repository, entry.GetSHA()) 76 if err != nil { 77 return nil, fmt.Errorf("could not get blob content: %w", err) 78 } 79 80 entry.Content = github.String(string(content)) 81 82 file := &File{ 83 Path: *entry.Path, 84 Mode: *entry.Mode, 85 Type: "blob", 86 Content: string(content), 87 } 88 89 files = append(files, file) 90 } 91 } 92 93 return &RepoFiles{files}, nil 94 } 95 96 func (g *GitHub) CommitNewFiles(updateEntries *RepoFiles) error { 97 ctx := context.Background() 98 99 newTree, _, err := g.client.Git.CreateTree(ctx, g.owner, g.repository, g.currentTree.GetSHA(), updateEntries.ToTreeEntries()) 100 if err != nil { 101 return fmt.Errorf("could not create a new tree: %w", err) 102 } 103 104 authorDate := time.Now() 105 author := &github.CommitAuthor{ 106 Date: &authorDate, 107 Name: g.currentCommit.Author.Name, 108 Email: g.currentCommit.Author.Email, 109 } 110 111 newCommitData := &github.Commit{ 112 Author: author, 113 Committer: author, 114 Message: github.String("Auto-morty-cally analyse post-mortems"), 115 Tree: newTree, 116 Parents: []*github.Commit{g.currentCommit}, 117 } 118 119 createdCommit, _, err := g.client.Git.CreateCommit(ctx, g.owner, g.repository, newCommitData) 120 if err != nil { 121 return fmt.Errorf("could not create a new commit: %w", err) 122 } 123 124 g.currentRef.Object.SHA = createdCommit.SHA 125 126 _, _, err = g.client.Git.UpdateRef(ctx, g.owner, g.repository, g.currentRef, false) 127 if err != nil { 128 return fmt.Errorf("could not update the current ref: %w", err) 129 } 130 131 return nil 132 }