Skip to content

Commit 49f497e

Browse files
authored
feat(internal): auto-run godocfx on new mods (#3069)
This uses index.golang.org to list all modules since a given time. For example, see https://index.golang.org/index?since=2019-04-10T19:08:52.997264Z. Each page is listed in chronological order and is limited to 2000 entries (as of today). This stores the last successful time in Datastore. If there is no time in Datastore, it defaults to 10 days ago. There is a bit of indirection with interfaces to enable testing. In the future, we should add the ability to regenerate the YAML for the latest version of all modules. cc @julieqiu @katiehockman
1 parent 4c538f4 commit 49f497e

10 files changed

Lines changed: 373 additions & 60 deletions

File tree

RELEASING.md

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,6 @@ the failures have been resolved.
8888
`git push origin $NV`
8989
1. Update [the releases page](https://github.com/googleapis/google-cloud-go/releases)
9090
with the new release, copying the contents of `CHANGES.md`.
91-
1. Run `go get cloud.google.com/go@vX.Y.Z` then wait for the release
92-
to show up on http://pkg.go.dev/cloud.google.com/go (a few minutes).
93-
1. Go to the [doc publishing job](http://go/google-cloud-go-publish-docs) and
94-
trigger the job with the following environment variables:
95-
`MODULE=cloud.google.com,VERSION=vX.Y.Z`.
96-
Replace the version with the value for the module you're
97-
releasing. See [`publish_docs.sh`](/internal/kokoro/publish_docs.sh).
9891

9992
# How to release a submodule
10093

@@ -131,15 +124,6 @@ To release a submodule:
131124
`git push origin $NV`
132125
1. Update [the releases page](https://github.com/googleapis/google-cloud-go/releases)
133126
with the new release, copying the contents of `datastore/CHANGES.md`.
134-
1. Run `go get cloud.google.com/go/datastore@vX.Y.Z` then wait for the release
135-
to show up on http://pkg.go.dev/cloud.google.com/go/datastore (a few
136-
minutes).
137-
1. Go to the [doc publishing job](http://go/google-cloud-go-publish-docs) and
138-
trigger the job with the following environment variables:
139-
`MODULE=cloud.google.com/go/datastore,VERSION=vX.Y.Z`.
140-
Replace the module path and version with the values for the module you're
141-
releasing. You can leave all of the other fields blank.
142-
See [`publish_docs.sh`](/internal/kokoro/publish_docs.sh).
143127

144128
# Appendix
145129

internal/godocfx/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.15
55
require (
66
cloud.google.com/go v0.70.0
77
cloud.google.com/go/bigquery v1.8.0
8+
cloud.google.com/go/datastore v1.1.0
89
cloud.google.com/go/storage v1.11.0
910
github.com/kr/pretty v0.2.1 // indirect
1011
golang.org/x/tools v0.0.0-20201021122455-2be66b663cb6

internal/godocfx/go.sum

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m
283283
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
284284
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
285285
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
286-
google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952 h1:y857ZwFJ60XFsJ00vOc7ouVMLOZp7C+7h03pESkILFY=
287286
google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
288287
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
289288
google.golang.org/genproto v0.0.0-20201021134325-0d71844de594 h1:JZWUHUjZJojCHxs9ZZLFsnRGKVBXBoOHGxeTSt6OE+Q=

internal/godocfx/godocfx_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestMain(m *testing.M) {
3737

3838
func TestParse(t *testing.T) {
3939
mod := "cloud.google.com/go/bigquery"
40-
r, err := parse(mod+"/...", []string{"README.md"})
40+
r, err := parse(mod+"/...", ".", []string{"README.md"})
4141
if err != nil {
4242
t.Fatalf("Parse: %v", err)
4343
}
@@ -103,7 +103,7 @@ func TestGoldens(t *testing.T) {
103103
extraFiles := []string{"README.md"}
104104

105105
testPath := "cloud.google.com/go/storage"
106-
r, err := parse(testPath, extraFiles)
106+
r, err := parse(testPath, ".", extraFiles)
107107
if err != nil {
108108
t.Fatalf("parse: %v", err)
109109
}

internal/godocfx/index.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright 2020 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+
// +build go1.15
16+
17+
package main
18+
19+
import (
20+
"bufio"
21+
"context"
22+
"encoding/json"
23+
"log"
24+
"net/http"
25+
"strings"
26+
"time"
27+
)
28+
29+
// indexer gets a limited list of entries from index.golang.org.
30+
type indexer interface {
31+
get(prefix string, since time.Time) (entries []indexEntry, last time.Time, err error)
32+
}
33+
34+
// indexClient is used to access index.golang.org.
35+
type indexClient struct{}
36+
37+
var _ indexer = indexClient{}
38+
39+
// indexEntry represents a line in the output of index.golang.org/index.
40+
type indexEntry struct {
41+
Path string
42+
Version string
43+
Timestamp time.Time
44+
}
45+
46+
// newModules returns the new modules with the given prefix.
47+
//
48+
// newModules uses index.golang.org/index?since=timestamp to find new module
49+
// versions since the given timestamp.
50+
//
51+
// newModules stores the timestamp of the last successful run with tSaver.
52+
func newModules(ctx context.Context, i indexer, tSaver timeSaver, prefix string) ([]indexEntry, error) {
53+
since, err := tSaver.get(ctx)
54+
if err != nil {
55+
return nil, err
56+
}
57+
fiveMinAgo := time.Now().Add(-5 * time.Minute).UTC() // When to stop processing.
58+
entries := []indexEntry{}
59+
log.Printf("Fetching index.golang.org entries since %s", since.Format(time.RFC3339))
60+
count := 0
61+
for {
62+
count++
63+
var cur []indexEntry
64+
cur, since, err = i.get(prefix, since)
65+
if err != nil {
66+
return nil, err
67+
}
68+
entries = append(entries, cur...)
69+
if since.After(fiveMinAgo) {
70+
break
71+
}
72+
}
73+
log.Printf("Parsed %d index.golang.org pages up to %s", count, since.Format(time.RFC3339))
74+
if err := tSaver.put(ctx, since); err != nil {
75+
return nil, err
76+
}
77+
78+
return entries, nil
79+
}
80+
81+
// get fetches a single chronological page of modules from
82+
// index.golang.org/index.
83+
func (indexClient) get(prefix string, since time.Time) ([]indexEntry, time.Time, error) {
84+
entries := []indexEntry{}
85+
sinceString := since.Format(time.RFC3339)
86+
resp, err := http.Get("https://index.golang.org/index?since=" + sinceString)
87+
if err != nil {
88+
return nil, time.Time{}, err
89+
}
90+
91+
s := bufio.NewScanner(resp.Body)
92+
last := time.Time{}
93+
for s.Scan() {
94+
e := indexEntry{}
95+
if err := json.Unmarshal(s.Bytes(), &e); err != nil {
96+
return nil, time.Time{}, err
97+
}
98+
last = e.Timestamp // Always update the last timestamp.
99+
if !strings.HasPrefix(e.Path, prefix) ||
100+
strings.Contains(e.Path, "internal") ||
101+
strings.Contains(e.Path, "third_party") ||
102+
strings.Contains(e.Version, "-") { // Filter out pseudo-versions.
103+
continue
104+
}
105+
entries = append(entries, e)
106+
}
107+
return entries, last, nil
108+
}

internal/godocfx/index_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2020 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+
// +build go1.15
16+
17+
package main
18+
19+
import (
20+
"context"
21+
"testing"
22+
"time"
23+
)
24+
25+
const wantEntries = 5
26+
27+
type fakeIC struct{}
28+
29+
func (f fakeIC) get(prefix string, since time.Time) (entries []indexEntry, last time.Time, err error) {
30+
e := indexEntry{Timestamp: since.Add(24 * time.Hour)}
31+
return []indexEntry{e}, e.Timestamp, nil
32+
}
33+
34+
type fakeTS struct {
35+
getCalled, putCalled bool
36+
}
37+
38+
func (f *fakeTS) get(context.Context) (time.Time, error) {
39+
f.getCalled = true
40+
t := time.Now().Add(-wantEntries * 24 * time.Hour).UTC()
41+
return t, nil
42+
}
43+
44+
func (f *fakeTS) put(context.Context, time.Time) error {
45+
f.putCalled = true
46+
return nil
47+
}
48+
49+
func TestNewModules(t *testing.T) {
50+
ic := fakeIC{}
51+
ts := &fakeTS{}
52+
entries, err := newModules(context.Background(), ic, ts, "cloud.google.com")
53+
if err != nil {
54+
t.Fatalf("newModules got err: %v", err)
55+
}
56+
if got, want := len(entries), wantEntries; got != want {
57+
t.Errorf("newModules got %d entries, want %d", got, want)
58+
}
59+
if !ts.getCalled {
60+
t.Errorf("fakeTS.get was never called")
61+
}
62+
if !ts.putCalled {
63+
t.Errorf("fakeTS.put was never called")
64+
}
65+
}

0 commit comments

Comments
 (0)