diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index efc2696f8f..b07a238d67 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -215,8 +215,7 @@ func main() { } optional := fileFeatures(*nextFile) exception := fileFeatures(*exceptFile) - fail = !compareAPI(bw, features, required, optional, exception, - *allowNew && strings.Contains(runtime.Version(), "devel")) + fail = !compareAPI(bw, features, required, optional, exception, *allowNew) } // export emits the exported package features. diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index 8c9fb723a5..81979de191 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -10,8 +10,11 @@ package main import ( + "errors" "fmt" exec "internal/execabs" + "internal/goversion" + "io/fs" "log" "os" "path/filepath" @@ -43,6 +46,7 @@ func main() { apiDir := filepath.Join(goroot, "api") out, err := exec.Command(goCmd(), "tool", "api", "-c", findAPIDirFiles(apiDir), + allowNew(apiDir), "-next", filepath.Join(apiDir, "next.txt"), "-except", filepath.Join(apiDir, "except.txt")).CombinedOutput() if err != nil { @@ -71,3 +75,35 @@ func findAPIDirFiles(apiDir string) string { } return strings.Join(apiFiles, ",") } + +// allowNew returns the -allow_new flag to use for the 'go tool api' invocation. +func allowNew(apiDir string) string { + // Verify that the api/go1.n.txt for previous Go version exists. + // It definitely should, otherwise it's a signal that the logic below may be outdated. + if _, err := os.Stat(filepath.Join(apiDir, fmt.Sprintf("go1.%d.txt", goversion.Version-1))); err != nil { + log.Fatalln("Problem with api file for previous release:", err) + } + + // See whether the api/go1.n.txt for this Go version has been created. + // (As of April 2021, it gets created during the release of the first Beta.) + _, err := os.Stat(filepath.Join(apiDir, fmt.Sprintf("go1.%d.txt", goversion.Version))) + if errors.Is(err, fs.ErrNotExist) { + // It doesn't exist, so we're in development or before Beta 1. + // At this stage, unmentioned API additions are deemed okay. + // (They will be quietly shown in API check output, but the test won't fail). + return "-allow_new=true" + } else if err == nil { + // The api/go1.n.txt for this Go version has been created, + // so we're definitely past Beta 1 in the release cycle. + // + // From this point, enforce that api/go1.n.txt is an accurate and complete + // representation of what's going into the release by failing API check if + // there are API additions (a month into the freeze, there shouldn't be many). + // + // See golang.org/issue/43956. + return "-allow_new=false" + } else { + log.Fatal(err) + } + panic("unreachable") +}