chore(ci): contribute 1.7.14 release-toolchain follow-up (v-prefixed release tags + HACS validation resilience + 1.7.14.1 stamp)#206
Conversation
* fix(ci): accept v-prefixed release tags in release stamping
BSkando tags releases vX.Y.Z while jleinenbach tags X.Y.Z[.N]; the shared
release-stamp.yml guard rejected any leading `v`, so publishing v1.7.14 on
BSkando failed at "Validate published tag" and never ran the stamp, commit,
push or HACS ZIP upload. The published release shipped with no
googlefindmy.zip asset (broken HACS installs).
Strip an optional single leading `v` at the workflow boundary
(VERSION="${TAG_NAME#v}") and validate/stamp that v-less VERSION; the full
TAG_NAME (with any `v`) still addresses the git tag and release asset
(checkout ref, rev-list refs/tags, gh release upload). VERSION_RE stays
version-only, a version literal never carries a `v`. release.yml's REAL_TIP
gate strips `v` too so a genuine v-prefixed line tip is recognised as a
version rather than blanked as foreign.
Adds mutation-sharp tests for the tag->version mapping and locks the
REAL_TIP strip into the workflow; the byte-parity guard test is unaffected
(the regex pattern is unchanged, only its input variable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* style(test): apply ruff format to test_stamp_version
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
) (#1206) * ci: tolerate transient HACS validation regression (hacs/integration#5252) The HACS validation job intermittently fails on hacsjson and integration_manifest with "invalid 'hacs.json' file" / "Got None" while the files are byte-identical to a green run and the action image digest is unchanged. This is the known upstream regression hacs/integration#5252 (the action fetches the raw files as None from the GitHub contents API). Run HACS first with continue-on-error; only on failure re-run it with exactly those two transient-prone validators isolated. If everything else passes, the failure was the known transient signature and is tolerated (job green + warning); any other failing check still exits non-zero. The isolation is not permanent (fallback runs only on failure). The real validity of both files stays enforced independently: manifest.json by the hassfest job (needs: hassfest) and hacs.json by the test job. ci-success and release.yml are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(ci): harden HACS transient-guard test via YAML parsing Address the terminal diff-review follow-ups (P2/P3): replace the whitespace-fragile string search with structural YAML parsing of the hacs job steps, and assert the continue-on-error placement explicitly (primary + fallback have it, the classifier does not) so the guard cannot regress into a blanket-ignore or a non-blocking classifier. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(hacs): validate hacs.json field types so transient guard cannot mask real schema errors The ci.yml transient-HACS guard classifies a run 'transient' when only hacsjson + integration_manifest fail, relying on the local test job to catch a genuine hacs.json schema error. test_hacs_metadata_matches_manifest only checked allowed keys, not their types, so a non-boolean zip_release/content_in_root could slip through green (Codex #1206 P2). Add explicit field-type validation covering the exact class HACS's hacsjson validator rejects; drop the duplicate path header. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7114812858
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| elif [ "$RETRY" = "success" ]; then | ||
| echo "::warning ::HACS validation failed only on the transient-prone checks (hacsjson, integration_manifest) and passed once they were isolated; treating as the known transient upstream regression (hacs/integration#5252). File validity is still enforced by the hassfest and test jobs." | ||
| echo "status=transient" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
Require the exact HACS transient signature
When the first HACS run fails because of a real hacsjson or integration_manifest problem that hassfest/local tests do not mirror (for example a HACS-only manifest or hacs.json requirement), the fallback reruns with both validators ignored and this branch marks the job successful solely because the remaining checks pass. That turns genuine HACS metadata regressions into green CI, so the classifier should inspect the original failure signature/logs or otherwise reproduce all ignored validators locally before setting status=transient.
Useful? React with 👍 / 👎.
…ard cannot mask real regressions (#1207) The ci.yml transient guard (#1206) ignores hacsjson + integration_manifest in its fallback and tolerates the job as transient when the remaining checks pass. test_hacs_metadata_field_types only reproduced hacs.json field *types*, so a *missing* required key (which HACS also rejects) could slip through green. Reproduce both ignored validators locally in the test job (the ci-success gate): - test_hacs_metadata_requires_name: hacs.json must declare a non-empty name. - test_manifest_satisfies_hacs_integration_contract: manifest.json must carry the six keys HACS's integration_manifest validator requires (domain, documentation, issue_tracker, name, version as non-empty strings; codeowners as a non-empty list of strings). Source: hacs.xyz/docs/publish/integration. Closes the N2 residual of PLAN_GFMY_HACS_TRANSIENT_GUARD (Codex #206 P2).
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a58e74b578
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| uses: hacs/action@main | ||
| with: | ||
| category: integration | ||
| ignore: topics issues hacsjson integration_manifest |
There was a problem hiding this comment.
Use a documented HACS check name
When the upstream #5252 failure occurs, the first run reports both hacsjson and integration_manifest, but I checked the HACS Action docs for with.ignore: they document a space-separated list of ignorable checks and list archived, brands, description, hacsjson, images, information, issues, and topics, not integration_manifest. Because this retry relies on ignoring integration_manifest, the retry will still run that failing validator in the transient scenario and RETRY remains failure, so the classifier exits 1 instead of making CI resilient.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Thanks for the careful read. I verified this against the HACS validation source (not the docs page), and integration_manifest is in fact a valid, effective ignore token, so the surgical retry does isolate it.
Chain of evidence (hacs/integration main, which is exactly what hacs/action@main runs via docker://ghcr.io/hacs/action:main):
- The ignore filter keys off the check slug, and the slug is the check module basename:
custom_components/hacs/validate/base.py:@property def slug(self) -> str: return self.__class__.__module__.rsplit(".", maxsplit=1)[-1]
- The integration-manifest check lives in
custom_components/hacs/validate/integration_manifest.py, so its slug is exactlyintegration_manifest. - The manager applies the ignore list uniformly over every validator by slug:
custom_components/hacs/validate/manager.py:and validator.slug not in os.getenv("INPUT_IGNORE", "").split(" ")
- GitHub Actions maps
with.ignoretoINPUT_IGNORE, soignore: topics issues hacsjson integration_manifestyieldsINPUT_IGNORE="topics issues hacsjson integration_manifest", whose split containsintegration_manifest, and thenot incheck excludes that validator from execution.
The list under https://hacs.xyz/docs/publish/action/ is an incomplete enumeration (it also omits license, which is likewise a real check module validate/license.py). The authoritative set of ignorable slugs is the set of module basenames under validate/, and integration_manifest is one of them. The #5252 error label "integration_manifest ... Got None" is that very slug.
So in the transient scenario the retry (ignore: ... hacsjson integration_manifest) skips both transient-prone validators; if only those two failed, hacs_surgical passes and the classifier reports transient (green with a warning). A failure on any other check keeps the retry red and the classifier exits 1. No change needed here.
Summary
Small follow-up to #205 (the
1.7.13 -> 1.7.14contribution). This bundles the three commits thejleinenbachfork's1.7line has accumulated since #205 merged, all CI/release-toolchain plus one version stamp -- no runtime behaviour change for Home Assistant users.GitHub shows a clean diff over these three commits (the two
1.7branches share the #205 merge base). The onlycustom_components/**/*.pychange is the version literal inconst.py(1.7.14.0 -> 1.7.14.1); everything else is.github/workflows/**,script/stamp_version.py,pyproject.toml, and tests.1.7.14.1stamp commit)Motivation
Two toolchain gaps surfaced after #205, plus the routine version stamp:
v-prefixed tag (v1.7.14), but the fork's release-stamp automation rejectedv-prefixed tags and only accepted the bareX.Y.Zform. On BSkando'sv1.7.14release this made the stamp step fail (that is the run you flagged). (#1205)hacs.json-- an external, transient regression inhacs/action(upstream HACS manifest validation failing incorrectly hacs/integration#5252), not a defect in this repo. The CI job now tolerates exactly that transient signature without weakening real validation. (#1206)1.7.14.1version stamp that keeps the three version literals in lockstep.Change Log (human-readable)
Fixed
v-prefixed release tags in release stamping (#1205, CI only). The release-stamp / release automation now strips a leadingvat the workflow boundary, so BSkando'svX.Y.Ztag format (e.g.v1.7.14) drives the stamp correctly. The SSOT version regex is untouched; thevis normalised only where the tag enters the workflow. This is the fix for the failed stamp run on thev1.7.14release.Changed
hacsjson,integration_manifest) isolated. Classification: primary green -> pass; primary red + isolated re-run green -> the two transient checks were the only failure (real file validity is independently covered byhassfest+ thetestjob) -> tolerated with a warning; primary red + re-run still red -> a real defect -> the job fails. The isolation is not permanent (on healthy HACS the primary run passes all seven checks and the fallback is skipped). A mutation-sharp guard test locks the structure; a companionhacs.jsonfield-type test makes the tolerance provably safe (rejects locally exactly the schema class HACS'shacsjsonvalidator rejects). This is a resilience guard against the external HACS manifest validation failing incorrectly hacs/integration#5252 wave, not a change tohacs.json.Changed (version stamp)
1.7.14.1version stamp (dev/CI). The three version literals (const.py/manifest.json/pyproject.toml) move1.7.14.0 -> 1.7.14.1in lockstep (invariant anchored incustom_components/googlefindmy/AGENTS.md).Removed
Compatibility
custom_components/**/*.pyedit is the version literal. No schema change, no data migration.Version notation (heads-up)
The fork emits a four-part PEP 440 version (
1.7.14.1), so the on-disk files read1.7.14.1. BSkando's release tag is thev-prefixed three-part form (v1.7.14). These two conventions are exactly why #1205 is needed: the stamp automation must accept thev1.7.14tag while the code literal stays four-part. Branch and shipped HACS asset always carry the stamped value.Tests
test_stamp_version.pyextended for thev-prefix normalisation (#1205);test_hacs_validation.pyextended with a mutation-sharp guard-structure test and ahacs.jsonfield-type test (#1206). Key regressions are mutation-sharp (they turn red when the fix is reverted).A note on the HACS check on this PR
If GitHub shows the HACS validation as red on this PR, it is the external, transient hacs/integration#5252 regression (unchanged
hacs.json, same Docker image digest green minutes earlier), not a defect introduced here -- and it is exactly what #1206 makes the fork's own CI resilient to. It is non-blocking. It tends to self-heal upstream within a couple of days.Risk & Rollback