1// Copyright 2021 Google LLC
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//     https://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
14package main
15
16import (
17	"flag"
18	"fmt"
19	"io"
20	"log"
21	"os"
22	"os/exec"
23	"path/filepath"
24	"strings"
25)
26
27func main() {
28	parent := flag.String("parent", "", "The path to the parent module. Required.")
29	child := flag.String("child", "", "The comma seperated relative paths to the child modules from the parent. Required.")
30	flag.Parse()
31	if *parent == "" || *child == "" {
32		log.Fatalf("parent and child are required")
33	}
34	children := strings.Split(strings.TrimSpace(*child), ",")
35	for _, child := range children {
36		if err := stabilize(*parent, child); err != nil {
37			log.Fatalf("unable to stabilize %v: %v", child, err)
38		}
39		tidy(filepath.Join(*parent, child))
40	}
41	tidy(*parent)
42	printCommands(children)
43}
44
45func stabilize(parentPath, child string) error {
46	// Remove file that is no longer needed
47	tidyHackPath := filepath.Join(parentPath, child, "go_mod_tidy_hack.go")
48	if err := os.Remove(tidyHackPath); err != nil {
49		return fmt.Errorf("unable to remove file in %v: %v", child, err)
50	}
51
52	// Update CHANGES.md
53	changesPath := filepath.Join(parentPath, child, "CHANGES.md")
54	f, err := os.OpenFile(changesPath, os.O_RDWR, 0644)
55	if err != nil {
56		return fmt.Errorf("unable to open CHANGES.md in %v: %v", child, err)
57	}
58	defer f.Close()
59	content, err := io.ReadAll(f)
60	if err != nil {
61		return err
62	}
63	ss := strings.Split(strings.TrimSpace(string(content)), "\n")
64	if _, err := f.Seek(0, io.SeekStart); err != nil {
65		return err
66	}
67	for i, line := range ss {
68		// Insert content after header
69		if i == 2 {
70			fmt.Fprint(f, "## 1.0.0\n\n")
71			fmt.Fprint(f, "Stabilize GA surface.\n\n")
72		}
73		fmt.Fprintf(f, "%s\n", line)
74	}
75	return nil
76}
77
78func tidy(dir string) error {
79	c := exec.Command("go", "mod", "tidy")
80	c.Dir = dir
81	return c.Run()
82}
83
84func printCommands(children []string) {
85	fmt.Print("Tags for commit message:\n")
86	for _, v := range children {
87		fmt.Printf("- %s/v1.0.0\n", v)
88	}
89	fmt.Print("\nCommands to run:\n")
90	for _, v := range children {
91		fmt.Printf("git tag %s/v1.0.0 $COMMIT_SHA\n", v)
92	}
93	for _, v := range children {
94		fmt.Printf("git push $REMOTE refs/tags/%s/v1.0.0\n", v)
95	}
96}
97