Repository navigation
Generate ol-analytics-api's TypeScript client off release tags - #5995
Merged
Merged
Conversation
ol-analytics-api publishes per-tenant OpenAPI specs as of mitodl/ol-analytics-api#70, but it cuts releases as bare CalVer tags (2026.9.17.1) and keeps no long-lived release branch, so there is nothing for the existing `release`-branch topology to watch. This adds an optional source_repo_tag_regex: when set, the source resource versions on tags (version_type=tags) instead of on spec changes landing on a branch. Two things to know about that switch, both in the docstring as well. The git resource consults `paths` only when versioning on commits, so under a tag regex every matching tag rebuilds the client whether or not a spec moved -- the "only when the interface changed" property comes from the release cadence instead of the path filter. `branch` stops applying too, so a matching tag anywhere in the repo triggers it. The regex is anchored and rejects hotfix/<sha>, v-prefixed and releases/-prefixed forms; checked against all eight tags the repo currently has. The LoadVarStep fix is not tag-specific. It read .git/refs/heads/<branch>, which does not exist under a detached tag checkout. .git/ref is written for every version_type and is already what this repo does elsewhere (k8s_apps/pipeline.py, simple_pulumi/pipeline.py). The mitxonline and mit-learn pipelines resolve it to the same SHA they read before; regenerating both shows an unchanged `source` and only this file path moving. Requires the version_type support added in ol-concourse. Without it the argument falls through git_repo's **kwargs onto the Resource as a top-level key, leaving it out of `source` entirely and the tag_regex inert -- it generates clean and silently versions on commits, so this cannot merge until that release lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CH3LZ41bD4ZKDnTQcviqb6
ol-analytics-api publishes two specs, one per tenant, and they are independent APIs: an org-manager dashboard behind a user JWT, and a machine-to-machine partner integration. A consumer of one has no reason to pull the other's types in, so they ship as separate packages. client_repo_subpath now takes a list as well as a string, and the publish job emits one task per entry. The packages share the repo-root VERSION the bump step writes, so a release moves them together. Existing variants pass a string and are normalized to a single-element list, so mitxonline and mit-learn still emit exactly one publish task against the same directory as before. Their task name changes from `publish-node` to `publish-node-<package>`, since two tasks in one plan cannot share a name; that is a step label in the Concourse UI, not behavior. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CH3LZ41bD4ZKDnTQcviqb6
…e lib Two problems with the tag support in the preceding commits, both found in review. The regex used `\d`. The resource filters tags with `grep -E`, which is POSIX ERE, not PCRE: GNU grep emits "stray \ before d", drops the escape, and the pattern then requires literal `d` characters. It matched none of the eight tags ol-analytics-api has, so the pipeline would have set up clean and never fired on a release. My earlier check of this pattern used Python's `re`, which is the wrong engine and matched all eight. Verified the replacement by piping every real tag through /usr/bin/grep -E, plus hotfix/<sha>, v- and releases/-prefixed forms, a three-component version and a -rc1 suffix, none of which match. The ordering hazard also had no mechanical guard. An ol-concourse without version_type support does not reject the argument -- git_repo forwards it through **kwargs onto the Resource, so it lands as a top-level key, `source` never gets it, and the resource falls back to versioning commits on `main` with no paths filter, republishing the client on every commit. Merging this before the ol-concourse release, or merging it and forgetting to relock, was a silent failure. Generation now raises if version_type did not reach the source. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CH3LZ41bD4ZKDnTQcviqb6
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Sequential package publishing cannot recover from a partial npm publication failure, and the required ol-concourse release remains unavailable.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
What changed in this PR
Adds tag-triggered TypeScript client generation for ol-analytics-api while supporting multiple packages per client repository.
Changes:
- Adds the ol-analytics-api CalVer-tag configuration.
- Supports tag-versioned sources and multiple publish subpaths.
- Uses
.git/reffor both branch and detached-tag checkouts.
| File | Description |
|---|---|
configuration.py |
Configures two ol-analytics-api client packages. |
api_clients_pipeline.py |
Adds tag handling and multi-package publishing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Sequential publish steps in one job can't recover from a partial failure: if the first `yarn npm publish` succeeds and a later package fails, retrying the job re-runs the first publish, which npm rejects since that name/version already exists. Split the publish job per subpath, each gated on the same generate-clients run, so a failed package retries on its own without touching packages that already published. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ps9LGhZZH9g4D4MLpsoNuC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What are the relevant tickets?
N/A
Description (What does it do?)
ol-analytics-api publishes per-tenant OpenAPI specs as of
mitodl/ol-analytics-api#70, so its TypeScript client can
now be generated. It cuts releases as bare CalVer tags (
2026.9.17.1) and keepsno long-lived release branch, so there is nothing for the existing
release-branch topology to watch.source_repo_tag_regex. When set, the source resourceversions on tags (
version_type: tags) instead of on spec changes landing ona branch.
ol-analytics-apientry toPIPELINE_CONFIGS.client_repo_subpathnow takes a list as well as a string, and the publishjob emits one task per entry. ol-analytics-api's two tenants are independent
APIs (an org-manager dashboard behind a user JWT, and a machine-to-machine
partner integration), so they ship as separate packages rather than one that
carries both.
LoadVarStep, which read.git/refs/heads/<branch>. That path doesnot exist under a detached tag checkout.
.git/refis written under bothversion types used here, and is already what this repo reads elsewhere
(
k8s_apps/pipeline.py,simple_pulumi/pipeline.py). Not tag-specific; itwas fragile before.
Two properties of tag versioning worth knowing, both also in the docstring. The
git resource consults
pathsonly when versioning on commits, so under a tagregex every matching tag rebuilds the client whether or not a spec actually
moved; "only when the interface changed" now comes from the release cadence
rather than the path filter.
branchstops applying too, so a matching taganywhere in the repo triggers it.
How can this be tested?
The two existing variants are unaffected. Generating
mitxonlineandmit-learngives an unchangedsource(stillbranch: release, still theopenapi/specs/*.yamlpaths filter, noversion_type) and exactly one publishtask against the same directory as before. Two things move for them: the
load_varfile path, which resolves to the same SHA it read before, and thepublish task's name, which becomes
publish-node-<package>because two tasks inone plan cannot share a name. That is a step label in the Concourse UI, not
behavior.
For the new variant, generating it produces:
The regex is POSIX ERE, not PCRE, because the resource filters tags with
grep -E.\dthere is not a digit class: GNU grep warns "stray \ before d",drops the escape, and the pattern then requires literal
dcharacters andmatches nothing. Checked by piping through
/usr/bin/grep -Erather than alanguage regex engine. All eight tags ol-analytics-api currently has match,
and
hotfix/abc123,releases/2026.9.17.1,v2026.9.17.1,2026.9.17,latestand2026.9.17.1-rc1do not.Generation raises if
version_typedid not reach the resource source, so anol-concourse too old to support it fails here rather than producing a pipeline
that quietly versions on commits:
ruff checkandmypyon the touched package are clean apart from twopre-existing
D100s, identical tomain.This cannot be validated against a running pipeline before merge, because there is no
client repo to point it at yet (see below).
Additional Context
Two things gate merging, which is why this is a draft:
The
version_typesupport this depends on(Let a git resource version on tags ol-concourse#108) is not released yet, and the
ol-concourse>=0.18,<0.19pin means merging the library PR is not enough onits own, because this repo still has to relock onto the release.
git_repodoes notreject the argument when the library is too old; it forwards it through
**kwargsontoResourceas a top-level key, sosourcenever gets it andthe
tag_regexsits inert, leaving a pipeline that versions commits onmainwith no paths filter. The guard above turns that into a generationerror, but the relock is still a step someone has to take.
mitodl/ol-analytics-api-clientsdoes not exist yet.client_repo_uripoints at it and the two
client_repo_subpathentries have to matchdirectories under
src/typescript/there, alongside oneconfig/typescript-axios-*.yamlgenerator config per spec file. Until thatrepo exists this entry is inert; nothing sets the pipeline up automatically.
Checklist:
(0.18.2 or later)
uv lock --upgrade-package ol-concoursehere, so the pin actuallyresolves to that release (generation raises until it does)
mitodl/ol-analytics-api-clientscreated, with a generator config perspec and the two package directories named above
🤖 Generated with Claude Code
https://claude.ai/code/session_01CH3LZ41bD4ZKDnTQcviqb6