22
33import json
44import re
5+ import os
6+ import shutil
57import sys
68from pathlib import Path
79
1820VERSION_RE = re .compile (r'^version\s*=\s*"([^"]+)"' , re .MULTILINE )
1921SEMVER_RE = re .compile (r"^(\d+)\.(\d+)\.(\d+)(?:rc(\d+))?$" )
2022PUBLICATION_SCOPE_PATH = Path (".github/publication_scope.json" )
23+ PUBLICATION_CANDIDATES_DIR = Path (".github/publication_candidates" )
24+ CHANGELOG_KEEP_FILE = ".gitkeep"
2125
2226
2327def get_current_version (pyproject_path : Path ) -> str :
@@ -33,9 +37,7 @@ def get_current_version(pyproject_path: Path) -> str:
3337
3438
3539def infer_bump (changelog_dir : Path ) -> str :
36- fragments = [
37- f for f in changelog_dir .iterdir () if f .is_file () and f .name != ".gitkeep"
38- ]
40+ fragments = changelog_fragments (changelog_dir )
3941 if not fragments :
4042 print ("No changelog fragments found" , file = sys .stderr )
4143 sys .exit (1 )
@@ -62,13 +64,56 @@ def bump_version(version: str, bump: str) -> str:
6264
6365
6466def write_publication_scope (path : Path , payload : dict [str , str ]) -> None :
67+ path .parent .mkdir (parents = True , exist_ok = True )
6568 path .write_text (json .dumps (payload , indent = 2 , sort_keys = True ) + "\n " )
6669 print (f" Updated { path } " )
6770
6871
72+ def changelog_fragments (changelog_dir : Path ) -> list [Path ]:
73+ return sorted (
74+ f
75+ for f in changelog_dir .iterdir ()
76+ if f .is_file () and f .name != CHANGELOG_KEEP_FILE
77+ )
78+
79+
80+ def snapshot_changelog_fragments (
81+ * ,
82+ run_id : str ,
83+ changelog_dir : Path ,
84+ publication_candidates_dir : Path ,
85+ ) -> Path :
86+ fragments = changelog_fragments (changelog_dir )
87+ if not run_id :
88+ print (
89+ "US_DATA_RUN_ID is required to snapshot changelog fragments" ,
90+ file = sys .stderr ,
91+ )
92+ sys .exit (1 )
93+ if not fragments :
94+ print ("No changelog fragments found" , file = sys .stderr )
95+ sys .exit (1 )
96+
97+ snapshot_dir = publication_candidates_dir / run_id / "changelog.d"
98+ if snapshot_dir .exists () and changelog_fragments (snapshot_dir ):
99+ print (
100+ f"Candidate changelog snapshot already exists: { snapshot_dir } " ,
101+ file = sys .stderr ,
102+ )
103+ sys .exit (1 )
104+ snapshot_dir .mkdir (parents = True , exist_ok = True )
105+ for fragment in fragments :
106+ destination = snapshot_dir / fragment .name
107+ shutil .copy2 (fragment , destination )
108+ fragment .unlink ()
109+ print (f" Snapshotted { fragment } -> { destination } " )
110+ return snapshot_dir
111+
112+
69113def main ():
70114 pyproject = _REPO_ROOT / "pyproject.toml"
71115 changelog_dir = _REPO_ROOT / "changelog.d"
116+ run_id = os .environ .get ("US_DATA_RUN_ID" , "" )
72117
73118 current = get_current_version (pyproject )
74119 bump = infer_bump (changelog_dir )
@@ -80,14 +125,25 @@ def main():
80125 print (f"Release bump: { bump } " )
81126 print (f"Would release as at build time: { would_release_as } " )
82127
128+ snapshot_changelog_fragments (
129+ run_id = run_id ,
130+ changelog_dir = changelog_dir ,
131+ publication_candidates_dir = _REPO_ROOT / PUBLICATION_CANDIDATES_DIR ,
132+ )
133+ payload = {
134+ "run_id" : run_id ,
135+ "base_release_version" : current ,
136+ "release_bump" : bump ,
137+ "candidate_scope" : candidate_scope ,
138+ "would_release_as_at_build_time" : would_release_as ,
139+ }
83140 write_publication_scope (
84141 _REPO_ROOT / PUBLICATION_SCOPE_PATH ,
85- {
86- "base_release_version" : current ,
87- "release_bump" : bump ,
88- "candidate_scope" : candidate_scope ,
89- "would_release_as_at_build_time" : would_release_as ,
90- },
142+ payload ,
143+ )
144+ write_publication_scope (
145+ _REPO_ROOT / PUBLICATION_CANDIDATES_DIR / run_id / PUBLICATION_SCOPE_PATH .name ,
146+ payload ,
91147 )
92148
93149
0 commit comments