Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# Configure the GitLab pipeline schedule with cron `12 9 * * *`.
# Push a raw SemVer tag, such as `0.1.0` or `0.1.0-alpha.20260515`,
# to run the publishing pipeline.
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH
- when: never

Expand Down Expand Up @@ -51,7 +52,7 @@ collect:github-artifacts:
name: alpine:3.22
pull_policy: if-not-present
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG
- when: never
before_script:
- apk add --no-cache findutils github-cli unzip
Expand All @@ -67,25 +68,19 @@ collect:github-artifacts:

mkdir -p collected/wheels collected/wasm collected/node downloaded

version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n1)"
if [ -z "$version" ]; then
echo "Error: failed to read workspace version from Cargo.toml." >&2
exit 1
fi
if ! printf '%s\n' "$version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Error: workspace version must be a stable SemVer base for nightly alpha tags: ${version}" >&2
tag="${CI_COMMIT_TAG:-}"
if [ -z "$tag" ]; then
echo "Error: CI_COMMIT_TAG is required to collect GitHub Actions artifacts for publishing." >&2
exit 1
fi

tag_date="$(date -u +%Y%m%d)"
tag="${version}-alpha.${tag_date}"
tag_ref="tags/${tag}"
deadline="$(( $(date -u +%s) + NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS ))"

echo "Waiting for nightly alpha tag ${tag} in ${NEMO_FLOW_CI_GITHUB_REPOSITORY}"
echo "Waiting for tag ${tag} in ${NEMO_FLOW_CI_GITHUB_REPOSITORY}"
while ! gh api "repos/${NEMO_FLOW_CI_GITHUB_REPOSITORY}/git/ref/${tag_ref}" >/dev/null 2>&1; do
if [ "$(date -u +%s)" -ge "$deadline" ]; then
echo "Error: nightly alpha tag ${tag} did not appear within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2
echo "Error: tag ${tag} did not appear within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2
exit 1
fi
sleep "$NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS"
Expand All @@ -108,13 +103,13 @@ collect:github-artifacts:
break
fi
if [ "$(date -u +%s)" -ge "$deadline" ]; then
echo "Error: no GitHub Actions run found for nightly alpha tag ${tag} within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2
echo "Error: no GitHub Actions run found for tag ${tag} within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds." >&2
exit 1
fi
sleep "$NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS"
done
if [ -z "$run_id" ]; then
echo "Error: no GitHub Actions run found for nightly alpha tag ${tag}." >&2
echo "Error: no GitHub Actions run found for tag ${tag}." >&2
exit 1
fi

Expand All @@ -124,13 +119,13 @@ collect:github-artifacts:
--json url \
--jq '.url'
)"
echo "Watching GitHub Actions run ${run_id} for nightly alpha tag ${tag}: ${run_html_url}"
echo "Watching GitHub Actions run ${run_id} for tag ${tag}: ${run_html_url}"
if ! timeout "$NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS" \
gh run watch "$run_id" \
--repo "$NEMO_FLOW_CI_GITHUB_REPOSITORY" \
--interval "$NEMO_FLOW_CI_GITHUB_RUN_POLL_SECONDS" \
--exit-status; then
echo "Error: GitHub Actions run ${run_id} for nightly alpha tag ${tag} failed, was cancelled, or did not complete within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds: ${run_html_url}" >&2
echo "Error: GitHub Actions run ${run_id} for tag ${tag} failed, was cancelled, or did not complete within ${NEMO_FLOW_CI_GITHUB_RUN_WAIT_SECONDS} seconds: ${run_html_url}" >&2
exit 1
fi

Expand Down Expand Up @@ -169,7 +164,7 @@ collect:github-artifacts:
printf '}\n'
} > collected/github-run.json
artifacts:
name: github-nightly-package-artifacts
name: github-package-artifacts
when: on_success
expire_in: 7 days
paths:
Expand All @@ -184,7 +179,7 @@ publish:artifactory:wheels:
name: ghcr.io/astral-sh/uv:${NEMO_FLOW_CI_UV_VERSION}-${NEMO_FLOW_CI_DEBIAN_VERSION}-slim
pull_policy: if-not-present
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG
- when: never
needs:
- job: collect:github-artifacts
Expand Down Expand Up @@ -213,7 +208,7 @@ publish:artifactory:cargo:
name: rust:${NEMO_FLOW_CI_RUST_VERSION}-${NEMO_FLOW_CI_DEBIAN_VERSION}
pull_policy: if-not-present
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG
- when: never
needs:
- job: collect:github-artifacts
Expand Down Expand Up @@ -261,6 +256,8 @@ publish:artifactory:cargo:
mkdir -p "$cargo_home"

cat > "${cargo_home}/config.toml" <<EOF
[registry]
global-credential-providers = ["cargo:token"]
[registries]
artifactory = { index = "sparse+${NEMO_FLOW_CI_ARTIFACTORY_CARGO_URL}" }
EOF
Expand Down Expand Up @@ -298,7 +295,7 @@ publish:artifactory:npm:
name: node:${NEMO_FLOW_CI_NODE_VERSION}-${NEMO_FLOW_CI_DEBIAN_VERSION}
pull_policy: if-not-present
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
- if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_TAG
- when: never
needs:
- job: collect:github-artifacts
Expand Down
15 changes: 15 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ The release pipeline publishes these package surfaces from a tag push:
Go remains source-first. There is no separate Go package-manager publication
step in the repository release workflow.

The mirrored GitLab pipeline also publishes the same tag's collected package
artifacts to NVIDIA Artifactory. It is driven by the tag push, not by a GitLab
pipeline schedule.
Comment thread
willkill07 marked this conversation as resolved.

## Version Model

NeMo Flow versions are anchored on the workspace SemVer in the repository root
Expand Down Expand Up @@ -260,6 +264,17 @@ The workflow boundary is split intentionally:
- This layout also satisfies the official `pypa/gh-action-pypi-publish`
guidance that trusted publishing should not run inside reusable workflows.

The mirrored GitLab pipeline in [`.gitlab-ci.yml`](.gitlab-ci.yml) handles
NVIDIA Artifactory publication for the same tag:

- GitLab starts the pipeline from a tag push through `CI_COMMIT_TAG`; no GitLab
cron or pipeline schedule is required.
- The collector waits for the mirrored GitHub tag and matching GitHub Actions
run, then downloads the wheel, Cargo, Node.js, and WebAssembly package
artifacts produced by GitHub Actions.
- The Artifactory jobs publish those collected artifacts to the configured
Python, Cargo, and npm Artifactory registries.

npm trusted publishing has its own registry-side constraints:

- Each npm package can only have one trusted publisher configured at a time.
Expand Down