diff --git a/AGENTS.md b/AGENTS.md index e66437159b..7cd5eb254c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,26 +14,103 @@ guide for package-specific conventions and workflows. # Pull requests -**Never push branches or commits to the upstream repo (github.com/NVIDIA/cuda-python). -Treat it as read-only.** All branch creation and pushes must go to the contributor's -personal fork. Before pushing, confirm which remote points to the contributor's -personal fork (not `upstream`) by running `git remote -v`, then push there -(`git push `). Open the PR from that fork with -`gh pr create`. Do not use `git push upstream` or any command that writes to -the `upstream` remote. - -When creating pull requests with `gh pr create`, always assign at least one -label and a milestone. CI enforces this via the `pr-metadata-check` workflow -and will block PRs that are missing labels or a milestone. Use `--label` and -`--milestone` flags, for example: +Treat the canonical repository used as the pull-request base as read-only by +default. Push branches and commits to an approved fork, which may be owned by +either a personal account or an organization. + +Before pushing: + +- Run `git remote -v` and resolve the complete `OWNER/REPOSITORY` names of the + base repository and intended fork. +- Confirm that the push target is a fork of the base repository and is not the + base repository itself. Compare complete repository names; the owner alone + is not sufficient to distinguish them. +- Push using the explicit fork remote and branch, for example + `git push `. + +Do not push to the canonical repository unless the user explicitly requests, +in the current conversation, a push to a specific branch in that repository. +This can be necessary, for example, to test workflows that run only for +upstream branches. Before such a push, verify the exact `OWNER/REPOSITORY`, +remote, and destination branch. Authorization to push a test branch does not +authorize pushing to a default or protected branch, creating tags, +force-pushing, or deleting branches; those actions require separate explicit +authorization. + +Use `gh pr create` when it can identify the fork unambiguously. Always select +the base repository explicitly with `--repo /`. +When the head is an organization-owned fork that `gh pr create` cannot +identify, create the pull request through the GraphQL API. Follow the +applicable pull-request template when preparing the body because the API does +not populate the template automatically. + +For the API fallback, resolve these values from the remotes and intended PR: ``` -gh pr create --title "..." --body "..." --label "bug" --milestone "v1.0" +BASE_REPO="/" +BASE_BRANCH="" +BASE_REPO_ID="" +HEAD_REPO="/" +HEAD_REPO_ID="" +HEAD_BRANCH="" +BODY_FILE="" ``` -If you are unsure which label or milestone to use, check the existing labels -and milestones on the repository with `gh label list` and `gh api -repos/{owner}/{repo}/milestones --jq '.[].title'`, and pick the best match. +Obtain the node IDs with `gh api "repos/${BASE_REPO}" --jq '.node_id'` and +`gh api "repos/${HEAD_REPO}" --jq '.node_id'`. Then create the PR with +`headRepositoryId` to identify the organization-owned fork: + +``` +gh api graphql \ + -f repositoryId="${BASE_REPO_ID}" \ + -f headRepositoryId="${HEAD_REPO_ID}" \ + -f baseRefName="${BASE_BRANCH}" \ + -f headRefName="${HEAD_BRANCH}" \ + -f title="" \ + -F body="@${BODY_FILE}" \ + -F draft=false \ + -f query=' + mutation CreatePullRequest( + $repositoryId: ID! + $headRepositoryId: ID! + $baseRefName: String! + $headRefName: String! + $title: String! + $body: String! + $draft: Boolean! + ) { + createPullRequest(input: { + repositoryId: $repositoryId + headRepositoryId: $headRepositoryId + baseRefName: $baseRefName + headRefName: $headRefName + title: $title + body: $body + draft: $draft + }) { + pullRequest { number url } + } + }' \ + --jq '.data.createPullRequest.pullRequest' +``` + +Use `-F draft=true` instead when a draft pull request is intended. + +Every pull request must have at least one assignee, one label, and a milestone, +regardless of how it was created. CI enforces this via the +`pr-metadata-check` workflow. With `gh pr create`, use the `--assignee`, +`--label`, and `--milestone` flags. After the API fallback, use the returned PR +number with the base repository explicitly: + +``` +gh pr edit <pr-number> --repo "${BASE_REPO}" \ + --add-assignee "<assignee>" --add-label "<label>" \ + --milestone "<milestone>" +``` + +If you are unsure which label or milestone to use, inspect the base repository +with `gh label list --repo "${BASE_REPO}"` and `gh api +"repos/${BASE_REPO}/milestones" --jq '.[].title'`, then pick the best match. # General