diff --git a/cmd/versions/main_test.go b/cmd/versions/main_test.go index 8c51614..d824ea1 100644 --- a/cmd/versions/main_test.go +++ b/cmd/versions/main_test.go @@ -39,7 +39,7 @@ func TestTheCommandsAnswerFromTheFile(t *testing.T) { source: https://cdn.kernel.org/pub/linux/kernel/v{major}.x/linux-{version}.tar.xz version: 7.2.8 pin: 1111111111111111111111111111111111111111111111111111111111111111 - track: kernel-stable + track: kernel `), 0o600)) for name, tc := range map[string]struct { argv []string @@ -88,7 +88,7 @@ func TestOneEntrySaysWhatItsKindHas(t *testing.T) { source: https://git.kernel.org/torvalds/t/linux-{version}.tar.gz version: 7.3-rc5 pin: 1111111111111111111111111111111111111111111111111111111111111111 - track: kernel-stable + track: kernel - name: alpine kind: image source: alpine diff --git a/site/src/content/docs/versions.md b/site/src/content/docs/versions.md index 2509d2a..523996a 100644 --- a/site/src/content/docs/versions.md +++ b/site/src/content/docs/versions.md @@ -23,7 +23,7 @@ date. source: https://cdn.kernel.org/pub/linux/kernel/v{major}.x/linux-{version}.tar.xz version: 7.2.8 pin: 12e8d5a973d1... # the file's sha256 - track: kernel-stable + track: kernel note: what a bump has to be checked with. - name: debian diff --git a/site/src/content/docs/versions/reference.md b/site/src/content/docs/versions/reference.md index 39226ae..601ac78 100644 --- a/site/src/content/docs/versions/reference.md +++ b/site/src/content/docs/versions/reference.md @@ -35,8 +35,7 @@ description: Every kind of entry versions.yaml takes, the build arguments each b | `tags ` | the highest release-numbered tag of a git repository; for a download, the highest whose file is published | | `commit ` | the commit a branch is at, for a download whose version is a commit: behind only when the file changed | | `go` | the newest stable Go, spelled as the tag is (`1.27.1-trixie`) | -| `kernel-stable` | the newest release of the same stable series; a series that has ended is for a person to decide | -| `kernel-mainline` | the newest series Linus released (`7.3`), its first tarball: no stable fixes, and while mainline is at an -rc, the series before it | +| `kernel` | the newest release of the pinned series; moving to another series is naming it (`versions bump kernel 7.4.1`), and a series kernel.org no longer lists is reported and the pin stays | | `digest` | the same tag: behind when it names another image | | `branch` | the same branch: behind when it is at another commit | | `pypi` | the package's newest on PyPI | diff --git a/versions/gate/gate_test.go b/versions/gate/gate_test.go index 7afc603..4dec4b2 100644 --- a/versions/gate/gate_test.go +++ b/versions/gate/gate_test.go @@ -39,7 +39,7 @@ func TestTheGateSaysWhereAPinIsNotVersionsYAMLs(t *testing.T) { good := func() map[string]string { return map[string]string{ versions.File: "- name: kernel\n kind: download\n source: https://x/{version}\n version: '1'\n pin: " + strings.Repeat("a", 64) + - "\n track: kernel-stable\n- name: go\n kind: image\n source: golang\n version: '1'\n pin: sha256:" + strings.Repeat("b", 64) + "\n track: go\n", + "\n track: kernel\n- name: go\n kind: image\n source: golang\n version: '1'\n pin: sha256:" + strings.Repeat("b", 64) + "\n track: go\n", "Taskfile.yml": "cmds:\n - docker build $(go tool versions args kernel) .\n - '{{.VERSIONS}} ref go'\n", "kernel/Dockerfile": "ARG KERNEL_VERSION\nARG KERNEL_SHA256\nFROM scratch\n", // Written by other tools, or by a build: not the gate's. diff --git a/versions/upstream/upstream.go b/versions/upstream/upstream.go index bca2f62..5f8aed5 100644 --- a/versions/upstream/upstream.go +++ b/versions/upstream/upstream.go @@ -31,6 +31,10 @@ import ( // errFollows is an entry whose newest version is another's to say: a person reads it there. var errFollows = errors.New("versions: follows another") +// errSeriesOver is a kernel whose series kernel.org no longer lists: check says so, and a bump +// leaves the pin where it is, so a refresh goes on with its other entries. +var errSeriesOver = errors.New("the series is over: the pin stays until a person names another") + // newest is the version check says e could be at: the same for an image tracked by its digest, // or a branch, whose pin is what moves. func newest(ctx context.Context, e versions.Entry) (string, error) { @@ -49,18 +53,12 @@ func newest(ctx context.Context, e versions.Entry) (string, error) { return tag, err case "go": return newestGo(ctx, e.Version) - case "kernel-stable": - releases, err := kernelReleases(ctx) - if err != nil { - return "", err - } - return kernelStable(e.Version, releases) - case "kernel-mainline": + case "kernel": releases, err := kernelReleases(ctx) if err != nil { return "", err } - return kernelMainline(releases) + return kernelSeries(e.Version, releases) case "digest", "branch": return e.Version, nil case "tags": @@ -147,7 +145,11 @@ func Bump(ctx context.Context, v *versions.Versions, name, version string) (vers return versions.Entry{}, nil, fmt.Errorf("versions: %s's archive is what a build's git writes of the commit, so it is bumped by hand: see its note", name) } if version == "" { - if version, err = newest(ctx, e); err != nil { + version, err = newest(ctx, e) + switch { + case errors.Is(err, errSeriesOver): + version = e.Version + case err != nil: return versions.Entry{}, nil, fmt.Errorf("%w; name the version", err) } } @@ -389,44 +391,21 @@ func kernelReleases(ctx context.Context) ([]kernelRelease, error) { return doc.Releases, nil } -// kernelStable is the newest release of version's series, 7.2 for 7.2.8. -func kernelStable(version string, releases []kernelRelease) (string, error) { +// kernelSeries is the newest release of version's series: 7.3.1 for 7.3, and the series itself +// while its first tarball is all there is. An -rc of it has no tarball. +func kernelSeries(version string, releases []kernelRelease) (string, error) { major, rest, _ := strings.Cut(version, ".") minor, _, _ := strings.Cut(rest, ".") if minor == "" { return "", fmt.Errorf("versions: %q is not a kernel release", version) } - series := major + "." + minor + "." + series := major + "." + minor for _, r := range releases { - if r.Moniker != "mainline" && strings.HasPrefix(r.Version, series) { + if r.Version == series || strings.HasPrefix(r.Version, series+".") { return r.Version, nil } } - return "", fmt.Errorf("versions: kernel.org lists no %sx: the series is over, and moving to another is a decision, not a bump", series) -} - -// kernelMainline is the newest X.Y Linus released. While mainline is at a release candidate, -// which has no tarball on cdn.kernel.org, that is the series stable carries: 7.3 for 7.4-rc2 -// beside 7.3.2. -func kernelMainline(releases []kernelRelease) (string, error) { - var newest []int - for _, r := range releases { - if r.Moniker == "linux-next" { - continue - } - // An -rc is no number, and 7.3.2 is of 7.3: the series is the first two. - n, err := numbers(r.Version) - if err != nil || len(n) < 2 { - continue - } - if slices.Compare(n[:2], newest) > 0 { - newest = n[:2] - } - } - if newest == nil { - return "", errors.New("versions: kernel.org lists no released kernel") - } - return fmt.Sprintf("%d.%d", newest[0], newest[1]), nil + return "", fmt.Errorf("versions: kernel.org lists no %s.x: %w", series, errSeriesOver) } // Status is one entry as check finds it. diff --git a/versions/upstream/upstream_test.go b/versions/upstream/upstream_test.go index e37b819..a048b3c 100644 --- a/versions/upstream/upstream_test.go +++ b/versions/upstream/upstream_test.go @@ -187,57 +187,38 @@ func TestAPinnedDownloadIsOnlyThePinnedBytes(t *testing.T) { } } -// Mainline is the newest X.Y Linus released: a release candidate has no tarball, so while one is -// mainline the newest is the series stable carries, and linux-next is never one. -func TestKernelMainlineIsTheNewestRelease(t *testing.T) { - for name, tc := range map[string]struct { - releases []kernelRelease - want string // "" is an error - }{ - "mainline released": {[]kernelRelease{{"7.3", "mainline"}, {"7.2.13", "stable"}, {"6.18.59", "longterm"}, {"next-20261029", "linux-next"}}, "7.3"}, - "mainline at an rc": {[]kernelRelease{{"7.4-rc2", "mainline"}, {"7.3.2", "stable"}, {"7.2.14", "stable"}}, "7.3"}, - "a later major": {[]kernelRelease{{"8.0", "mainline"}, {"7.9.4", "stable"}}, "8.0"}, - "nothing released": {[]kernelRelease{{"8.0-rc1", "mainline"}, {"next-20261029", "linux-next"}}, ""}, - "a bare major": {[]kernelRelease{{"8", "mainline"}, {"7.9.4", "stable"}}, "7.9"}, - } { - t.Run(name, func(t *testing.T) { - got, err := kernelMainline(tc.releases) - if tc.want == "" && err == nil { - t.Fatalf("newest %q, want an error", got) - } - if tc.want != "" && (err != nil || got != tc.want) { - t.Errorf("newest %q, %v; want %q", got, err, tc.want) - } - }) - } -} - -// Stable is the newest of the pinned series past mainline: a series mainline alone lists, or none -// does, is over. -func TestKernelStableIsTheNewestOfTheSeries(t *testing.T) { - releases := []kernelRelease{{"7.3", "mainline"}, {"7.2.13", "stable"}, {"6.18.59", "longterm"}} +// A kernel stays in the series it is pinned in, whatever else kernel.org has released, and a series +// nothing lists is over rather than a failure to read kernel.org. +func TestKernelStaysInItsSeries(t *testing.T) { + releases := []kernelRelease{{"7.4-rc1", "mainline"}, {"7.3.1", "stable"}, {"7.2.15", "stable"}, {"6.18.60", "longterm"}, {"next-20261029", "linux-next"}} for version, want := range map[string]string{ - "7.2.8": "7.2.13", "6.18": "6.18.59", - "7.3": "", "7.1.4": "", "7": "", + "7.3": "7.3.1", "7.3.1": "7.3.1", "7.2.8": "7.2.15", "6.18": "6.18.60", } { - got, err := kernelStable(version, releases) - if want == "" && err == nil { - t.Errorf("%s: newest %q, want an error", version, got) - } - if want != "" && (err != nil || got != want) { + if got, err := kernelSeries(version, releases); err != nil || got != want { t.Errorf("%s: newest %q, %v; want %q", version, got, err, want) } } + // Its first tarball, while mainline alone lists it. + if got, err := kernelSeries("7.4", []kernelRelease{{"7.4", "mainline"}, {"7.3.9", "stable"}}); err != nil || got != "7.4" { + t.Errorf("a first tarball: newest %q, %v", got, err) + } + // 7.4-rc1 is no release of 7.4, and 7.1 is none of 7.15's. + for _, version := range []string{"7.4", "7.1.4"} { + if got, err := kernelSeries(version, append(releases, kernelRelease{"7.15.2", "stable"})); !errors.Is(err, errSeriesOver) { + t.Errorf("%s: newest %q, %v; want the series over", version, got, err) + } + } + if _, err := kernelSeries("7", releases); err == nil || errors.Is(err, errSeriesOver) { + t.Errorf("a bare major: %v, want refused as no release", err) + } } -// Either kernel track says it could not read kernel.org, not that kernel.org lists nothing. -func TestAKernelTrackSaysKernelOrgDidNotAnswer(t *testing.T) { +// A kernel says it could not read kernel.org, not that kernel.org lists nothing. +func TestAKernelSaysKernelOrgDidNotAnswer(t *testing.T) { ctx, cancel := context.WithCancel(t.Context()) cancel() - for _, track := range []string{"kernel-stable", "kernel-mainline"} { - _, err := newest(ctx, versions.Entry{Version: "7.2.8", Track: track}) - if !errors.Is(err, context.Canceled) { - t.Errorf("%s: %v, want kernel.org's request's error", track, err) - } + _, err := newest(ctx, versions.Entry{Version: "7.2.8", Track: "kernel"}) + if !errors.Is(err, context.Canceled) { + t.Errorf("%v, want kernel.org's request's error", err) } }