Skip to content

Commit 0ef515f

Browse files
committed
chore: update version in CITATION upon release
1 parent e7672d4 commit 0ef515f

File tree

3 files changed

+175
-2
lines changed

3 files changed

+175
-2
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"update:starters": "poetry run python ./scripts/update.py",
4343
"vendor:libs": "vite build --config vite.config.js",
4444
"vendor:libs:watch": "vite build --config vite.config.js --watch",
45-
"vendor:update-and-build": "pnpm up katex mermaid markmap-autoloader alpinejs plotly.js preact --latest && pnpm vendor:libs"
45+
"vendor:update-and-build": "pnpm up katex mermaid markmap-autoloader alpinejs plotly.js preact --latest && pnpm vendor:libs",
46+
"test:releaser": "poetry run python scripts/test_release_modules.py"
4647
},
4748
"browserslist": "> 1%"
4849
}

scripts/release_modules.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,38 @@ def write_blox_tailwind_theme_version(module: Module, version: str) -> List[Path
294294
return updated
295295

296296

297+
def update_citation_release_info(module: Module, version: str) -> List[Path]:
298+
"""Update the public citation metadata to the latest blox-tailwind release."""
299+
if module.name != "blox-tailwind":
300+
return []
301+
302+
citation = REPO_ROOT / "CITATION.cff"
303+
if not citation.exists():
304+
return []
305+
306+
original = citation.read_text(encoding="utf-8")
307+
release_date = datetime.now(timezone.utc).date().isoformat()
308+
309+
updated = original
310+
version_pattern = r'(?m)^(version:\s*)"[^"]+"'
311+
if re.search(version_pattern, updated):
312+
updated = re.sub(version_pattern, rf'\g<1>"{version}"', updated)
313+
else:
314+
updated = f'{updated.rstrip()}\nversion: "{version}"\n'
315+
316+
date_pattern = r'(?m)^(date-released:\s*)(.+)$'
317+
if re.search(date_pattern, updated):
318+
updated = re.sub(date_pattern, rf"\g<1>{release_date}", updated)
319+
else:
320+
updated = f"{updated.rstrip()}\ndate-released: {release_date}\n"
321+
322+
if updated != original:
323+
citation.write_text(updated, encoding="utf-8")
324+
logging.info("updated CITATION.cff -> version %s, date %s", version, release_date)
325+
return [citation]
326+
return []
327+
328+
297329
def update_go_mod_require_version(go_mod_text: str, dep_module_path: str, new_version: str) -> str:
298330
# Replace exact require line if present
299331
# Handles both single-line require and block form
@@ -686,8 +718,9 @@ def main() -> None:
686718
go_mod_synced = update_module_requirements_to_latest(m, modules, latest_versions)
687719
if go_mod_synced:
688720
touched_files.append(go_mod_synced)
689-
# Special-case blox-tailwind theme version bump
721+
# Special-case blox-tailwind theme version bump and citation metadata
690722
touched_files.extend(write_blox_tailwind_theme_version(m, next_version))
723+
touched_files.extend(update_citation_release_info(m, next_version))
691724

692725
# Stage and commit any pre-release file changes
693726
if touched_files:

scripts/test_release_modules.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
import tempfile
5+
import unittest
6+
from pathlib import Path
7+
8+
ROOT = Path(__file__).resolve().parents[1]
9+
SCRIPTS_DIR = ROOT / "scripts"
10+
if str(SCRIPTS_DIR) not in sys.path:
11+
sys.path.insert(0, str(SCRIPTS_DIR))
12+
13+
try:
14+
import requests # type: ignore
15+
except ModuleNotFoundError:
16+
import types
17+
18+
class _DummyResponse:
19+
status_code = 0
20+
21+
def json(self):
22+
return {}
23+
24+
requests = types.SimpleNamespace(get=lambda *args, **kwargs: _DummyResponse())
25+
sys.modules["requests"] = requests
26+
27+
try:
28+
import tomlkit # type: ignore
29+
except ModuleNotFoundError:
30+
import types
31+
32+
def _noop_parse(content: str):
33+
return {}
34+
35+
def _noop_dumps(data):
36+
return ""
37+
38+
tomlkit = types.SimpleNamespace(parse=_noop_parse, dumps=_noop_dumps)
39+
sys.modules["tomlkit"] = tomlkit
40+
41+
try:
42+
from ruamel.yaml import YAML # type: ignore
43+
from ruamel.yaml.scalarstring import SingleQuotedScalarString # type: ignore
44+
except ModuleNotFoundError:
45+
import types
46+
47+
class _DummyYAML:
48+
preserve_quotes = False
49+
50+
def load(self, stream):
51+
return {}
52+
53+
def dump(self, data, stream=None):
54+
if stream and hasattr(stream, "write"):
55+
stream.write("")
56+
return ""
57+
58+
class _DummyScalarString(str):
59+
pass
60+
61+
ruamel_module = types.ModuleType("ruamel")
62+
ruamel_yaml_module = types.ModuleType("ruamel.yaml")
63+
ruamel_yaml_scalar_module = types.ModuleType("ruamel.yaml.scalarstring")
64+
ruamel_yaml_module.YAML = _DummyYAML
65+
ruamel_yaml_scalar_module.SingleQuotedScalarString = _DummyScalarString
66+
ruamel_module.yaml = ruamel_yaml_module
67+
sys.modules["ruamel"] = ruamel_module
68+
sys.modules["ruamel.yaml"] = ruamel_yaml_module
69+
sys.modules["ruamel.yaml.scalarstring"] = ruamel_yaml_scalar_module
70+
YAML = _DummyYAML
71+
SingleQuotedScalarString = _DummyScalarString
72+
73+
import release_modules
74+
75+
76+
class UpdateCitationReleaseInfoTests(unittest.TestCase):
77+
def setUp(self) -> None:
78+
self.original_repo_root = release_modules.REPO_ROOT
79+
self.original_datetime = release_modules.datetime
80+
81+
def tearDown(self) -> None:
82+
release_modules.REPO_ROOT = self.original_repo_root
83+
release_modules.datetime = self.original_datetime
84+
85+
def _patch_repo_root_with_citation(self, content: str) -> Path:
86+
tmp_dir = tempfile.TemporaryDirectory()
87+
self.addCleanup(tmp_dir.cleanup)
88+
repo_root = Path(tmp_dir.name)
89+
(repo_root / "CITATION.cff").write_text(content, encoding="utf-8")
90+
release_modules.REPO_ROOT = repo_root
91+
return repo_root
92+
93+
def test_updates_version_and_date_for_blox_tailwind(self) -> None:
94+
repo_root = self._patch_repo_root_with_citation(
95+
'version: "0.10.0"\ndate-released: 2024-01-01\n',
96+
)
97+
98+
original_datetime = release_modules.datetime
99+
100+
class FixedDatetime(original_datetime):
101+
@classmethod
102+
def now(cls, tz=None):
103+
return cls(2024, 2, 3, tzinfo=tz)
104+
105+
release_modules.datetime = FixedDatetime
106+
107+
module = release_modules.Module(
108+
name="blox-tailwind",
109+
rel_dir=Path("modules/blox-tailwind"),
110+
module_path="modules/blox-tailwind",
111+
major=0,
112+
)
113+
114+
updated_paths = release_modules.update_citation_release_info(module, "1.2.3")
115+
self.assertEqual(updated_paths, [repo_root / "CITATION.cff"])
116+
117+
contents = (repo_root / "CITATION.cff").read_text(encoding="utf-8")
118+
self.assertIn('version: "1.2.3"', contents)
119+
self.assertIn("date-released: 2024-02-03", contents)
120+
121+
def test_noop_for_non_blox_tailwind_module(self) -> None:
122+
repo_root = self._patch_repo_root_with_citation('version: "0.10.0"\n')
123+
124+
module = release_modules.Module(
125+
name="other-module",
126+
rel_dir=Path("modules/other-module"),
127+
module_path="modules/other-module",
128+
major=0,
129+
)
130+
131+
result = release_modules.update_citation_release_info(module, "9.9.9")
132+
self.assertEqual(result, [])
133+
134+
contents = (repo_root / "CITATION.cff").read_text(encoding="utf-8")
135+
self.assertEqual(contents, 'version: "0.10.0"\n')
136+
137+
138+
if __name__ == "__main__":
139+
unittest.main()

0 commit comments

Comments
 (0)