Skip to content

[CI] Split arm-ci into a standalone workflow#6699

Merged
kellyguo11 merged 4 commits into
isaac-sim:developfrom
hujc7:jichuanh/arm-ci-separate-workflow
Jul 25, 2026
Merged

[CI] Split arm-ci into a standalone workflow#6699
kellyguo11 merged 4 commits into
isaac-sim:developfrom
hujc7:jichuanh/arm-ci-separate-workflow

Conversation

@hujc7

@hujc7 hujc7 commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Description

1. Summary

Moves the arm-ci job out of build.yaml ("Docker + Tests") into its own workflow, .github/workflows/arm-ci.yml, and extracts the change-detection gate into a reusable workflow, .github/workflows/detect-changes.yml, shared by both.

Problem. arm-ci shared the "Docker + Tests" run with every test-* job. GitHub only exposes "Re-run failed jobs" once the entire run completes, so a fast test job that failed early could not be retried until arm-ci's slow arm64 build + render finished (up to its 60-minute timeout on the scarce DGX Spark runners). arm-ci is continue-on-error (informational) and never needed to hold the run open.

Fix. arm-ci now owns its own workflow run — independent status, independent Re-run failed jobs, and no coupling to the main workflow's lifecycle.

2. What changed

  • New .github/workflows/arm-ci.yml — the arm-ci job (verbatim: continue-on-error, 60-minute timeout, same build / marker-test / cartpole-smoke steps) plus an inlined config step, gated by the shared change detector.
  • New .github/workflows/detect-changes.yml — reusable (workflow_call) change-detection gate; each caller passes its own patterns.
  • build.yaml — the arm-ci block is removed; its changes job now calls the reusable workflow (same patterns); config and all test-* jobs are unchanged.

3. Design notes

  • Required-ready. arm-ci triggers on every PR and gates the arm64 build behind the shared changes detector + if:. An irrelevant PR skips the job (which branch protection reads as green) rather than never creating the check. So arm-ci can be promoted to a required status check later with zero workflow change — a workflow-level paths: filter could not (a not-triggered required check stays pending forever). This is the same changes+if: pattern build.yaml already uses for its required test jobs.
  • Reusable detector. Both workflows share one change-detection implementation; each declares its own patterns (<ERE regex> :: <description> per line). build.yaml keeps its exact patterns; arm-ci additionally lists its real inputs — pyproject.toml, environment.yml, isaaclab.* (the root files Dockerfile.base COPYs and resolve-ov-pins reads) — which the old gating missed.
  • Trigger parity. Push to main/develop/release/** always runs (post-merge integration); pull_request runs only when arm-relevant paths change.
  • Config inlined in arm-ci.yml (only the base-image name/tag + CI image tag it needs) — not shared, since arm-ci builds its own independent -arm64 image.

4. Validation

  • ./isaaclab.sh -f clean on all changed files; YAML parses.
  • build.yaml's downstream needs.changes.outputs.run_docker_tests references preserved (build, build-curobo); inline detect logic fully removed.
  • ARM CI runs as its own workflow on this PR, independent of Docker + Tests; its Load Config job succeeds and arm-ci is confirmed not a required check today.

5. Notes

arm-ci stays continue-on-error / non-required for now; the structure above makes promoting it to a required check a branch-protection-only change.

@hujc7
hujc7 force-pushed the jichuanh/arm-ci-separate-workflow branch 3 times, most recently from 9c05f8f to 02b3976 Compare July 24, 2026 00:43
The arm-ci job lived in build.yaml (Docker + Tests) alongside every
test-* job. GitHub only exposes "Re-run failed jobs" after the whole run
completes, so a fast test job that failed early could not be retried
until arm-ci's slow arm64 build+render finished (up to its 60-minute
timeout on the scarce DGX Spark runners). arm-ci is continue-on-error
(informational) and never needed to hold the run open.

Move it to .github/workflows/arm-ci.yml as its own run, with independent
status and an independent "Re-run failed jobs".

Extract the change-detection gate into a reusable workflow,
.github/workflows/detect-changes.yml, called by both build.yaml and
arm-ci.yml with their own path patterns. arm-ci triggers on every PR and
gates the arm64 build behind that detector + `if:`, so it is safe to
promote to a required status check later: an irrelevant PR skips the job
(green to branch protection) rather than never creating the check, which
a workflow-level paths filter would do (leaving a required check pending
forever). This mirrors the changes+if pattern build.yaml already uses for
its required test jobs.

The detector lists each workflow's real inputs, including the root files
Dockerfile.base copies (pyproject.toml, environment.yml, isaaclab.*,
.dockerignore) that the old gating missed, applied to both callers.

build.yaml keeps its inline config job and all test-* jobs unchanged; its
changes job now calls the shared reusable workflow.
@hujc7
hujc7 force-pushed the jichuanh/arm-ci-separate-workflow branch from 02b3976 to dfbc442 Compare July 24, 2026 01:09
@hujc7
hujc7 marked this pull request as ready for review July 24, 2026 01:13
@hujc7
hujc7 requested a review from a team July 24, 2026 01:13
@hujc7
hujc7 requested a review from nvsekkin July 24, 2026 01:13
@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR splits the arm-ci job out of build.yaml ("Docker + Tests") into its own standalone workflow (arm-ci.yml) and extracts the shared change-detection logic into a reusable detect-changes.yml called by both workflows. The motivation is sound: arm-ci previously held the main workflow run open for up to 60 minutes (DGX Spark timeout) before GitHub exposed the "Re-run failed jobs" button for any failed test job.

  • detect-changes.yml is a new workflow_call reusable workflow that accepts caller-specific ERE patterns, queries the GitHub API for changed files, and emits run_docker_tests (always-true on non-PR events; pattern-matched on PRs). build.yaml's inlined ~90-line detection shell is replaced with a single uses: call.
  • arm-ci.yml reproduces the job verbatim from build.yaml, adds previously missing ARM-relevant patterns (pyproject.toml, environment.yml, isaaclab.*), and uses the same changes+if: gate to remain promotable to a required status check without workflow-level paths: filters.
  • build.yaml drops the arm-ci block and its inlined detection shell; all test-* job references and run_docker_tests output consumers are unchanged.

Confidence Score: 4/5

Safe to merge — the extraction is a structural reorganization with no behavioral changes to the test jobs themselves; ARM CI runs independently on this PR and the Load Config job already confirms the change-detection plumbing works end-to-end.

The core migration is faithful (arm-ci steps copied verbatim), the changes+if: required-check pattern is preserved, and the fail-safe API-error path carries over correctly. The two observations are naming (run_docker_tests in a generic reusable workflow) and a duplicated tag formula that could drift silently — neither affects current behavior.

detect-changes.yml deserves a second look on the run_docker_tests output name if more workflows adopt this reusable gate in the future.

Important Files Changed

Filename Overview
.github/workflows/detect-changes.yml New reusable workflow_call change-detection gate that replaces the inlined logic from build.yaml; parses caller-supplied ERE patterns, queries the GitHub API for changed files, and outputs run_docker_tests. The output name is semantically tied to Docker even though it now gates ARM CI as well.
.github/workflows/arm-ci.yml arm-ci job extracted verbatim from build.yaml into its own workflow; correctly gates on the shared detect-changes reusable workflow and adds previously missing ARM-relevant patterns (pyproject.toml, environment.yml, isaaclab.*). config and arm-ci jobs mirror the build.yaml pattern.
.github/workflows/build.yaml Simplified by replacing ~90 lines of inlined change-detection shell with a single uses: call to detect-changes.yml; arm-ci block removed entirely; all remaining test-* job references and outputs (run_docker_tests) are preserved correctly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    PR([PR / Push Event]) --> BW[build.yaml Docker + Tests]
    PR --> AW[arm-ci.yml ARM CI]

    BW --> BC{changes job calls detect-changes.yml}
    AW --> AC{changes job calls detect-changes.yml}

    DC[detect-changes.yml reusable workflow] --> |run_docker_tests output| BC
    DC --> |run_docker_tests output| AC

    BC -- run_docker_tests=true --> BCONFIG[config job build.yaml]
    BC -- run_docker_tests=false --> BSKIP([test-* jobs skipped green to branch protection])

    AC -- run_docker_tests=true --> ACONFIG[config job arm-ci.yml]
    AC -- run_docker_tests=false --> ASKIP([arm-ci skipped green to branch protection])

    BCONFIG --> BTESTS[test-* matrix jobs ubuntu-latest]
    ACONFIG --> ARMJOB[arm-ci job self-hosted arm64 continue-on-error]

    ARMJOB --> ARTIFACT[Upload arm-ci-reports]
Loading

Reviews (1): Last reviewed commit: "[CI] Split arm-ci into a standalone work..." | Re-trigger Greptile

Comment thread .github/workflows/detect-changes.yml Outdated
Comment on lines +42 to +45
outputs:
run_docker_tests:
description: "Whether the caller's gated jobs should run for this event."
value: ${{ jobs.detect.outputs.run_docker_tests }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 The reusable workflow's output is named run_docker_tests, which is semantically correct for build.yaml but misleading for arm-ci.yml, where callers must write needs.changes.outputs.run_docker_tests == 'true' to gate an ARM build. A generic name like should_run would communicate the reusable intent without implying Docker, and wouldn't require any build.yaml change since build.yaml's changes job reference would just rename the output it reads.

Suggested change
outputs:
run_docker_tests:
description: "Whether the caller's gated jobs should run for this event."
value: ${{ jobs.detect.outputs.run_docker_tests }}
outputs:
should_run:
description: "Whether the caller's gated jobs should run for this event."
value: ${{ jobs.detect.outputs.run_docker_tests }}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +114 to +133
- id: image_tag
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REF_NAME: ${{ github.ref_name }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail

if [ "$EVENT_NAME" = "pull_request" ]; then
ref_component="pr-${PR_NUMBER}"
else
ref_component="$REF_NAME"
fi

# Sanitize the ref name for use as a Docker tag suffix.
sanitized_ref=$(echo "$ref_component" | sed 's/[^a-zA-Z0-9._-]/-/g')
echo "ci_image_tag=isaac-lab-ci:${sanitized_ref}-${SHA}" >> "$GITHUB_OUTPUT"
echo "CI image tag: isaac-lab-ci:${sanitized_ref}-${SHA}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Duplicated ci_image_tag formula divergence risk

The ci_image_tag computation (pr-<number> vs. ref_name, sanitize, append SHA) is duplicated between arm-ci.yml and build.yaml's config job. Both produce independent tags for their respective images, which is correct, but if the naming formula is ever changed in one file (e.g., adding a prefix, changing the separator), the other must be updated manually. A stale discrepancy would be invisible until someone tries to correlate an arm64 image tag with an x86 image tag from the same run. At minimum, a comment in each config job pointing to the other would help future editors keep them in sync.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is valid but I would say non-blocking since this is already commented here and is a nit

- Rename the reusable detect-changes output run_docker_tests ->
  should_run, since the shared gate now drives arm-ci as well as the
  Docker + Tests jobs; both callers updated.
- Add cross-reference comments in each config job noting the
  ci_image_tag formula is intentionally duplicated (independent -arm64
  and x86 images) and must be kept in sync.
# Dockerfile.base copies (pyproject.toml, environment.yml, isaaclab.*) that a
# path filter would otherwise miss.
changes:
name: Detect Changes

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion (non-blocking): Both callers name the job Detect Changes, should we add a Detect Changes (ARM) and Detect Changes (Docker)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The info is available at workflow level, e.g. ARM CI / Detect Changes / Detect Changes (pull_request).

@nvsekkin

Copy link
Copy Markdown
Collaborator

overall PR looks good, made a non-blocking comment. we can merge

hujc7 added 2 commits July 24, 2026 12:03
Convert the shared change-detection gate from a reusable workflow
(.github/workflows/detect-changes.yml) to a composite action
(.github/actions/detect-changes), matching the repo convention: all
shared CI logic lives under .github/actions/ and there were no reusable
workflows before.

This also flattens the check name a reviewer flagged: a reusable-workflow
call renders as 'ARM CI / Detect Changes / Detect Changes' (workflow /
caller job / inner job), whereas the composite action runs as steps in a
single job -> 'ARM CI / Detect Changes', distinguished from the Docker +
Tests copy by the workflow name. The changes job now checks out sparsely
and calls the action, like every other action caller in the repo.
The job's check now reads 'ARM CI / Build & Test' instead of the
redundant 'ARM CI / arm-ci' — the workflow name already conveys the
platform, so the job name should describe what it does (build + marker
tests). Job id stays 'arm-ci'.
@kellyguo11
kellyguo11 merged commit 11ae551 into isaac-sim:develop Jul 25, 2026
42 of 43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants