Skip to content

Commit 6bc381b

Browse files
committed
addd support policy sorting
Signed-off-by: sirutBuasai <sirutbuasai27@outlook.com>
1 parent 7b5b29b commit 6bc381b

File tree

4 files changed

+71
-24
lines changed

4 files changed

+71
-24
lines changed

.kiro/steering/docs.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ from utils import render_table
172172
# Build a complete row (uses img.get_display() internally)
173173
row = build_image_row(img, columns) # ["PyTorch 2.9", "py312", ...]
174174

175+
# Build row with field overrides (e.g., for version consolidation in support_policy)
176+
row = build_image_row(img, columns, overrides={"version": "2.9"})
177+
175178
# Render markdown table
176179
table = render_table(headers, rows)
177180
```
@@ -216,7 +219,7 @@ To generate release notes for an image, add the following fields to the image co
216219
217220
```yaml
218221
# Required for release notes generation (both must be present)
219-
announcement:
222+
announcements:
220223
- "Introduced containers for PyTorch 2.9 for Training"
221224
- "Added Python 3.12 support"
222225

@@ -236,14 +239,14 @@ optional:
236239
**Required fields for release notes** are defined in `constants.py`:
237240

238241
```python
239-
RELEASE_NOTES_REQUIRED_FIELDS = ["announcement", "packages"]
242+
RELEASE_NOTES_REQUIRED_FIELDS = ["announcements", "packages"]
240243
```
241244

242245
The `packages` field uses keys that map to display names in `global.yml` under `display_names`.
243246

244247
### Release Notes Generation
245248

246-
Release notes are automatically generated for images that have all required fields (`announcement` and `packages`).
249+
Release notes are automatically generated for images that have all required fields (`announcements` and `packages`).
247250

248251
**Output structure:**
249252

@@ -275,7 +278,7 @@ This separation uses the `ImageConfig.is_supported` property.
275278
276279
**Generated release note sections:**
277280
278-
1. **Announcement** - Bullet list from `announcement` field
281+
1. **Announcements** - Bullet list from `announcements` field
279282
1. **Core Packages** - Table from `packages` field (keys mapped via `display_names`)
280283
1. **Security Advisory** - Hardcoded section with link to AWS Security Bulletin
281284
1. **Reference** - Docker image URIs (private ECR + public ECR if `public_registry: true`) and links to available_images.md and support_policy.md
@@ -357,11 +360,16 @@ table_order:
357360

358361
The `framework_groups` configuration consolidates support policy rows by framework. Repositories in the same group are combined into a single row using the framework name (e.g., "PyTorch").
359362

363+
**Version Display:**
364+
365+
- Images with the same major.minor version (e.g., `2.6.0` and `2.6.1`) are consolidated into a single row displayed as `2.6` if they have identical GA/EOP dates
366+
- If patch versions have different GA/EOP dates, each is displayed separately with full version (e.g., `2.6.0`, `2.6.1`) and a warning is logged
367+
360368
**Requirements:**
361369

362-
- All repositories in a group that have a given version must have identical GA/EOP dates
370+
- All repositories in a group that have a given full version (X.Y.Z) must have identical GA/EOP dates
363371
- Missing versions in some repositories are allowed (only present repos are consolidated)
364-
- A `ValueError` is raised if dates differ within a group for the same version
372+
- A `ValueError` is raised if dates differ within a group for the same full version
365373

366374
To add a new framework group, add an entry to `framework_groups` with the framework name as key and list of repositories as value.
367375

docs/DEVELOPMENT.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,12 @@ ga: "2025-10-15" # General Availability date
8585
eop: "2026-10-15" # End of Patch date
8686
```
8787

88-
**Validation:** All images in the same framework group with the same version must have identical GA/EOP dates.
88+
**Version Consolidation:**
89+
90+
- Images with the same major.minor version (e.g., `2.6.0` and `2.6.1`) are consolidated into a single row displayed as `2.6` if they have identical GA/EOP dates
91+
- If patch versions have different GA/EOP dates, each is displayed separately with full version (e.g., `2.6.0`, `2.6.1`) and a warning is logged
92+
93+
**Validation:** All images in the same framework group with the same full version (X.Y.Z) must have identical GA/EOP dates.
8994

9095
______________________________________________________________________
9196

docs/src/generate.py

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -187,36 +187,66 @@ def generate_support_policy(dry_run: bool = False) -> str:
187187
if not images:
188188
continue
189189

190-
# Deduplicate by version, validating date consistency
191-
version_map: dict[str, ImageConfig] = {}
190+
# Group by major.minor, then decide display format based on date consistency
191+
major_minor_groups: dict[str, list[ImageConfig]] = {}
192192
for img in images:
193-
existing = version_map.get(img.version)
194-
if existing and (existing.ga != img.ga or existing.eop != img.eop):
195-
raise ValueError(
196-
f"Inconsistent dates for {framework_group} {img.version}: \n"
197-
f"\tExisting: {existing._repository}-{existing.version}-{existing.accelerator}-{existing.platform}\n"
198-
f"\tImage: {img._repository}-{img.version}-{img.accelerator}-{img.platform}\n"
199-
f"\t({existing.ga}, {existing.eop}) vs ({img.ga}, {img.eop})"
193+
v = parse_version(img.version)
194+
major_minor = f"{v.major}.{v.minor}"
195+
major_minor_groups.setdefault(major_minor, []).append(img)
196+
197+
version_map: dict[str, ImageConfig] = {}
198+
for major_minor, group in major_minor_groups.items():
199+
# Check if all images in group have same ga/eop
200+
first = group[0]
201+
all_same_dates = all(img.ga == first.ga and img.eop == first.eop for img in group)
202+
203+
if all_same_dates:
204+
# Consolidate to major.minor display
205+
version_map[major_minor] = first
206+
else:
207+
# Keep full versions, warn about inconsistency
208+
versions_info = ", ".join(f"{img.version} ({img.ga}, {img.eop})" for img in group)
209+
LOGGER.warning(
210+
f"Different GA/EOP dates for {framework_group} patch versions: {versions_info}"
200211
)
201-
version_map[img.version] = img
212+
# Keep each patch version as separate row with full version display
213+
for img in group:
214+
existing = version_map.get(img.version)
215+
# Error if same full version (e.g., X.Y.Z) has different dates across images
216+
if existing and (existing.ga != img.ga or existing.eop != img.eop):
217+
raise ValueError(
218+
f"Inconsistent dates for {framework_group} {img.version}: \n"
219+
f"\tExisting: {existing._repository}-{existing.version}-{existing.accelerator}-{existing.platform}\n"
220+
f"\tImage: {img._repository}-{img.version}-{img.accelerator}-{img.platform}\n"
221+
f"\t({existing.ga}, {existing.eop}) vs ({img.ga}, {img.eop})"
222+
)
223+
# Deduplicate same full version with same dates
224+
version_map[img.version] = img
202225

203226
# Merge legacy entries for this framework
204227
for legacy_img in legacy_data.get(framework_group, []):
205228
if legacy_img.version not in version_map:
206229
version_map[legacy_img.version] = legacy_img
207230

208-
# Sort by version descending and separate supported/unsupported
209-
for img in sort_by_version(list(version_map.values())):
210-
(supported if img.is_supported else unsupported).append(img)
231+
# Sort by version descending within this framework group
232+
# Key is the display version (major.minor if consolidated, full version otherwise)
233+
sorted_keys = sorted(
234+
version_map.keys(), key=lambda k: parse_version(version_map[k].version), reverse=True
235+
)
236+
for key in sorted_keys:
237+
img = version_map[key]
238+
(supported if img.is_supported else unsupported).append((img, key))
211239

212240
# Build tables
213241
table_config = load_table_config("extra/support_policy")
214242
columns = table_config.get("columns", [])
215243
headers = [col["header"] for col in columns]
216244

217-
supported_table = render_table(headers, [build_image_row(img, columns) for img in supported])
245+
supported_table = render_table(
246+
headers, [build_image_row(img, columns, {"version": ver}) for img, ver in supported]
247+
)
218248
unsupported_table = render_table(
219-
headers, [build_image_row(img, columns) for img in unsupported]
249+
headers, [build_image_row(img, columns, {"version": ver}) for img, ver in unsupported]
220250
)
221251

222252
# Render template

docs/src/image_config.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,17 @@ def get_display(self, field: str) -> str:
167167
return str(value) if value is not None else "-"
168168

169169

170-
def build_image_row(img: ImageConfig, columns: list[dict]) -> list[str]:
170+
def build_image_row(img: ImageConfig, columns: list[dict], overrides: dict = None) -> list[str]:
171171
"""Build a table row from an ImageConfig using column definitions.
172172
173173
In tables/<table>.yml, the <field> name will map to img.<field> / img.get(<field>) attribute.
174174
If you need to do string manipulation on the field, create a new property with convention display_<field>.
175+
176+
Args:
177+
overrides: Optional dict of field -> value to override img values (e.g., {"version": "2.6"})
175178
"""
176-
return [img.get_display(col["field"]) for col in columns]
179+
overrides = overrides or {}
180+
return [overrides.get(col["field"], img.get_display(col["field"])) for col in columns]
177181

178182

179183
def load_repository_images(repository: str) -> list[ImageConfig]:

0 commit comments

Comments
 (0)