Skip to content

ci: scope the dependency docs check to its real inputs #948

Description

@balajinvda

Problem

generated dependency docs in .github/workflows/license-dependencies.yml runs on every pull request, with no scoping. It takes about nine minutes. Across the last twelve completed runs:

8m19s  8m36s  8m46s  9m5s  9m9s  9m37s  9m39s  9m43s  10m26s  10m35s  10m47s  16m55s

The job regenerates dependencies.md with tools/collect-dependencies and diffs it against the checked-in copy. That output is derived entirely from dependency manifests, so a pull request touching no manifest cannot change it, and the nine minutes buys nothing.

Two recent examples:

The job is also the slowest part of the Java dependency path, because collecting the Java runtime inventory shells out to bazel build for each registered component, which is why it needs Bazelisk, a JDK and a 1.4 GB Bazel cache.

Why this is not just a paths: filter

The obvious fix is on.pull_request.paths, but two things make that wrong here.

A skipped required check never reports, so branch protection blocks the merge unless a companion no-op job is added. That is avoidable complexity.

More importantly, the input set is wider than the manifest files. tools/collect-dependencies/java_deps.go builds each Java component's runtime_inventory.json through Bazel, so the inventory reflects the build graph, not only maven_install.json. Moving an artifact between compile and runtime deps in a Java component's BUILD.bazel can change the generated output without touching a single manifest. A naive path filter would skip that and let dependencies.md go stale silently, which is the exact failure the job exists to catch.

Scoping has to fail closed: when in doubt, run.

Proposal

Keep the job always running, so it always reports and branch protection is untouched, and gate only the expensive steps on a cheap scope decision computed from the merge base.

Relevant inputs, from reading the collector:

  • imports.yaml, dependencies.md, tools/collect-dependencies/**, the check script and this workflow
  • Go: go.mod, go.sum, vendor/**
  • Rust: Cargo.toml
  • Java: pom.xml, bazel-java-ci.json, and BUILD.bazel or *.bzl under a registered Java component root
  • Python: pyproject.toml, requirements*.txt
  • Node: pnpm-lock.yaml
  • Helm: Chart.yaml, Chart.lock
  • Bazel: MODULE.bazel, MODULE.bazel.lock, maven_install.json, .bazelversion

The Java component roots are discovered rather than hardcoded, by locating bazel-java-ci.json, so a new Java service is covered the day it is added. A BUILD.bazel change under a Go or Rust subtree, which is the #945 case, is correctly treated as irrelevant.

Always run in full for push to main, merge_group and workflow_dispatch, so the default branch and the merge queue are never scoped down. Only pull requests are scoped.

The decision belongs in a script under tools/ci/ with unit tests, not inline YAML, so the fail-closed behaviour is actually verifiable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions