Skip to content

Commit 4374b90

Browse files
authored
feat(.github): support dynamic submodule detection (#4537)
Today the sub-modules are are coded into a couple of places to work with release-please. This change is the first of three to make release-please automatically support newly added modules.
1 parent 67facd9 commit 4374b90

File tree

3 files changed

+160
-37
lines changed

3 files changed

+160
-37
lines changed

.github/workflows/release-submodule.yaml

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,12 @@ jobs:
1919
submodules: ${{ steps.interrogate.outputs.submodules }}
2020
steps:
2121
- uses: actions/checkout@v2
22-
- id: interrogate
23-
uses: actions/github-script@v4
22+
- name: Setup Go
23+
uses: actions/setup-go@v2
2424
with:
25-
github-token: ${{secrets.GITHUB_TOKEN}}
26-
script: |
27-
const {execSync} = require('child_process');
28-
const SUB_MODULES = [
29-
'bigtable',
30-
'bigquery',
31-
'datastore',
32-
'firestore',
33-
'logging',
34-
'pubsub',
35-
'pubsublite',
36-
'spanner',
37-
'storage',
38-
];
39-
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
40-
const latestRelease = await github.repos.getLatestRelease({
41-
owner,
42-
repo
43-
});
44-
console.info(`latest release: ${latestRelease.data.tag_name}`);
45-
// pull all tags, so we can get diff between HEAD and last release:
46-
execSync('git pull --tags');
47-
execSync(`git reset --hard ${latestRelease.data.tag_name}`);
48-
const status = execSync(`git diff --name-only origin/master`, { encoding: 'utf-8'});
49-
console.info(status);
50-
const changes = status.split('\n');
51-
const submodules = new Set();
52-
for (const change of changes) {
53-
const library = change.split('/')[0];
54-
console.info(`update to path ${library}`);
55-
if (SUB_MODULES.includes(library)) {
56-
submodules.add(library);
57-
}
58-
}
59-
console.log(`::set-output name=submodules::${JSON.stringify(Array.from(submodules))}`);
25+
go-version: '^1.16'
26+
- id: interrogate
27+
run: go run internal/actions/cmd/changefinder/main.go
6028
release-pr: # Create the release PR based on commit history:
6129
runs-on: ubuntu-latest
6230
needs: changeFinder
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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+
// 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+
package main
16+
17+
import (
18+
"bytes"
19+
"encoding/json"
20+
"fmt"
21+
"io/fs"
22+
"log"
23+
"os"
24+
"os/exec"
25+
"path/filepath"
26+
"strings"
27+
)
28+
29+
func main() {
30+
rootDir, err := os.Getwd()
31+
if err != nil {
32+
log.Fatal(err)
33+
}
34+
if len(os.Args) > 1 {
35+
rootDir = os.Args[1]
36+
}
37+
log.Printf("Root dir: %q", rootDir)
38+
var modDirs []string
39+
// Find all external modules
40+
filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error {
41+
if err != nil {
42+
return err
43+
}
44+
if d.Name() == "internal" {
45+
return filepath.SkipDir
46+
}
47+
if d.Name() == "go.mod" {
48+
modDirs = append(modDirs, filepath.Dir(path))
49+
}
50+
return nil
51+
})
52+
53+
// Find relative sub-module
54+
submodules := map[string]bool{}
55+
for _, dir := range modDirs {
56+
name, err := modName(dir)
57+
if err != nil {
58+
log.Fatalf("unable to lookup mod dir")
59+
}
60+
// Skip non-submodule
61+
if name == "cloud.google.com/go" {
62+
continue
63+
}
64+
name = strings.TrimPrefix(name, "cloud.google.com/go/")
65+
submodules[name] = true
66+
}
67+
68+
c := exec.Command("git", "pull", "--tags")
69+
c.Dir = rootDir
70+
if err := c.Run(); err != nil {
71+
log.Fatalf("unable to pull tags: %v", err)
72+
}
73+
74+
tag, err := latestTag(rootDir)
75+
if err != nil {
76+
log.Fatalf("unable to find tag: %v", err)
77+
}
78+
log.Printf("Latest release: %s", tag)
79+
80+
c = exec.Command("git", "reset", "--hard", tag)
81+
c.Dir = rootDir
82+
if err := c.Run(); err != nil {
83+
log.Fatalf("unable to reset to tag: %v", err)
84+
}
85+
86+
changes, err := gitFilesChanges(rootDir)
87+
if err != nil {
88+
log.Fatalf("unable to get files changed: %v", err)
89+
}
90+
91+
updatedSubmodulesSet := map[string]bool{}
92+
for _, change := range changes {
93+
//TODO(codyoss): This will not work with nested sub-modules. If we add
94+
// those this needs to be updated.
95+
pkg := strings.Split(change, "/")[0]
96+
log.Printf("update to path: %s", pkg)
97+
if submodules[pkg] {
98+
updatedSubmodulesSet[pkg] = true
99+
}
100+
}
101+
102+
updatedSubmodule := []string{}
103+
for mod := range updatedSubmodulesSet {
104+
updatedSubmodule = append(updatedSubmodule, mod)
105+
}
106+
b, err := json.Marshal(updatedSubmodule)
107+
if err != nil {
108+
log.Fatalf("unable to marshal submodules: %v", err)
109+
}
110+
fmt.Printf("::set-output name=submodules::%s", b)
111+
}
112+
113+
func modName(dir string) (string, error) {
114+
c := exec.Command("go", "list", "-m")
115+
c.Dir = dir
116+
b, err := c.Output()
117+
if err != nil {
118+
return "", err
119+
}
120+
b = bytes.TrimSpace(b)
121+
return string(b), nil
122+
}
123+
124+
func latestTag(dir string) (string, error) {
125+
c := exec.Command("git", "rev-list", "--tags", "--max-count=1")
126+
c.Dir = dir
127+
b, err := c.Output()
128+
if err != nil {
129+
return "", err
130+
}
131+
commit := string(bytes.TrimSpace(b))
132+
c = exec.Command("git", "describe", "--tags", commit)
133+
c.Dir = dir
134+
b, err = c.Output()
135+
if err != nil {
136+
return "", err
137+
}
138+
b = bytes.TrimSpace(b)
139+
return string(b), nil
140+
}
141+
142+
func gitFilesChanges(dir string) ([]string, error) {
143+
c := exec.Command("git", "diff", "--name-only", "origin/master")
144+
c.Dir = dir
145+
b, err := c.Output()
146+
if err != nil {
147+
return nil, err
148+
}
149+
b = bytes.TrimSpace(b)
150+
log.Printf("Files changed:\n%s", b)
151+
return strings.Split(string(b), "\n"), nil
152+
}

internal/actions/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module cloud.google.com/go/internal/actions
2+
3+
go 1.16

0 commit comments

Comments
 (0)