CI workflows

GitHub Actions workflows that automate PR checks, label management, and other CI/CD processes.

All workflow files live under .github/workflows/.

PR approval labels

Two workflows work together to automatically manage approval-related labels on pull requests:

Workflow fileTriggerPrivileges
pr-review-trigger.ymlpull_request_reviewMinimal (no secrets)
pr-approval-labels.ymlpull_request_target, workflow_run, scheduleApp token for label edits and org/team reads

Labels managed

  • missing:docs-approval — added when approval from the docs-approvers team is pending; removed once a docs-approver approves.
  • missing:sig-approval — added when approval from a SIG team is pending (determined by files changed and .github/component-owners.yml); removed once a SIG member approves or when no SIG component is touched.
  • ready-to-be-merged — added when all required approvals are present; removed otherwise. For PRs carrying any label in PUBLISH_DATE_LABELS, this label is also gated on the publish date found in changed files.

Publish date gating

The script scans each changed file for a line beginning with date: (typically from the front matter in Markdown content). If it finds a date in the future, the ready-to-be-merged label is withheld until that date arrives (UTC). This helps prevent content from being merged before its scheduled publication date.

The check applies to PRs carrying any label listed in the PUBLISH_DATE_LABELS array in the script (currently: blog, automatically applied to any PR touching content/en/blog/**). Adding a label to that array extends the check to other PR types.

If a PR contains multiple files with different dates, the label is gated on the latest date — all content must be ready before merging.

Script operating modes

The script runs in one of two modes, selected by whether the PR environment variable is set:

  • Single-PR mode — processes a single PR. Used by the pull_request_target and workflow_run triggers.
  • Batch mode — queries GitHub for all open PRs carrying any PUBLISH_DATE_LABELS label and processes each one. Used by the schedule trigger (daily at midnight UTC), so a PR whose publish date arrives overnight receives ready-to-be-merged automatically without requiring a new commit.

Why two workflows?

GitHub’s pull_request_review event has no _target variant. This means a workflow triggered by a review on a fork PR runs in the fork’s context and cannot access the base repository’s secrets.

To work around this limitation, the system uses a workflow_run chaining pattern:

  1. pr-review-trigger runs on every review submission/dismissal. It saves the PR number as an artifact and exits — no secrets needed.
  2. pr-approval-labels is triggered by workflow_run (when the trigger workflow completes). It runs in the base repository context with full access to the GitHub App token, downloads the artifact, and updates labels.

For content changes (opened, reopened, synchronize), the pr-approval-labels workflow is triggered directly via pull_request_target.

sequenceDiagram
    participant R as Reviewer
    participant GH as GitHub
    participant T as pr-review-trigger
    participant L as pr-approval-labels

    R->>GH: Submits review (approve/request changes/dismiss)

    Note over GH: pull_request_review event

    GH->>T: Trigger (fork context, no secrets)
    T->>T: Save PR number as artifact
    T->>GH: Upload artifact, workflow completes

    Note over GH: workflow_run event (completed)

    GH->>L: Trigger (base repo context, with secrets)
    L->>L: Download PR number artifact
    L->>L: Run pr-approval-labels.sh
    L->>GH: Add/remove labels
sequenceDiagram
    participant A as Author
    participant GH as GitHub
    participant L as pr-approval-labels

    A->>GH: Opens/updates PR

    Note over GH: pull_request_target event

    GH->>L: Trigger directly (base repo context, with secrets)
    L->>L: Run pr-approval-labels.sh
    L->>GH: Add/remove labels
sequenceDiagram
    participant GH as GitHub
    participant L as pr-approval-labels
    participant API as GitHub API

    Note over GH: schedule event (daily, midnight UTC)

    GH->>L: Trigger (base repo context, with secrets)
    L->>API: Query open PRs with PUBLISH_DATE_LABELS labels
    API-->>L: List of PRs
    loop Each PR
        L->>L: Run pr-approval-labels.sh
        L->>GH: Add/remove labels
    end

Security model

  • pr-review-trigger: intentionally minimal — no secrets, no privileged permissions. Ignores review.state == "commented" since comments don’t affect approvals.
  • pr-approval-labels: runs with a GitHub App token (OTELBOT_DOCS_APP_ID / OTELBOT_DOCS_PRIVATE_KEY) that has permissions to read org/team membership and edit PR labels. Uses pull_request_target and workflow_run to ensure it always executes in the trusted base repository context.

PR fix directives

The pr-actions.yml workflow lets contributors run selected fix scripts by commenting on a PR:

  • /fix runs npm run fix.
  • /fix:<name> runs npm run fix:<name> (for example, /fix:format).
  • /fix:all is mapped to /fix since the command semantics changed (#9291).
  • /fix:ALL is mapped to fix:all so that maintainers can run fix:all.

It runs as a two-stage pipeline:

  1. generate-patch (untrusted): checks out the PR branch, runs the fix command, prunes the link refcache, and uploads a patch artifact (pr-fix.patch), up to 1024 KB.
  2. apply-patch (trusted): runs with a GitHub App token, applies the patch, and pushes a commit to the PR branch.

If a directive produces no changes, a separate notify-noop job comments that nothing needed to be committed.

Other workflows

The repository includes several other workflows:

WorkflowPurpose
check-links.ymlSharded link checking using htmltest
check-text.ymlTextlint terminology checks
check-i18n.ymlLocalization front matter validation
check-spelling.ymlSpell checking
auto-update-registry.ymlAuto-update registry package versions
auto-update-versions.ymlAuto-update OTel component versions
build-dev.ymlDevelopment build and preview
label-prs.ymlAuto-label PRs based on file paths
component-owners.ymlAssign reviewers based on component ownership