Content module patches
Spec pages published on this site (OTel specification, OTLP, semantic
conventions, OpAMP) come from upstream repositories managed as git submodules
under content-modules/. Because the website pins a specific
release of each submodule, the raw Markdown is a snapshot that can only be
updated by bumping to a newer release.
When you run npm run cp:spec,
cp-pages.sh copies submodule content into tmp/, renames
README.md files to _index.md, and then runs adjust-pages.pl over
every Markdown file. Hugo mounts tmp/ into the site tree so the processed
pages appear under /docs/specs/.
What the script does
Spec Markdown files are written for GitHub rendering: they have no Hugo front
matter, their links point to GitHub URLs, and image paths assume the repository
layout. The adjust-pages.pl script bridges this gap by applying the
following transformations to each file:
| Transformation | Description |
|---|---|
| Front matter injection | Extracts the first # Heading as title, generates linkTitle, and emits Hugo front matter. Supports front matter embedded in <!--- Hugo ... ---> comment blocks. |
| Version stamping | Appends spec version numbers (e.g., 1.54.0) to titles and linkTitles for OTel spec, OTLP, and semconv landing pages. |
| URL rewriting | Converts absolute GitHub URLs for spec repositories into local /docs/specs/... paths so cross-spec links work on the site. |
| Image path adjustment | Rewrites relative image paths so they resolve correctly from the Hugo page location. |
| Content stripping | Removes <details> blocks and <!-- toc --> sections that are not needed on the site. |
| Temporary patches | Applies regex-based patches for spec issues that have not yet been fixed in a release (see below). |
Spec versions are declared at the top of the script in the %versionsRaw hash
and are updated automatically by the version-update workflow.
Patching specs between releases
Fixing a broken link or incorrect content in a spec requires a PR to the
upstream repository, a new release, and a submodule bump in this repository.
That process can take weeks or months. In the meantime, the broken content
causes CI failures — most commonly in the automated otelbot/refcache-refresh
PRs that check every external link on the site.
To unblock CI without waiting for an upstream release, you can add a temporary
patch to adjust-pages.pl. Patches are regex-based rewrites that run
at build time and include built-in version tracking: once the spec advances past
the target version, cp:spec prints a warning that the patch is obsolete and
can be removed.
1. Create a patch function
Copy the template below and adapt it. A patch function has three parts:
- A file-scope guard that restricts the patch to the relevant spec files.
- A call to
applyPatchOrPrintMsgIfthat controls whether the patch runs based on the current spec version. - The regular expression replacement that fixes the content.
sub patchSpec_because_of_SemConv_DockerAPIVersions() {
return unless
$ARGV =~ m|^tmp/semconv/docs/|
&&
applyPatchOrPrintMsgIf('2025-11-21-docker-api-versions',
'semconv', '1.39.0-dev');
# For the problematic links, see:
# https://github.com/open-telemetry/semantic-conventions/issues/3103
#
# Replace older Docker API versions with the latest:
# https://github.com/open-telemetry/semantic-conventions/pull/3093
s{
(https://docs.docker.com/reference/api/engine/version)/v1.(43|51)/(\#tag/)
}{$1/v1.52/$3}gx;
}
The three arguments to applyPatchOrPrintMsgIf are:
| Argument | Description |
|---|---|
| Patch ID | A unique identifier (date + short description) printed in log messages. |
| Spec name | One of spec, otlp, or semconv. |
| Target vers | The spec version the patch applies to. The patch runs while the submodule is at this version and becomes obsolete once the spec advances past it. |
2. Register the patch call
Add a call to your function inside the section of the main loop that corresponds
to the spec kind. For semconv patches, add the call inside the
if ($ARGV =~ /^tmp\/semconv/) block:
## Semconv
if ($ARGV =~ /^tmp\/semconv/) {
# ... existing rewrites ...
patchSpec_because_of_SemConv_DockerAPIVersions();
}
For OTel spec patches, add the call under the
# SPECIFICATION custom processing section. For front-matter patches, add them
in the printFrontMatter subroutine.
3. Test the patch
Run the spec copy step and verify the patch was applied:
npm run cp:spec
A successful run shows no errors. You can then search the tmp/ output for the
problematic content to confirm it was rewritten. For link-related patches, also
run:
npm run fix:refcache # Prunes stale refcache entries, then checks links
npm test # Full test run including link checking
4. Commit and push
If your patch was created while fixing a refcache PR (e.g., the
otelbot/refcache-refresh branch), commit the changes to adjust-pages.pl
together with the updated refcache.json, then force-push with lease:
git add scripts/content-modules/adjust-pages.pl static/refcache.json
git commit -m "Patch adjust-pages.pl and refresh refcache"
git push --force-with-lease
5. Remove obsolete patches
Once a new release of the spec includes the fix, cp:spec prints a warning:
INFO: adjust-pages.pl: patch '<id>' is probably obsolete now that
spec '<name>' is at version '<new>' >= '<target>'; if so, remove the patch
When you see this message, delete the patch function and its call from the script. If it is the last remaining patch, you may comment it out instead of deleting, to preserve it as a reference for future patches.