github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/build v0.0.0-20240122184708-c291ad69d6be h1:h1qJlb1MudWuUMYotaFX+nSdSgv6zrBBDNojV68uqCA=
-golang.org/x/build v0.0.0-20240122184708-c291ad69d6be/go.mod h1:RHSzqFUzT4+buJlGik6WptO5NxLQiR/ewD2uz3fgWuA=
+golang.org/x/build v0.0.0-20240201175143-3ee44a092755 h1:irSM9p93GT4I3+Pu/grZlkwIjrXA3GfyKwlSosVbmtU=
+golang.org/x/build v0.0.0-20240201175143-3ee44a092755/go.mod h1:RHSzqFUzT4+buJlGik6WptO5NxLQiR/ewD2uz3fgWuA=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
// Check that each file in api/next has corresponding release note files in doc/next.
func TestCheckAPIFragments(t *testing.T) {
- t.Skip("impossibly confusing error messages")
if !*flagCheck {
t.Skip("-check not specified")
}
docFS := os.DirFS(filepath.Join(root, "doc", "next"))
// Check that each api/next file has a corresponding release note fragment.
for _, apiFile := range files {
- if err := relnote.CheckAPIFile(rootFS, apiFile, docFS); err != nil {
+ if err := relnote.CheckAPIFile(rootFS, apiFile, docFS, "doc/next"); err != nil {
t.Errorf("%s: %v", apiFile, err)
}
}
// CheckFragment reports problems in a release-note fragment.
func CheckFragment(data string) error {
doc := NewParser().Parse(data)
- if len(doc.Blocks) == 0 {
- return errors.New("empty content")
- }
// Check that the content of the document contains either a TODO or at least one sentence.
- txt := text(doc)
+ txt := ""
+ if len(doc.Blocks) > 0 {
+ txt = text(doc)
+ }
if !strings.Contains(txt, "TODO") && !strings.ContainsAny(txt, ".?!") {
- return errors.New("needs a TODO or a sentence")
+ return errors.New("File must contain a complete sentence or a TODO.")
}
return nil
}
// CheckAPIFile reads the api file at filename in apiFS, and checks the corresponding
// release-note files under docFS. It checks that the files exist and that they have
// some minimal content (see [CheckFragment]).
-func CheckAPIFile(apiFS fs.FS, filename string, docFS fs.FS) error {
+// The docRoot argument is the path from the repo or project root to the root of docFS.
+// It is used only for error messages.
+func CheckAPIFile(apiFS fs.FS, filename string, docFS fs.FS, docRoot string) error {
features, err := parseAPIFile(apiFS, filename)
if err != nil {
return err
filenames = append(filenames, fn)
}
slices.Sort(filenames)
+ mcDir, err := minorChangesDir(docFS)
+ if err != nil {
+ return err
+ }
var errs []error
- for _, filename := range filenames {
+ for _, fn := range filenames {
+ // Use path.Join for consistency with io/fs pathnames.
+ fn = path.Join(mcDir, fn)
// TODO(jba): check that the file mentions each feature?
- if err := checkFragmentFile(docFS, filename); err != nil {
- errs = append(errs, fmt.Errorf("%s: %v", filename, err))
+ if err := checkFragmentFile(docFS, fn); err != nil {
+ errs = append(errs, fmt.Errorf("%s: %v\nSee doc/README.md for more information.", path.Join(docRoot, fn), err))
}
}
return errors.Join(errs...)
}
+// minorChangesDir returns the unique directory in docFS that corresponds to the
+// "Minor changes to the standard library" section of the release notes.
+func minorChangesDir(docFS fs.FS) (string, error) {
+ dirs, err := fs.Glob(docFS, "*stdlib/*minor")
+ if err != nil {
+ return "", err
+ }
+ var bad string
+ if len(dirs) == 0 {
+ bad = "No"
+ } else if len(dirs) > 1 {
+ bad = "More than one"
+ }
+ if bad != "" {
+ return "", fmt.Errorf("%s directory matches *stdlib/*minor.\nThis shouldn't happen; please file a bug at https://go.dev/issues/new.",
+ bad)
+ }
+ return dirs[0], nil
+}
+
func checkFragmentFile(fsys fs.FS, filename string) error {
f, err := fsys.Open(filename)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
- err = fs.ErrNotExist
+ err = errors.New("File does not exist. Every API change must have a corresponding release note file.")
}
return err
}