Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bcc7cf6
Reconcile enterprise/cloud doc divergence + add bump-last-updated too…
justinegeffen Jun 8, 2026
08ba49d
[automated] Fix code formatting
Jun 8, 2026
197a870
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 8, 2026
5555c16
Update platform-enterprise_docs/pipelines/versioning.md
justinegeffen Jun 9, 2026
4c77658
Update platform-enterprise_docs/secrets/overview.md
justinegeffen Jun 9, 2026
a22a275
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 9, 2026
0c4aa11
[automated] Fix code formatting
Jun 9, 2026
996a93b
Switch bump-last-updated to checker pattern with invocable fix command
justinegeffen Jun 9, 2026
3c19717
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 10, 2026
b222e26
[automated] Fix code formatting
Jun 10, 2026
ebc1b01
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 10, 2026
893eb61
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 11, 2026
339c264
[automated] Fix code formatting
Jun 11, 2026
58e9989
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 12, 2026
3c09ebb
[automated] Fix code formatting
Jun 12, 2026
995eb4e
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 18, 2026
0d1dbc0
[automated] Fix code formatting
Jun 18, 2026
6b624b1
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 19, 2026
f1d55b9
[automated] Fix code formatting
Jun 19, 2026
770b0c0
Merge branch 'master' into enterprise-cloud-divergence-audit
justinegeffen Jun 22, 2026
c43dc31
[automated] Fix code formatting
Jun 22, 2026
fbb3492
[automated] Fix code formatting
Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
48 changes: 48 additions & 0 deletions .github/scripts/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,53 @@
# GitHub Actions scripts

This directory contains scripts invoked by [.pre-commit-config.yaml](../../.pre-commit-config.yaml) or by the GitHub Actions workflows under [.github/workflows/](../workflows/). See the [README's "Workflows and actions audit"](../../README.md#workflows-and-actions-audit) section for how each workflow uses these.

## bump-last-updated.py

Two-mode utility for keeping frontmatter `last updated:` current on `.md` / `.mdx` files. Used as a **checker** by the [pre-commit hook](../../.pre-commit-config.yaml) (fails with an invocable command, doesn't modify files) and as a **fixer** by the [pre-commit-fix.yaml](../workflows/pre-commit-fix.yaml) CI workflow (rewrites files in place).

### Modes

**Check mode** (`--check`): used by the pre-commit hook on `git commit`. Reports any changed file whose `last updated:` is stale (or missing on a file that declares `date created:`), prints the exact fix command, exits 1. No files modified.

**Fix mode** (default): rewrites files in place. Sets `last updated:` to today's date. If the file declares `date created:` but lacks `last updated:`, inserts the field immediately after `date created:`. Files without `date created:` (changelog entries, partials) are skipped.

### Invocation

**Check (what the pre-commit hook does):**

```bash
python3 .github/scripts/bump-last-updated.py --check path/to/file.md ...
```

**Fix (what you run when the check fails):**

```bash
python3 .github/scripts/bump-last-updated.py path/to/file.md ...
```

The check-mode failure message includes a paste-ready fix invocation listing exactly the stale files.

### Exit codes

| Mode | `0` | `1` |
|---|---|---|
| `--check` | No staleness detected | One or more files have stale `last updated:` (workflow / commit aborts; user runs the fixer) |
| default (fix) | Nothing to change | At least one file was modified (signals pre-commit to re-stage if invoked via the hook) |

### Why two modes

Following the same pattern as [check-doc-tags.py](check-doc-tags.py): the local hook should fail explicitly and tell the contributor what to run, not silently rewrite their working tree. The CI workflow then invokes the fixer on changed files so fork contributors and skipped local hooks still merge with a current `last updated:`.

### Scope

Excluded by `.pre-commit-config.yaml`:
- `platform-enterprise_versioned_docs/` — frozen release snapshots; their `last updated:` should reflect when the snapshot was cut.
- `changelog/` — entries don't follow the `date created:` / `last updated:` convention.
- Standard build/vendor dirs (`node_modules/`, `build/`, `dist/`, `.git/`).

---

## verify-agent-findings.py

Validates agent output by checking that quoted text actually exists at the claimed line numbers, preventing hallucinations from being reported.
Expand Down
124 changes: 124 additions & 0 deletions .github/scripts/bump-last-updated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
Comment thread
justinegeffen marked this conversation as resolved.
"""Check (or bump) frontmatter `last updated:` on changed Markdown files.

Two modes:

- **Check mode** (`--check`): used by the `bump-last-updated` pre-commit hook.
Reads each file path passed in, reports any whose `last updated:` is not
today (or that lack the field entirely), prints the exact command to fix,
and exits 1. No files modified.
- **Fix mode** (default): rewrites the file in place. For each file:
- If frontmatter has `last updated:`, set its value to today (YYYY-MM-DD).
- If frontmatter has `date created:` but no `last updated:`, insert
`last updated:` immediately after `date created:` with today's date.
Files without `date created:` are skipped (changelog entries, partials).
Exits non-zero if any file was modified, zero otherwise — per the standard
pre-commit fixer convention.

Why two modes: hook runs in check mode so the contributor sees an explicit
failure with an invocable command (matches the `check-doc-tags` pattern in
this repo). The CI workflow runs the script directly in fix mode and commits
the bump back, so fork contributors and skipped local hooks still get a
correct `last updated:` on merge.
"""
from __future__ import annotations

import re
import sys
from datetime import date
from pathlib import Path

TODAY = date.today().strftime("%Y-%m-%d")

FRONTMATTER_RE = re.compile(r"^---[ \t]*\n(.*?\n)---[ \t]*\n", re.DOTALL)
LAST_UPDATED_RE = re.compile(r"^(last updated:\s*).*$", re.MULTILINE)
DATE_CREATED_LINE_RE = re.compile(r"^date created:\s*")


def compute_new_frontmatter(fm: str) -> str | None:
"""Return the new frontmatter body if a bump is needed, else None.

Returns the same string the fixer would write so check mode and fix mode
stay in lockstep — no chance of one saying "stale" while the other says
"no-op".
"""
if not any(DATE_CREATED_LINE_RE.match(line) for line in fm.splitlines()):
return None # file doesn't follow the convention; skip

if LAST_UPDATED_RE.search(fm):
new_fm = LAST_UPDATED_RE.sub(rf'\1"{TODAY}"', fm, count=1)
else:
# Insert `last updated:` right after the `date created:` line.
out: list[str] = []
inserted = False
for line in fm.splitlines():
out.append(line)
if not inserted and DATE_CREATED_LINE_RE.match(line):
out.append(f'last updated: "{TODAY}"')
inserted = True
new_fm = "\n".join(out) + "\n"

return new_fm if new_fm != fm else None


def needs_bump(path: Path) -> bool:
"""True if `last updated:` is stale or missing on a file that has `date created:`."""
try:
content = path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
return False
m = FRONTMATTER_RE.match(content)
if not m:
return False
return compute_new_frontmatter(m.group(1)) is not None


def apply_bump(path: Path) -> bool:
"""Write the bump. Return True if file was modified."""
try:
content = path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
return False
m = FRONTMATTER_RE.match(content)
if not m:
return False
new_fm = compute_new_frontmatter(m.group(1))
if new_fm is None:
return False
rest = content[m.end():]
path.write_text(f"---\n{new_fm}---\n{rest}", encoding="utf-8")
return True


def main(argv: list[str]) -> int:
check_only = "--check" in argv
paths = [
Path(a) for a in argv
if a != "--check" and Path(a).is_file() and Path(a).suffix in (".md", ".mdx")
]

if check_only:
stale = [p for p in paths if needs_bump(p)]
if not stale:
return 0
print(f"ERROR: {len(stale)} file(s) have stale `last updated:` (expected {TODAY}):")
for p in stale:
print(f" {p}")
print()
print("Fix locally by running:")
print(f" python3 .github/scripts/bump-last-updated.py {' '.join(str(p) for p in stale)}")
print()
print("Or comment `fix formatting` on your PR to let CI bump these for you.")
return 1

modified = [p for p in paths if apply_bump(p)]
if not modified:
return 0
print(f"Bumped `last updated:` to {TODAY} in:")
for p in modified:
print(f" {p}")
return 1


if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
58 changes: 51 additions & 7 deletions .github/workflows/pre-commit-fix.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
name: Run pre-commit when requested via comment
name: Run pre-commit on PRs or via comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add an author_association here to improve security.

on:
issue_comment:
types: [created]
pull_request:
types: [opened, synchronize, reopened]

jobs:
pre_commit_fix:
runs-on: ubuntu-latest
# Only run if comment is on a PR with the main repo, and if it contains the magic keywords
# Run when:
# - An "fix formatting" comment is posted on any PR (works for fork PRs too).
# - A PR is opened/updated from a same-repo branch (skip forks — they have
# read-only tokens that can't push; fork contributors can still trigger
# the fix via the comment route above).
if: >
github.event.issue.pull_request &&
startsWith(github.event.comment.body, 'fix formatting')
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
startsWith(github.event.comment.body, 'fix formatting'))
||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login != 'seqera-docs-bot')

permissions:
contents: write
Expand All @@ -18,17 +29,50 @@ jobs:
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # ratchet:actions/checkout@v6.0.3

# Action runs on the issue comment, so we don't get the PR by default.
# Use the GitHub CLI to check out the PR.
- name: Checkout Pull Request
# issue_comment events don't give us the PR ref, so use gh CLI to switch.
- name: Checkout PR branch (comment trigger)
if: github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ github.token }}
run: gh pr checkout ${{ github.event.issue.number }}

# pull_request events already supply head ref — use it directly so the
# subsequent push lands on the contributor's branch.
- name: Checkout PR branch (pull_request trigger)
if: github.event_name == 'pull_request'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0

- uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # ratchet:j178/prek-action@v2.0.4
id: pre-commit
continue-on-error: true

# bump-last-updated is a checker locally (fails with an invocable
# command, doesn't modify files). For PR / comment-triggered CI runs we
# explicitly invoke the script in fix mode against the PR's changed
# files, so fork contributors and skipped local hooks still get a
# current `last updated:` on merge.
- name: Bump stale last_updated dates
run: |
set -e
BASE_REF="${{ github.event.pull_request.base.ref || github.event.repository.default_branch }}"
git fetch --no-tags --depth=1 origin "$BASE_REF" || true
BASE_SHA=$(git merge-base "origin/$BASE_REF" HEAD 2>/dev/null || git rev-parse "origin/$BASE_REF" 2>/dev/null || echo "")
if [ -z "$BASE_SHA" ]; then
echo "No base ref to diff against; skipping."
exit 0
fi
CHANGED=$(git diff --name-only --diff-filter=ACMR "$BASE_SHA" HEAD -- '*.md' '*.mdx' \
| grep -vE '^(platform-enterprise_versioned_docs|changelog)/' || true)
if [ -z "$CHANGED" ]; then
echo "No changed .md/.mdx files; nothing to bump."
exit 0
fi
# shellcheck disable=SC2086
python3 .github/scripts/bump-last-updated.py $CHANGED || true

- name: Check if any files changed
run: |
git diff --exit-code || echo "changed=YES" >> $GITHUB_ENV
Expand Down
20 changes: 20 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@ repos:
\.git/
)

# Check frontmatter `last updated:` is today's date on changed docs.
# Reports stale dates with an invocable fix command; does not modify files.
# Run the script directly (without --check) to apply the bump.
- repo: local
hooks:
- id: bump-last-updated
name: Check frontmatter last updated date is current
language: python
entry: python3 .github/scripts/bump-last-updated.py --check
files: \.(md|mdx)$
exclude: |
(?x)^(
node_modules/|
build/|
dist/|
\.git/|
platform-enterprise_versioned_docs/|
changelog/
)

# Standard pre-commit hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ This repository ships 18 GitHub Actions workflows under [.github/workflows/](.gi
|---|---|---|---|---|
| No unresolved conflicts | [no-conflict-markers.yml](.github/workflows/no-conflict-markers.yml) | `pull_request` to `master` | Automatic | Active |
| Pre-commit check | [pre-commit-check.yaml](.github/workflows/pre-commit-check.yaml) | `pull_request` | Automatic | Active |
| Pre-commit fix | [pre-commit-fix.yaml](.github/workflows/pre-commit-fix.yaml) | PR comment `fix formatting` | Manual (comment) | Active |
| Pre-commit fix | [pre-commit-fix.yaml](.github/workflows/pre-commit-fix.yaml) | `pull_request: opened/synchronize/reopened` (same-repo PRs only), PR comment `fix formatting` (any PR) | Automatic + manual | Active |
| Internal link checking | [check-internal-links.yml](.github/workflows/check-internal-links.yml) | `pull_request` | Automatic | Active |
|| External link check (Links) | [links.yml](.github/workflows/links.yml) | Weekly cron (Sat 18:00 UTC), `repository_dispatch`, manual | Automatic + manual | Active |
| markdownlint-cli2 | [markdown-lint.yml](.github/workflows/markdown-lint.yml) | `workflow_dispatch` only | Manual | Disabled (manual-only) |
Expand Down Expand Up @@ -425,10 +425,11 @@ Platform repo (release tag cut)
tower-cli release
└── check-cli-updates.yml ──► dispatch: cli-release ──► update-cli-docs.yml ──► PR

PR comment `/editorial-review` ──► docs-review.yml (gates + Vale + /editorial-review skill)
PR comment `fix formatting` ──► pre-commit-fix.yaml
PR label `overlays-approved` ──► apply-overlays-and-regenerate.yml
@claude in comment/issue/review ──► claude.yml
PR comment `/editorial-review` ──► docs-review.yml (gates + Vale + /editorial-review skill)
PR opened/synchronize (same-repo)──► pre-commit-fix.yaml (bumps last-updated, fixes formatting)
PR comment `fix formatting` ──► pre-commit-fix.yaml (manual route, works for fork PRs)
PR label `overlays-approved` ──► apply-overlays-and-regenerate.yml
@claude in comment/issue/review ──► claude.yml
```

The two `repository_dispatch` content pipelines (permissions, audit events) and the API overlay pipeline are independent of each other — they share the `DOCS_BOT_APP_ID` / `DOCS_BOT_APP_PRIVATE_KEY` GitHub App credentials but otherwise don't interact.
Expand Down
Loading
Loading