name: Team Request NVSkills CI on: workflow_call: secrets: NVSKILLS_CI_DISPATCH_TOKEN: required: false permissions: contents: read pull-requests: read statuses: read jobs: require-nvskills-ci: if: github.event_name == 'pull_request' permissions: contents: read pull-requests: read statuses: read uses: ./.github/workflows/require-nvskills-status.yml request: if: > (github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/nvskills-ci')) || (github.event_name == 'push' && github.actor == (vars.NVSKILLS_SIGNATURE_PUSH_ACTOR || 'nv-skills-ci[bot]') && startsWith(github.event.head_commit.message, vars.NVSKILLS_SIGNATURE_COMMIT_TITLE || 'Attach NVSkills validation signatures')) runs-on: ubuntu-latest concurrency: group: nvskills-ci-request-${{ github.repository }}-${{ github.event.issue.number || github.sha }} cancel-in-progress: true steps: - name: Validate requester permission if: ${{ github.event_name == 'issue_comment' }} env: GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} ACTOR: ${{ github.actor }} run: | set -euo pipefail role_name="$(gh api "repos/${REPO}/collaborators/${ACTOR}/permission" --jq '.role_name // ""')" case "${role_name}" in admin|maintain) ;; *) echo "Requester must have maintain or admin permission"; exit 1 ;; esac - name: Resolve request context id: context env: GH_TOKEN: ${{ github.token }} EVENT_NAME: ${{ github.event_name }} REPO: ${{ github.repository }} ISSUE_PR_NUMBER: ${{ github.event.issue.number || '' }} HEAD_SHA: ${{ github.sha }} HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message || '' }} SIGNATURE_COMMIT_TITLE: ${{ vars.NVSKILLS_SIGNATURE_COMMIT_TITLE || 'Attach NVSkills validation signatures' }} SIGNATURE_PUSH_ACTOR: ${{ vars.NVSKILLS_SIGNATURE_PUSH_ACTOR || 'nv-skills-ci[bot]' }} ACTOR: ${{ github.actor }} run: | set -euo pipefail owner="${REPO%%/*}" repo="${REPO#*/}" pr_number="${ISSUE_PR_NUMBER}" commit_title="$(printf '%s' "${HEAD_COMMIT_MESSAGE}" | sed -n '1p')" if [ "${EVENT_NAME}" = "push" ]; then if [ "${commit_title}" != "${SIGNATURE_COMMIT_TITLE}" ]; then echo "Push is not the configured NVSkills signature commit; skipping dispatch." exit 0 fi if [ "${ACTOR}" != "${SIGNATURE_PUSH_ACTOR}" ]; then echo "Push actor ${ACTOR} is not the configured NVSkills signing actor; skipping dispatch." exit 0 fi prs_json="$(curl -fsSL \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${owner}/${repo}/commits/${HEAD_SHA}/pulls")" pr_number="$(printf '%s' "${prs_json}" | jq -r '[.[] | select(.state == "open")][0].number // empty')" if [ -z "${pr_number}" ]; then echo "No open pull request is associated with the signature commit; skipping dispatch." exit 0 fi fi if [ -z "${pr_number}" ]; then echo "Pull request number could not be resolved." exit 1 fi pr_json="$(curl -fsSL \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${owner}/${repo}/pulls/${pr_number}")" head_sha="$(printf '%s' "${pr_json}" | jq -r '.head.sha')" base_ref="$(printf '%s' "${pr_json}" | jq -r '.base.ref')" if [ "${EVENT_NAME}" != "push" ]; then commit_json="$(curl -fsSL \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${owner}/${repo}/commits/${head_sha}")" commit_title="$(printf '%s' "${commit_json}" | jq -r '.commit.message | split("\n")[0]')" fi has_watched_change=false page=1 while true; do files_json="$(curl -fsSL \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${owner}/${repo}/pulls/${pr_number}/files?per_page=100&page=${page}")" if printf '%s' "${files_json}" | jq -e ' def watched: (. // "") | startswith("skills/") or startswith("team-skills/") or startswith("rules/team-rules/") or startswith("plugins/"); any(.[]; (.filename | watched) or (.previous_filename? | watched)) ' >/dev/null; then has_watched_change=true break fi if [ "$(printf '%s' "${files_json}" | jq 'length')" -lt 100 ]; then break fi page=$((page + 1)) done if [ "${has_watched_change}" != "true" ]; then { echo "## NVSkills CI request" echo echo "Skipped: no changes under \`skills/\`, \`team-skills/\`, \`rules/team-rules/\`, or \`plugins/\`." } >> "${GITHUB_STEP_SUMMARY}" exit 0 fi { echo "should_dispatch=true" echo "pr_number=${pr_number}" echo "head_sha=${head_sha}" echo "base_ref=${base_ref}" echo "commit_title=${commit_title}" } >> "${GITHUB_OUTPUT}" - name: Dispatch NVSkills CI if: steps.context.outputs.should_dispatch == 'true' env: GH_TOKEN: ${{ secrets.NVSKILLS_CI_DISPATCH_TOKEN }} REPO: ${{ github.repository }} PR_NUMBER: ${{ steps.context.outputs.pr_number }} REQUEST_HEAD_SHA: ${{ steps.context.outputs.head_sha }} REQUEST_BASE_REF: ${{ steps.context.outputs.base_ref }} REQUEST_COMMIT_TITLE: ${{ steps.context.outputs.commit_title }} REQUEST_COMMENT_ID: ${{ github.event.comment.id || '' }} REQUEST_RUN_ID: ${{ github.run_id }} REQUESTED_BY: ${{ github.actor }} run: | set -euo pipefail if [ -z "${GH_TOKEN}" ]; then echo "Missing NVSKILLS_CI_DISPATCH_TOKEN secret." exit 1 fi owner="${REPO%%/*}" repo="${REPO#*/}" gh workflow run nvskills-ci.yml \ -R NVIDIA/nvskills-ci \ --ref main \ -f source_owner="${owner}" \ -f source_repo="${repo}" \ -f pr_number="${PR_NUMBER}" \ -f request_run_id="${REQUEST_RUN_ID}" \ -f request_head_sha="${REQUEST_HEAD_SHA}" \ -f request_base_ref="${REQUEST_BASE_REF}" \ -f request_commit_title="${REQUEST_COMMIT_TITLE}" \ -f request_comment_id="${REQUEST_COMMENT_ID}" \ -f requested_by="${REQUESTED_BY}"