|
1 | 1 | """ |
2 | | -Bazel maintenance tasks. |
| 2 | +Renovate maintenance tasks. |
3 | 3 |
|
4 | 4 | The first task here, ``refresh_archive_hashes``, is the companion to the |
5 | 5 | Renovate auto-bump flow for native deps pinned via ``http_archive(...)`` in |
|
21 | 21 | import urllib.request |
22 | 22 | from pathlib import Path |
23 | 23 |
|
24 | | -from invoke import task |
25 | 24 | from invoke.context import Context |
26 | 25 | from invoke.exceptions import Exit |
| 26 | +from invoke.tasks import task |
27 | 27 |
|
28 | 28 | REPO_ROOT = Path(__file__).resolve().parent.parent |
29 | 29 | MODULE_FILE = REPO_ROOT / "deps" / "repos.MODULE.bazel" |
|
46 | 46 | URL_LITERAL_RE = re.compile(r'"(https?://[^"\s]+)"') |
47 | 47 |
|
48 | 48 |
|
| 49 | +@task( |
| 50 | + help={ |
| 51 | + "base_ref": "Git ref to compare against to detect changed http_archive blocks. " |
| 52 | + "Defaults to origin/main, which suits the bazel-native-tidy workflow. " |
| 53 | + "For local testing pass HEAD~1 or any other ref." |
| 54 | + } |
| 55 | +) |
| 56 | +def refresh_archive_hashes(ctx: Context, base_ref: str = "origin/main") -> None: |
| 57 | + """ |
| 58 | + Recompute sha256 for any http_archive in deps/repos.MODULE.bazel whose |
| 59 | + version literal differs from ``base_ref``. |
| 60 | +
|
| 61 | + Used by ``.github/workflows/bazel-native-tidy.yml`` after Renovate bumps a |
| 62 | + version. Renovate cannot refresh ``sha256`` itself; this task downloads the |
| 63 | + new tarball from the first reachable URL, hashes it, and rewrites the |
| 64 | + source so the next Bazel build verifies cleanly. |
| 65 | + """ |
| 66 | + current_text = MODULE_FILE.read_text() |
| 67 | + current_blocks = _parse_archive_blocks(current_text) |
| 68 | + |
| 69 | + result = ctx.run(f"git show {base_ref}:deps/repos.MODULE.bazel", hide=True, warn=True) |
| 70 | + if not result.ok: |
| 71 | + raise Exit(f"Could not read deps/repos.MODULE.bazel at {base_ref!r}: {result.stderr.strip()}") |
| 72 | + previous_blocks = _parse_archive_blocks(result.stdout) |
| 73 | + |
| 74 | + needs_refresh: list[str] = [] |
| 75 | + for name, body in current_blocks.items(): |
| 76 | + prev = previous_blocks.get(name) |
| 77 | + if prev is None: |
| 78 | + # New http_archive added in this PR — initial sha256 is the human's job. |
| 79 | + continue |
| 80 | + if _block_signature(body) != _block_signature(prev): |
| 81 | + needs_refresh.append(name) |
| 82 | + |
| 83 | + if not needs_refresh: |
| 84 | + print("No http_archive blocks need sha256 refresh.") |
| 85 | + return |
| 86 | + |
| 87 | + print(f"Refreshing sha256 for {len(needs_refresh)} block(s): {', '.join(needs_refresh)}") |
| 88 | + new_text = current_text |
| 89 | + for name in needs_refresh: |
| 90 | + body = _parse_archive_blocks(new_text)[name] |
| 91 | + urls = _extract_urls(body) |
| 92 | + if not urls: |
| 93 | + print(f" ! {name}: skipping — no literal URL found in block") |
| 94 | + continue |
| 95 | + old_sha = _extract_sha256(body) |
| 96 | + print(f" → {name}: downloading from {urls[0]}") |
| 97 | + new_sha = _download_and_hash(urls) |
| 98 | + if new_sha == old_sha: |
| 99 | + print(f" sha256 unchanged ({old_sha[:12]}...)") |
| 100 | + continue |
| 101 | + new_text = _replace_sha256_in_block(new_text, name, new_sha) |
| 102 | + print(f" sha256 {old_sha[:12]}... -> {new_sha[:12]}...") |
| 103 | + |
| 104 | + if new_text != current_text: |
| 105 | + MODULE_FILE.write_text(new_text) |
| 106 | + print(f"Updated {MODULE_FILE.relative_to(REPO_ROOT)}.") |
| 107 | + else: |
| 108 | + print("No sha256 values changed.") |
| 109 | + |
| 110 | + |
49 | 111 | def _parse_archive_blocks(text: str) -> dict[str, str]: |
50 | 112 | """Return a mapping of http_archive name -> raw block body.""" |
51 | 113 | blocks: dict[str, str] = {} |
@@ -111,65 +173,3 @@ def repl(match: re.Match[str]) -> str: |
111 | 173 | if count == 0: |
112 | 174 | raise Exit(f"Could not locate http_archive block for {archive_name!r}") |
113 | 175 | return new_text |
114 | | - |
115 | | - |
116 | | -@task( |
117 | | - help={ |
118 | | - "base_ref": "Git ref to compare against to detect changed http_archive blocks. " |
119 | | - "Defaults to origin/main, which suits the bazel-native-tidy workflow. " |
120 | | - "For local testing pass HEAD~1 or any other ref." |
121 | | - } |
122 | | -) |
123 | | -def refresh_archive_hashes(ctx: Context, base_ref: str = "origin/main") -> None: |
124 | | - """ |
125 | | - Recompute sha256 for any http_archive in deps/repos.MODULE.bazel whose |
126 | | - version literal differs from ``base_ref``. |
127 | | -
|
128 | | - Used by ``.github/workflows/bazel-native-tidy.yml`` after Renovate bumps a |
129 | | - version. Renovate cannot refresh ``sha256`` itself; this task downloads the |
130 | | - new tarball from the first reachable URL, hashes it, and rewrites the |
131 | | - source so the next Bazel build verifies cleanly. |
132 | | - """ |
133 | | - current_text = MODULE_FILE.read_text() |
134 | | - current_blocks = _parse_archive_blocks(current_text) |
135 | | - |
136 | | - result = ctx.run(f"git show {base_ref}:deps/repos.MODULE.bazel", hide=True, warn=True) |
137 | | - if not result.ok: |
138 | | - raise Exit(f"Could not read deps/repos.MODULE.bazel at {base_ref!r}: {result.stderr.strip()}") |
139 | | - previous_blocks = _parse_archive_blocks(result.stdout) |
140 | | - |
141 | | - needs_refresh: list[str] = [] |
142 | | - for name, body in current_blocks.items(): |
143 | | - prev = previous_blocks.get(name) |
144 | | - if prev is None: |
145 | | - # New http_archive added in this PR — initial sha256 is the human's job. |
146 | | - continue |
147 | | - if _block_signature(body) != _block_signature(prev): |
148 | | - needs_refresh.append(name) |
149 | | - |
150 | | - if not needs_refresh: |
151 | | - print("No http_archive blocks need sha256 refresh.") |
152 | | - return |
153 | | - |
154 | | - print(f"Refreshing sha256 for {len(needs_refresh)} block(s): {', '.join(needs_refresh)}") |
155 | | - new_text = current_text |
156 | | - for name in needs_refresh: |
157 | | - body = _parse_archive_blocks(new_text)[name] |
158 | | - urls = _extract_urls(body) |
159 | | - if not urls: |
160 | | - print(f" ! {name}: skipping — no literal URL found in block") |
161 | | - continue |
162 | | - old_sha = _extract_sha256(body) |
163 | | - print(f" → {name}: downloading from {urls[0]}") |
164 | | - new_sha = _download_and_hash(urls) |
165 | | - if new_sha == old_sha: |
166 | | - print(f" sha256 unchanged ({old_sha[:12]}...)") |
167 | | - continue |
168 | | - new_text = _replace_sha256_in_block(new_text, name, new_sha) |
169 | | - print(f" sha256 {old_sha[:12]}... -> {new_sha[:12]}...") |
170 | | - |
171 | | - if new_text != current_text: |
172 | | - MODULE_FILE.write_text(new_text) |
173 | | - print(f"Updated {MODULE_FILE.relative_to(REPO_ROOT)}.") |
174 | | - else: |
175 | | - print("No sha256 values changed.") |
0 commit comments