github.com/cs3org/reva/v2@v2.27.7/tools/prepare-release/main.go (about) 1 // Copyright 2018-2022 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package main 20 21 import ( 22 "bytes" 23 "flag" 24 "fmt" 25 "io" 26 "os" 27 "os/exec" 28 "path" 29 "strings" 30 "time" 31 ) 32 33 var ( 34 version = flag.String("version", "", "version to release: 0.0.1") 35 commit = flag.Bool("commit", false, "creates a commit") 36 tag = flag.Bool("tag", false, "creates a tag") 37 ) 38 39 func init() { 40 flag.Parse() 41 42 if *version == "" { 43 fmt.Fprintf(os.Stderr, "missing version: use -version flag\n") 44 os.Exit(1) 45 } 46 } 47 48 func main() { 49 // check if repo is dirty 50 if isRepoDirty() { 51 fmt.Fprintf(os.Stderr, "the repo is dirty, to generate a new release all changes need to be committed\n") 52 os.Exit(1) 53 return 54 } 55 56 // also the build is okay 57 cmd := exec.Command("make", "gen-doc") 58 run(cmd) 59 60 fmt.Printf("Generating new release: version=%s\n", *version) 61 62 dt := time.Now() 63 date := dt.Format("2006-01-02") 64 newChangelog := fmt.Sprintf("changelog/%s_%s", *version, date) 65 66 if info, _ := os.Stat("changelog/unreleased"); info == nil { 67 fmt.Fprintf(os.Stderr, "no changelog/unreleased folder, to create a new version you need to fill it") 68 os.Exit(1) 69 } 70 71 cmd = exec.Command("mv", "changelog/unreleased", newChangelog) 72 run(cmd) 73 74 // install release-deps: calens 75 cmd = exec.Command("make", "toolchain") 76 run(cmd) 77 78 // create new changelog 79 cmd = exec.Command("toolchain/calens", "-o", "CHANGELOG.md") 80 run(cmd) 81 82 // add new VERSION and BUILD_DATE 83 if err := os.WriteFile("VERSION", []byte(*version), 0644); err != nil { 84 fmt.Fprintf(os.Stderr, "error writing to VERSION file: %s", err) 85 os.Exit(1) 86 } 87 88 // add new VERSION and RELEASE_DATE 89 if err := os.WriteFile("RELEASE_DATE", []byte(date), 0644); err != nil { 90 fmt.Fprintf(os.Stderr, "error writing to RELEASE_DATE file: %s", err) 91 os.Exit(1) 92 } 93 94 tmp, err := os.MkdirTemp("", "reva-changelog") 95 if err != nil { 96 fmt.Fprintf(os.Stderr, "error creating tmp directory to store changelog: %s", err) 97 os.Exit(1) 98 } 99 100 if err := os.MkdirAll(path.Join(tmp, "changelog"), 0755); err != nil { 101 fmt.Fprintf(os.Stderr, "error creating changelog in temporary directory: %s", tmp) 102 os.RemoveAll(tmp) 103 os.Exit(1) 104 } 105 106 dir := path.Join(tmp, fmt.Sprintf("changelog/%s_%s", *version, date)) 107 cmd = exec.Command("cp", "-a", fmt.Sprintf("changelog/%s_%s", *version, date), dir) 108 run(cmd) 109 110 // create new changelog 111 cmd = exec.Command("toolchain/calens", "-o", "changelog/NOTE.md", "-i", path.Join(tmp, "changelog")) 112 run(cmd) 113 114 // Generate changelog also in the documentation 115 if err := os.MkdirAll(fmt.Sprintf("docs/content/en/docs/changelog/%s", *version), 0755); err != nil { 116 fmt.Fprintf(os.Stderr, "error creating docs/content/en/docs/changelog/%s: %s", *version, err) 117 os.RemoveAll(tmp) 118 os.Exit(1) 119 } 120 os.RemoveAll(tmp) 121 122 data, err := os.ReadFile("changelog/NOTE.md") 123 if err != nil { 124 fmt.Fprintf(os.Stderr, "error reading NOTE.md: %s", err) 125 os.Exit(1) 126 } 127 128 releaseDocs := fmt.Sprintf(` 129 --- 130 title: "v%s" 131 linkTitle: "v%s" 132 weight: 40 133 description: > 134 Changelog for Reva v%s (%s) 135 --- 136 137 `, *version, *version, *version, date) 138 139 releaseDocs += string(data) 140 if err := os.WriteFile(fmt.Sprintf("docs/content/en/docs/changelog/%s/_index.md", *version), []byte(releaseDocs), 0644); err != nil { 141 fmt.Fprintf(os.Stderr, "error writing docs release file _index.md: %s", err) 142 os.Exit(1) 143 } 144 145 add(fmt.Sprintf("v%s", *version), 146 "changelog", 147 "CHANGELOG.md", 148 "VERSION", 149 "RELEASE_DATE", 150 "docs/content/en/docs/changelog", 151 ) 152 153 if *commit { 154 createCommit(fmt.Sprintf("v%s", *version)) 155 fmt.Println("Commit created, check with git log") 156 } 157 158 if *tag { 159 createTag(*version) 160 fmt.Println("Tag created, check with git tag") 161 } 162 163 if *tag && *commit { 164 fmt.Println("RELEASE READY: you only need to\n$ git push --follow-tags") 165 os.Exit(0) 166 } else { 167 fmt.Println("Was a dry run, run with -commit and -tag to create release") 168 os.Exit(1) 169 } 170 } 171 172 func isRepoDirty() bool { 173 repo := "." 174 cmd := exec.Command("git", "status", "-s") 175 cmd.Dir = repo 176 changes := runAndGet(cmd) 177 if changes != "" { 178 fmt.Println("repo is dirty") 179 fmt.Println(changes) 180 } 181 return changes != "" 182 } 183 184 func add(msg string, files ...string) { 185 for _, f := range files { 186 cmd := exec.Command("git", "add", "--all", f) 187 cmd.Dir = "." 188 run(cmd) 189 } 190 } 191 192 func createCommit(msg string) { 193 cmd := exec.Command("git", "commit", "-m", msg) 194 cmd.Dir = "." // always run from the root of the repo 195 run(cmd) 196 } 197 198 func createTag(version string) { 199 // check if repo is dirty 200 if isRepoDirty() { 201 fmt.Fprintf(os.Stderr, "repo is dirty when creating a new tag for version %s", version) 202 os.Exit(1) 203 } 204 205 cmd := exec.Command("git", "tag", "-a", "v"+version, "-m", "v"+version) 206 run(cmd) 207 } 208 209 func run(cmd *exec.Cmd) { 210 var b bytes.Buffer 211 mw := io.MultiWriter(os.Stdout, &b) 212 cmd.Stdout = mw 213 cmd.Stderr = mw 214 err := cmd.Run() 215 fmt.Println(cmd.Dir, cmd.Args) 216 fmt.Println(b.String()) 217 if err != nil { 218 fmt.Println("ERROR: ", err.Error()) 219 os.Exit(1) 220 } 221 } 222 223 func runAndGet(cmd *exec.Cmd) string { 224 var b bytes.Buffer 225 mw := io.MultiWriter(os.Stdout, &b) 226 cmd.Stderr = mw 227 out, err := cmd.Output() 228 fmt.Println(cmd.Dir, cmd.Args) 229 fmt.Println(b.String()) 230 if err != nil { 231 fmt.Println("ERROR: ", err.Error()) 232 os.Exit(1) 233 } 234 return strings.TrimSpace(string(out)) 235 }