diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdad2bca566f..618fd2179491 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,10 +60,25 @@ jobs: if [[ -n '${{ secrets.PUSH_NIGHTLY_TOKEN }}' ]]; then git remote add nightly https://foo:'${{ secrets.PUSH_NIGHTLY_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-nightly.git git fetch nightly --tags - LEAN_VERSION_STRING="nightly-$(date -u +%F)" - # do nothing if commit already has a different tag - if [[ "$(git name-rev --name-only --tags --no-undefined HEAD 2> /dev/null || echo "$LEAN_VERSION_STRING")" == "$LEAN_VERSION_STRING" ]]; then + BASE_NIGHTLY="nightly-$(date -u +%F)" + if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then + # Manual re-release: find next available revision if base nightly exists + if git rev-parse "refs/tags/$BASE_NIGHTLY" >/dev/null 2>&1; then + REV=1 + while git rev-parse "refs/tags/${BASE_NIGHTLY}-rev${REV}" >/dev/null 2>&1; do + REV=$((REV + 1)) + done + LEAN_VERSION_STRING="${BASE_NIGHTLY}-rev${REV}" + else + LEAN_VERSION_STRING="$BASE_NIGHTLY" + fi echo "nightly=$LEAN_VERSION_STRING" >> "$GITHUB_OUTPUT" + else + # Scheduled: do nothing if commit already has a different tag + LEAN_VERSION_STRING="$BASE_NIGHTLY" + if [[ "$(git name-rev --name-only --tags --no-undefined HEAD 2> /dev/null || echo "$LEAN_VERSION_STRING")" == "$LEAN_VERSION_STRING" ]]; then + echo "nightly=$LEAN_VERSION_STRING" >> "$GITHUB_OUTPUT" + fi fi fi @@ -475,7 +490,7 @@ jobs: git tag "${{ needs.configure.outputs.nightly }}" git push nightly "${{ needs.configure.outputs.nightly }}" git push -f origin refs/tags/${{ needs.configure.outputs.nightly }}:refs/heads/nightly - last_tag="$(git log HEAD^ --simplify-by-decoration --pretty="format:%d" | grep -o "nightly-[-0-9]*" | head -n 1)" + last_tag="$(git log HEAD^ --simplify-by-decoration --pretty="format:%d" | grep -o "nightly-[^ ,)]*" | head -n 1)" echo -e "*Changes since ${last_tag}:*\n\n" > diff.md git show "$last_tag":RELEASES.md > old.md #./script/diff_changelogs.py old.md doc/changes.md >> diff.md diff --git a/script/lean-bisect b/script/lean-bisect index faaf4d7b5559..7ab7f93e943c 100755 --- a/script/lean-bisect +++ b/script/lean-bisect @@ -36,7 +36,7 @@ sys.path.insert(0, str(Path(__file__).parent)) import build_artifact # Constants -NIGHTLY_PATTERN = re.compile(r'^nightly-(\d{4})-(\d{2})-(\d{2})$') +NIGHTLY_PATTERN = re.compile(r'^nightly-(\d{4})-(\d{2})-(\d{2})(-rev(\d+))?$') VERSION_PATTERN = re.compile(r'^v4\.(\d+)\.(\d+)(-rc\d+)?$') # Accept short SHAs (7+ chars) - we'll resolve to full SHA later SHA_PATTERN = re.compile(r'^[0-9a-f]{7,40}$') @@ -158,7 +158,7 @@ def parse_identifier(s: str) -> Tuple[str, str]: return ('sha', full_sha) error(f"Invalid identifier format: '{s}'\n" f"Expected one of:\n" - f" - nightly-YYYY-MM-DD (e.g., nightly-2024-06-15)\n" + f" - nightly-YYYY-MM-DD or nightly-YYYY-MM-DD-revK (e.g., nightly-2024-06-15, nightly-2024-06-15-rev1)\n" f" - v4.X.Y or v4.X.Y-rcK (e.g., v4.8.0, v4.9.0-rc1)\n" f" - commit SHA (short or full)") @@ -244,8 +244,13 @@ def fetch_nightly_tags() -> List[str]: if len(data) < 100: break - # Sort by date (nightly-YYYY-MM-DD format sorts lexicographically) - tags.sort() + # Sort by date and revision (nightly-YYYY-MM-DD-revK needs numeric comparison on rev) + def nightly_sort_key(tag): + m = NIGHTLY_PATTERN.match(tag) + if m: + return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(5) or 0)) + return (0, 0, 0, 0) + tags.sort(key=nightly_sort_key) return tags def get_commit_for_nightly(nightly: str) -> str: @@ -1024,6 +1029,7 @@ Range Syntax: Identifier Formats: nightly-YYYY-MM-DD Nightly build date (e.g., nightly-2024-06-15) + nightly-YYYY-MM-DD-revK Revised nightly (e.g., nightly-2024-06-15-rev1) Uses pre-built toolchains from leanprover/lean4-nightly. Fast: downloads via elan (~30s each). @@ -1151,9 +1157,9 @@ Examples: # Validate --nightly-only if args.nightly_only: if from_val is not None and from_type != 'nightly': - error("--nightly-only requires FROM to be a nightly identifier (nightly-YYYY-MM-DD)") + error("--nightly-only requires FROM to be a nightly identifier (nightly-YYYY-MM-DD or nightly-YYYY-MM-DD-revK)") if to_type != 'nightly': - error("--nightly-only requires TO to be a nightly identifier (nightly-YYYY-MM-DD)") + error("--nightly-only requires TO to be a nightly identifier (nightly-YYYY-MM-DD or nightly-YYYY-MM-DD-revK)") if from_val: info(f"From: {from_val} ({from_type})") diff --git a/src/lake/Lake/Util/Version.lean b/src/lake/Lake/Util/Version.lean index ff44901c29e5..8e5f6abbd0d0 100644 --- a/src/lake/Lake/Util/Version.lean +++ b/src/lake/Lake/Util/Version.lean @@ -235,13 +235,14 @@ open ToolchainVer in /-- A Lean toolchain version. -/ inductive ToolchainVer | release (ver : LeanVer) -| nightly (date : Date) +| nightly (date : Date) (rev : Option Nat := none) | pr (n : Nat) | other (v : String) with @[computed_field] toString : ToolchainVer → String | .release ver => s!"{defaultOrigin}:v{ver}" - | .nightly date => s!"{defaultOrigin}:nightly-{date}" + | .nightly date rev => s!"{defaultOrigin}:nightly-{date}" ++ + match rev with | none => "" | some r => s!"-rev{r}" | .pr n => s!"{prOrigin}:pr-release-{n}" | .other v => v deriving Repr, DecidableEq @@ -264,13 +265,20 @@ public def ofString (ver : String) : ToolchainVer := Id.run do if let .ok ver := StdVer.parse (tag.drop 1).copy then if noOrigin|| origin == defaultOrigin then return .release ver - else if let some date := tag.dropPrefix? "nightly-" then - if let some date := Date.ofString? date.toString then - if noOrigin then - return .nightly date - else if let some suffix := origin.dropPrefix? defaultOrigin then - if suffix.isEmpty || suffix == "-nightly" then - return .nightly date + else if let some rest := tag.dropPrefix? "nightly-" then + let rest := rest.toString + -- Dates are exactly 10 characters (YYYY-MM-DD); anything after must be a -revK suffix + if let some date := Date.ofString? (rest.take 10).toString then + let rev? : Option Nat := do + let suffix ← (rest.drop 10).dropPrefix? "-rev" + suffix.toString.toNat? + -- Accept if no suffix (plain nightly) or valid -revK suffix + if rest.length ≤ 10 || rev?.isSome then + if noOrigin then + return .nightly date rev? + else if let some suffix := origin.dropPrefix? defaultOrigin then + if suffix.isEmpty || suffix == "-nightly" then + return .nightly date rev? else if let some n := tag.dropPrefix? "pr-release-" then if let some n := n.toNat? then if noOrigin || origin == prOrigin then @@ -301,7 +309,8 @@ public instance : FromJson ToolchainVer := ⟨(ToolchainVer.ofString <$> fromJso public def blt (a b : ToolchainVer) : Bool := match a, b with | .release v1, .release v2 => v1 < v2 - | .nightly d1, .nightly d2 => d1 < d2 + | .nightly d1 r1, .nightly d2 r2 => + d1 < d2 || (d1 == d2 && (r1.getD 0) < (r2.getD 0)) | _, _ => false public instance : LT ToolchainVer := ⟨(·.blt ·)⟩ @@ -311,7 +320,8 @@ public instance decLt (a b : ToolchainVer) : Decidable (a < b) := public def ble (a b : ToolchainVer) : Bool := match a, b with | .release v1, .release v2 => v1 ≤ v2 - | .nightly d1, .nightly d2 => d1 ≤ d2 + | .nightly d1 r1, .nightly d2 r2 => + d1 < d2 || (d1 == d2 && (r1.getD 0) ≤ (r2.getD 0)) | .pr n1, .pr n2 => n1 = n2 | .other v1, .other v2 => v1 = v2 | _, _ => false diff --git a/tests/lake/tests/updateToolchain/test.lean b/tests/lake/tests/updateToolchain/test.lean index c15208018283..d369e585acc9 100644 --- a/tests/lake/tests/updateToolchain/test.lean +++ b/tests/lake/tests/updateToolchain/test.lean @@ -12,21 +12,33 @@ def test := do IO.println "" checkParse "leanprover/lean4:v4.13.0-rc1" checkParse "leanprover/lean4:nightly-2024-09-15" + checkParse "leanprover/lean4:nightly-2024-09-15-rev1" + checkParse "nightly-2024-09-15-rev2" checkParse "leanprover/lean4-pr-releases:pr-release-101" checkParse "leanprover/lean:v4.1.0" checkParse "4.12.0" + checkParse "nightly-2024-09-15-foo" -- malformed suffix → .other checkLt "4.6.0-rc1" "v4.6.0" checkLt "4.12.0" "leanprover/lean4:v4.13.0-rc1" checkLt "nightly-2024-09-08" "nightly-2024-10-09" + checkLt "nightly-2024-09-08" "nightly-2024-09-08-rev1" + checkLt "nightly-2024-09-08-rev1" "nightly-2024-09-08-rev2" + checkLt "nightly-2024-09-08-rev2" "nightly-2024-09-09" checkLt "nightly-2024-09-08" "4.0.0" /-- info: Lake.ToolchainVer.release { toSemVerCore := { major := 4, minor := 13, patch := 0 }, specialDescr := "rc1" } -Lake.ToolchainVer.nightly { year := 2024, month := 9, day := 15 } +Lake.ToolchainVer.nightly { year := 2024, month := 9, day := 15 } none +Lake.ToolchainVer.nightly { year := 2024, month := 9, day := 15 } (some 1) +Lake.ToolchainVer.nightly { year := 2024, month := 9, day := 15 } (some 2) Lake.ToolchainVer.pr 101 Lake.ToolchainVer.other "leanprover/lean:v4.1.0" Lake.ToolchainVer.release { toSemVerCore := { major := 4, minor := 12, patch := 0 }, specialDescr := "" } +Lake.ToolchainVer.other "nightly-2024-09-15-foo" +true +true +true true true true diff --git a/tests/lake/tests/updateToolchain/test.sh b/tests/lake/tests/updateToolchain/test.sh index aa688ea305ec..8cec228823e4 100755 --- a/tests/lake/tests/updateToolchain/test.sh +++ b/tests/lake/tests/updateToolchain/test.sh @@ -42,6 +42,12 @@ echo nightly-2024-10-01 > a/lean-toolchain echo nightly-2024-01-10 > b/lean-toolchain test_update leanprover/lean4:nightly-2024-10-01 +# Test nightly revision comparison +./clean.sh +echo nightly-2024-10-01-rev1 > a/lean-toolchain +echo nightly-2024-01-10 > b/lean-toolchain +test_update leanprover/lean4:nightly-2024-10-01-rev1 + # Test up-to-date root ./clean.sh echo v4.4.0 > a/lean-toolchain