github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/ci/release/avado.go (about) 1 /* 2 * Copyright (C) 2021 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package release 19 20 import ( 21 "bufio" 22 "context" 23 "fmt" 24 "strings" 25 "time" 26 27 "github.com/google/go-github/v35/github" 28 "github.com/mysteriumnetwork/go-ci/job" 29 "github.com/rs/zerolog/log" 30 "golang.org/x/oauth2" 31 32 "github.com/mysteriumnetwork/go-ci/env" 33 "github.com/mysteriumnetwork/node/logconfig" 34 ) 35 36 type avadoPR struct { 37 client *github.Client 38 39 version string 40 41 avadoUser string 42 mysteriumUser string 43 44 msg string 45 branch string 46 47 repo string 48 49 authorName string 50 authorEmail string 51 } 52 53 func newAvadoPR(ctx context.Context) *avadoPR { 54 token := env.Str(env.GithubAPIToken) 55 version := env.Str(env.BuildVersion) 56 owner := env.Str(env.GithubOwner) 57 58 ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}) 59 tc := oauth2.NewClient(ctx, ts) 60 client := github.NewClient(tc) 61 62 return &avadoPR{ 63 version: version, 64 client: client, 65 66 avadoUser: "AvadoDServer", 67 mysteriumUser: owner, 68 69 repo: "AVADO-DNP-Mysterium-Server", 70 71 msg: "Update Mysterium Node version to " + version, 72 branch: "update-mysterium-node-" + version, 73 74 authorName: "MysteriumTeam", 75 authorEmail: "core-services@mysterium.network", 76 } 77 } 78 79 func (a *avadoPR) getRef(ctx context.Context) (ref *github.Reference, err error) { 80 var baseRef *github.Reference 81 if baseRef, _, err = a.client.Git.GetRef(ctx, a.avadoUser, a.repo, "refs/heads/master"); err != nil { 82 return nil, err 83 } 84 newRef := &github.Reference{Ref: github.String("refs/heads/" + a.branch), Object: &github.GitObject{SHA: baseRef.Object.SHA}} 85 ref, _, err = a.client.Git.CreateRef(ctx, a.mysteriumUser, a.repo, newRef) 86 return ref, err 87 } 88 89 func (a *avadoPR) getTree(ctx context.Context, ref *github.Reference) (tree *github.Tree, err error) { 90 entries := []*github.TreeEntry{} 91 92 for _, fileName := range []string{"dappnode_package.json", "build/Dockerfile"} { 93 file, content, err := a.getFileContent(ctx, fileName) 94 if err != nil { 95 return nil, err 96 } 97 content = replaceVersion(file, content, a.version) 98 entries = append(entries, &github.TreeEntry{Path: github.String(file), Type: github.String("blob"), Content: github.String(content), Mode: github.String("100644")}) 99 } 100 101 tree, _, err = a.client.Git.CreateTree(ctx, a.mysteriumUser, a.repo, *ref.Object.SHA, entries) 102 return tree, err 103 } 104 105 func (a *avadoPR) getFileContent(ctx context.Context, fileArg string) (targetName string, s string, err error) { 106 f, _, _, err := a.client.Repositories.GetContents(ctx, a.avadoUser, a.repo, fileArg, nil) 107 if err != nil { 108 return "", "", err 109 } 110 111 c, err := f.GetContent() 112 return fileArg, c, err 113 } 114 115 func (a *avadoPR) pushCommit(ctx context.Context, ref *github.Reference, tree *github.Tree) (err error) { 116 parent, _, err := a.client.Repositories.GetCommit(ctx, a.mysteriumUser, a.repo, *ref.Object.SHA) 117 if err != nil { 118 return err 119 } 120 121 parent.Commit.SHA = parent.SHA 122 123 date := time.Now() 124 author := &github.CommitAuthor{Date: &date, Name: &a.authorName, Email: &a.authorEmail} 125 commit := &github.Commit{Author: author, Message: &a.msg, Tree: tree, Parents: []*github.Commit{parent.Commit}} 126 newCommit, _, err := a.client.Git.CreateCommit(ctx, a.mysteriumUser, a.repo, commit) 127 if err != nil { 128 return err 129 } 130 131 ref.Object.SHA = newCommit.SHA 132 _, _, err = a.client.Git.UpdateRef(ctx, a.mysteriumUser, a.repo, ref, false) 133 return err 134 } 135 136 func (a *avadoPR) createPR(ctx context.Context) (err error) { 137 base := "master" 138 head := fmt.Sprintf("%s:%s", a.mysteriumUser, a.branch) 139 140 newPR := &github.NewPullRequest{ 141 Title: &a.msg, 142 Head: &head, 143 Base: &base, 144 MaintainerCanModify: github.Bool(true), 145 } 146 147 _, _, err = a.client.PullRequests.Create(ctx, a.avadoUser, a.repo, newPR) 148 if err != nil { 149 return err 150 } 151 152 return nil 153 } 154 155 func replaceVersion(file, content, version string) (out string) { 156 oldLine := "" 157 newLine := "" 158 switch file { 159 case "dappnode_package.json": 160 oldLine = ` "upstream": ` 161 newLine = fmt.Sprintf(` "upstream": "%s",`, version) 162 case "build/Dockerfile": 163 oldLine = "FROM mysteriumnetwork/myst:" 164 newLine = fmt.Sprintf(`FROM mysteriumnetwork/myst:%s-alpine`, version) 165 } 166 167 scanner := bufio.NewScanner(strings.NewReader(content)) 168 for scanner.Scan() { 169 line := scanner.Text() 170 if strings.Contains(line, oldLine) && !strings.HasPrefix(line, "#") { 171 out += newLine + "\n" 172 } else { 173 out += line + "\n" 174 } 175 } 176 177 return out 178 } 179 180 // CreateAvadoPR create github PR to the Avado repository. 181 func CreateAvadoPR() error { 182 logconfig.Bootstrap() 183 184 if err := env.EnsureEnvVars( 185 env.GithubAPIToken, 186 env.GithubOwner, 187 env.BuildVersion, 188 ); err != nil { 189 return err 190 } 191 job.Precondition(func() bool { 192 return env.Bool(env.TagBuild) && !env.Bool(env.RCBuild) 193 }) 194 195 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 196 defer cancel() 197 198 a := newAvadoPR(ctx) 199 200 ref, err := a.getRef(ctx) 201 if err != nil || ref == nil { 202 log.Error().Msgf("Unable to get/create the commit reference: %s\n", err) 203 return err 204 } 205 206 tree, err := a.getTree(ctx, ref) 207 if err != nil { 208 log.Error().Msgf("Unable to create the tree based on the provided files: %s\n", err) 209 return err 210 } 211 212 if err := a.pushCommit(ctx, ref, tree); err != nil { 213 log.Error().Msgf("Unable to create the commit: %s\n", err) 214 return err 215 } 216 217 if err := a.createPR(ctx); err != nil { 218 log.Error().Msgf("Error while creating the pull request: %s", err) 219 return err 220 } 221 222 return nil 223 }