From f437d984d6a47f778d45a29897d50c0a97af3c16 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah Date: Sun, 21 Jun 2026 20:48:06 -0700 Subject: [PATCH] Make gh issue assignee configurable --- .ai-context/COMMANDS.md | 7 +- .ai-context/WORKFLOWS.md | 4 + .github/base-project.yml | 1 + AGENTS.md | 4 +- cli/bash/commands/basectl/README.md | 6 +- cli/bash/commands/basectl/subcommands/gh.sh | 107 +++++++++++++++--- .../commands/basectl/tests/completions.bats | 2 + cli/bash/commands/basectl/tests/gh.bats | 72 ++++++++++-- .../base_github_projects/project_config.py | 2 +- .../base_github_projects/project_configure.py | 8 +- .../base_github_projects/tests/test_engine.py | 11 +- docs/github-workflow.md | 18 +-- lib/shell/completions/basectl_completion.sh | 2 +- 13 files changed, 202 insertions(+), 42 deletions(-) diff --git a/.ai-context/COMMANDS.md b/.ai-context/COMMANDS.md index 97015140..a9207b57 100644 --- a/.ai-context/COMMANDS.md +++ b/.ai-context/COMMANDS.md @@ -49,8 +49,11 @@ the canonical current command list. hygiene, and Project metadata using Base conventions. - `basectl gh issue create` defaults to category `enhancement` when `--category` is omitted and prints that default in command output. Pass - `--size ` when the issue scope is clear; otherwise Project - metadata defaults to `Size=S`. + `--assignee ` to assign an issue, or set + `project.issue_defaults.assignee` in `.github/base-project.yml` for a + repo-local default. Pass `--no-assignee` to ignore that default for one + issue. Pass `--size ` when the issue scope is clear; otherwise + Project metadata defaults to `Size=S`. - `basectl gh pr create` auto-injects `Fixes #` from Base branch names; pass `--no-fixes` to suppress that body injection. - `basectl gh project doctor --project ` - inspect Project metadata diff --git a/.ai-context/WORKFLOWS.md b/.ai-context/WORKFLOWS.md index a6fe4336..24f940a8 100644 --- a/.ai-context/WORKFLOWS.md +++ b/.ai-context/WORKFLOWS.md @@ -22,6 +22,10 @@ Use the smallest accurate `Size` when creating issues: `T` for tiny obvious work, `S` for normal small work or unknown scope, `M` for interacting changes, and `L` only for work that should probably be split. The default remains `S` when automation cannot infer scope. +Issue creation is unassigned by default unless `basectl gh issue create` +receives `--assignee <login>` or `.github/base-project.yml` sets +`project.issue_defaults.assignee`; use `--no-assignee` to skip that repo-local +default for a specific issue. Base-managed repositories should carry `.github/workflows/project-intake.yml` as the fallback for issues created outside `basectl gh issue create`. diff --git a/.github/base-project.yml b/.github/base-project.yml index c656b30d..e790b1ec 100644 --- a/.github/base-project.yml +++ b/.github/base-project.yml @@ -25,3 +25,4 @@ project: area: Product initiative: Adoption Polish size: S + assignee: codeforester diff --git a/AGENTS.md b/AGENTS.md index 89df2c81..b5a74536 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,9 @@ them. - Use one primary category label: `bug`, `enhancement`, `documentation`, `ci`, or `security`. - Do not create or apply `type:*` issue labels. -- Assign Codex-created issues to `codeforester` when GitHub allows it. +- Assign Codex-created Base repository issues to `codeforester` when GitHub + allows it; `.github/base-project.yml` carries this repo-local default for + `basectl gh issue create`. - For issues tracked in Base Roadmap, set Project `Status` to `In Progress` before implementation starts, move it to `In Review` when the PR opens, and verify `Done` after merge/closure. If Project V2 access or item state diff --git a/cli/bash/commands/basectl/README.md b/cli/bash/commands/basectl/README.md index 94bf5e93..a14a902c 100644 --- a/cli/bash/commands/basectl/README.md +++ b/cli/bash/commands/basectl/README.md @@ -73,8 +73,10 @@ such command directories exist. Optional utility CLIs such as `caff` and hygiene, and GitHub Project metadata using Base's opinionated workflow. It uses standard GitHub-style issue categories such as `bug`, `enhancement`, `documentation`, `ci`, and `security`, and derives branch names from those - categories. Prefer this command for Base repository GitHub workflows when it - supports the task. + categories. Issue creation is unassigned by default unless `--assignee` is + passed or `.github/base-project.yml` sets `project.issue_defaults.assignee`. + Prefer this command for Base repository GitHub workflows when it supports the + task. - `basectl onboard` guides first-run setup around existing setup, check, doctor, profile, and project-discovery primitives. See `docs/basectl-onboard.md`. diff --git a/cli/bash/commands/basectl/subcommands/gh.sh b/cli/bash/commands/basectl/subcommands/gh.sh index 38b201b5..ff546dbc 100644 --- a/cli/bash/commands/basectl/subcommands/gh.sh +++ b/cli/bash/commands/basectl/subcommands/gh.sh @@ -8,7 +8,7 @@ base_gh_usage() { cat <<'EOF' Usage: basectl gh issue list [gh options...] - basectl gh issue create [--category <bug|enhancement|documentation|ci|security>] --title <title> [--body <body>] [--repo <owner/name>] [--size <T|S|M|L>] [project options...] + basectl gh issue create [--category <bug|enhancement|documentation|ci|security>] --title <title> [--body <body>] [--repo <owner/name>] [--assignee <login>|--no-assignee] [--size <T|S|M|L>] [project options...] basectl gh issue start <number> [--category <bug|enhancement|documentation|ci|security>] [--title <title>] basectl gh pr create [--no-fixes] [gh options...] basectl gh pr status [gh options...] @@ -32,6 +32,8 @@ Branch naming: Issue create project options: --repo <owner/name> Repository to create the issue in. Defaults to the origin remote. --category <category> Issue label category. Defaults to enhancement. + --assignee <login> Assign the issue to a GitHub login. + --no-assignee Do not assign the issue, even when repo config has a default. --project <title> Project to update. Defaults to the repository name. --project-owner <login> Project owner. Defaults to the repository owner. --size <T|S|M|L> Project Size value. Defaults to .github/base-project.yml or S. @@ -42,7 +44,8 @@ Issue categories: Notes: - This command requires the GitHub CLI (`gh`) for GitHub operations. - - Issues created through this command are assigned to codeforester. + - Issues are unassigned unless --assignee is passed or .github/base-project.yml + sets project.issue_defaults.assignee. - When the GitHub repo is known, issue create also adds the issue to the repo-named Project and applies defaults from .github/base-project.yml. - PR creation auto-injects Fixes #<issue> when the branch follows the Base @@ -56,7 +59,7 @@ base_gh_issue_usage() { cat <<'EOF' Usage: basectl gh issue list [gh options...] - basectl gh issue create [--category <bug|enhancement|documentation|ci|security>] --title <title> [--body <body>] [--repo <owner/name>] [--size <T|S|M|L>] [project options...] + basectl gh issue create [--category <bug|enhancement|documentation|ci|security>] --title <title> [--body <body>] [--repo <owner/name>] [--assignee <login>|--no-assignee] [--size <T|S|M|L>] [project options...] basectl gh issue start <number> [--category <bug|enhancement|documentation|ci|security>] [--title <title>] Purpose: @@ -68,12 +71,15 @@ Branch naming: Issue create project options: --repo <owner/name> Repository to create the issue in. Defaults to the origin remote. --category <category> Issue label category. Defaults to enhancement. + --assignee <login> Assign the issue to a GitHub login. + --no-assignee Do not assign the issue, even when repo config has a default. --project <title> Project to update. Defaults to the repository name. --project-owner <login> Project owner. Defaults to the repository owner. --size <T|S|M|L> Project Size value. Defaults to .github/base-project.yml or S. --no-project Skip Project metadata updates. Default category: enhancement. +Default assignee: none unless project.issue_defaults.assignee is set in .github/base-project.yml. Categories: bug, enhancement, documentation, ci, security. EOF } @@ -330,6 +336,50 @@ base_gh_project_config_path() { printf '%s\n' "$path" } +base_gh_trim_scalar() { + printf '%s' "$1" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' +} + +base_gh_issue_default_assignee_from_config() { + local in_defaults=0 + local in_project=0 + local line path trimmed value + + path="$1" + while IFS= read -r line || [[ -n "$line" ]]; do + trimmed="$(base_gh_trim_scalar "$line")" + [[ -n "$trimmed" && "$trimmed" != \#* ]] || continue + + if [[ "$line" != [[:space:]]* ]]; then + in_defaults=0 + if [[ "$trimmed" == "project:" ]]; then + in_project=1 + else + in_project=0 + fi + continue + fi + + if ((in_project)) && [[ "$line" == " "* && "$line" != " "* ]]; then + if [[ "$trimmed" == "issue_defaults:" ]]; then + in_defaults=1 + else + in_defaults=0 + fi + continue + fi + + if ((in_project)) && ((in_defaults)) && [[ "$line" == " "* && "$trimmed" == assignee:* ]]; then + value="$(base_gh_trim_scalar "${trimmed#assignee:}")" + [[ -n "$value" ]] || return 1 + printf '%s\n' "$value" + return 0 + fi + done <"$path" + + return 1 +} + base_gh_issue_number_from_output() { local output="$1" local issue_number @@ -399,13 +449,17 @@ base_gh_do_issue() { } base_gh_issue_create() { + local assignee="" + local assignee_explicit=0 local body="" local category="" local configure_project=1 local config_path="" local github_repo="" + local issue_args=() local issue_number="" local issue_output="" + local no_assignee=0 local project_owner="" local project_size="" local project_title="" @@ -425,6 +479,14 @@ base_gh_issue_create() { title="${2:-}" shift ;; + --assignee) + assignee="${2:-}" + assignee_explicit=1 + shift + ;; + --no-assignee) + no_assignee=1 + ;; --body) body="${2:-}" shift @@ -468,21 +530,37 @@ base_gh_issue_create() { if [[ -n "$project_size" ]]; then base_gh_validate_project_size "$project_size" || return 1 fi + if ((assignee_explicit)) && ((no_assignee)); then + base_gh_error "Options '--assignee' and '--no-assignee' cannot be used together." + return 1 + fi + if ((assignee_explicit)) && [[ -z "$assignee" ]]; then + base_gh_error "Option '--assignee' requires an argument." + return 1 + fi [[ -n "$github_repo" ]] || github_repo="$(base_gh_infer_github_repo || true)" + config_path="$(base_gh_project_config_path || true)" + if ((assignee_explicit)); then + : + elif ((no_assignee)); then + assignee="" + elif [[ -n "$config_path" ]]; then + assignee="$(base_gh_issue_default_assignee_from_config "$config_path" || true)" + fi + + issue_args=(issue create --title "$title") if [[ -n "$body" ]]; then - if [[ -n "$github_repo" ]]; then - issue_output="$(base_gh_run issue create --title "$title" --body "$body" --label "$category" --assignee codeforester --repo "$github_repo")" || return $? - else - issue_output="$(base_gh_run issue create --title "$title" --body "$body" --label "$category" --assignee codeforester)" || return $? - fi - else - if [[ -n "$github_repo" ]]; then - issue_output="$(base_gh_run issue create --title "$title" --label "$category" --assignee codeforester --repo "$github_repo")" || return $? - else - issue_output="$(base_gh_run issue create --title "$title" --label "$category" --assignee codeforester)" || return $? - fi + issue_args+=(--body "$body") + fi + issue_args+=(--label "$category") + if [[ -n "$assignee" ]]; then + issue_args+=(--assignee "$assignee") + fi + if [[ -n "$github_repo" ]]; then + issue_args+=(--repo "$github_repo") fi + issue_output="$(base_gh_run "${issue_args[@]}")" || return $? printf '%s\n' "$issue_output" if ((configure_project)) && [[ -n "$github_repo" ]]; then @@ -492,7 +570,6 @@ base_gh_issue_create() { } [[ -n "$project_title" ]] || project_title="$(base_gh_default_project_title "$github_repo")" [[ -n "$project_owner" ]] || project_owner="$(base_gh_project_owner_from_repo "$github_repo")" - config_path="$(base_gh_project_config_path || true)" if [[ -n "$config_path" ]]; then local field_args=( "$issue_number" diff --git a/cli/bash/commands/basectl/tests/completions.bats b/cli/bash/commands/basectl/tests/completions.bats index 78a76f0a..f5504754 100644 --- a/cli/bash/commands/basectl/tests/completions.bats +++ b/cli/bash/commands/basectl/tests/completions.bats @@ -271,6 +271,8 @@ EOF [[ "$output" == *"--category"* ]] [[ "$output" == *"--title"* ]] [[ "$output" == *"--body"* ]] + [[ "$output" == *"--assignee"* ]] + [[ "$output" == *"--no-assignee"* ]] [[ "$output" == *"--size"* ]] [[ "$output" != *"--type"* ]] } diff --git a/cli/bash/commands/basectl/tests/gh.bats b/cli/bash/commands/basectl/tests/gh.bats index bf414cea..f836173a 100644 --- a/cli/bash/commands/basectl/tests/gh.bats +++ b/cli/bash/commands/basectl/tests/gh.bats @@ -15,7 +15,7 @@ load ./basectl_helpers.bash [[ "$output" == *"basectl gh worktree prune"* ]] [[ "$output" != *"basectl gh todo"* ]] [[ "$output" == *"<category>/<issue>-<YYYYMMDD>-<slug>"* ]] - [[ "$output" == *"assigned to codeforester"* ]] + [[ "$output" == *"sets project.issue_defaults.assignee"* ]] } @test "basectl gh issue prints area help" { @@ -26,8 +26,11 @@ load ./basectl_helpers.bash [[ "$output" == *"basectl gh issue create"* ]] [[ "$output" == *"basectl gh issue start <number>"* ]] [[ "$output" == *"Issue create project options:"* ]] + [[ "$output" == *"--assignee <login>"* ]] + [[ "$output" == *"--no-assignee"* ]] [[ "$output" == *"--size <T|S|M|L>"* ]] [[ "$output" == *"Default category: enhancement."* ]] + [[ "$output" == *"Default assignee: none unless project.issue_defaults.assignee is set in .github/base-project.yml."* ]] [[ "$output" == *"Categories: bug, enhancement, documentation, ci, security."* ]] [[ "$output" != *"basectl gh pr create"* ]] [[ "$output" != *"basectl gh worktree prune"* ]] @@ -92,7 +95,7 @@ load ./basectl_helpers.bash [[ "$output" != *"basectl gh todo plan"* ]] } -@test "basectl gh issue create applies category label and assignee" { +@test "basectl gh issue create accepts explicit assignee" { cat > "$TEST_MOCKBIN/gh" <<'EOF' #!/usr/bin/env bash if [[ "$*" == "auth status -h github.com" ]]; then @@ -110,7 +113,7 @@ EOF bash -c ' source "$BASE_HOME/base_init.sh" source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh" - base_gh_subcommand_main issue create --category bug --title "Repair branch pruning" --repo codeforester/base --no-project + base_gh_subcommand_main issue create --category bug --title "Repair branch pruning" --repo codeforester/base --assignee codeforester --no-project ' [ "$status" -eq 0 ] @@ -118,7 +121,7 @@ EOF [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Repair branch pruning --label bug --assignee codeforester --repo codeforester/base" ] } -@test "basectl gh issue create announces default category" { +@test "basectl gh issue create announces default category without forcing an assignee" { cat > "$TEST_MOCKBIN/gh" <<'EOF' #!/usr/bin/env bash if [[ "$*" == "auth status -h github.com" ]]; then @@ -134,6 +137,7 @@ EOF BASE_GH_TEST_STATE_DIR="$TEST_STATE_DIR" \ PATH="$TEST_MOCKBIN:$PATH" \ bash -c ' + cd "$HOME" source "$BASE_HOME/base_init.sh" source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh" base_gh_subcommand_main issue create --title "Default category issue" --repo codeforester/base --no-project @@ -141,7 +145,59 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"Using default --category: enhancement"* ]] - [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Default category issue --label enhancement --assignee codeforester --repo codeforester/base" ] + [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Default category issue --label enhancement --repo codeforester/base" ] +} + +@test "basectl gh issue create uses repo config assignee default" { + cat > "$TEST_MOCKBIN/gh" <<'EOF' +#!/usr/bin/env bash +if [[ "$*" == "auth status -h github.com" ]]; then + exit 0 +fi +printf '%s\n' "$*" > "${BASE_GH_TEST_STATE_DIR:?}/gh-args" +EOF + chmod +x "$TEST_MOCKBIN/gh" + + run env \ + HOME="$TEST_HOME" \ + BASE_HOME="$BASE_REPO_ROOT" \ + BASE_GH_TEST_STATE_DIR="$TEST_STATE_DIR" \ + PATH="$TEST_MOCKBIN:$PATH" \ + bash -c ' + cd "$BASE_HOME" + source "$BASE_HOME/base_init.sh" + source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh" + base_gh_subcommand_main issue create --category bug --title "Base repo issue" --repo basefoundry/base --no-project + ' + + [ "$status" -eq 0 ] + [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Base repo issue --label bug --assignee codeforester --repo basefoundry/base" ] +} + +@test "basectl gh issue create --no-assignee ignores repo config assignee default" { + cat > "$TEST_MOCKBIN/gh" <<'EOF' +#!/usr/bin/env bash +if [[ "$*" == "auth status -h github.com" ]]; then + exit 0 +fi +printf '%s\n' "$*" > "${BASE_GH_TEST_STATE_DIR:?}/gh-args" +EOF + chmod +x "$TEST_MOCKBIN/gh" + + run env \ + HOME="$TEST_HOME" \ + BASE_HOME="$BASE_REPO_ROOT" \ + BASE_GH_TEST_STATE_DIR="$TEST_STATE_DIR" \ + PATH="$TEST_MOCKBIN:$PATH" \ + bash -c ' + cd "$BASE_HOME" + source "$BASE_HOME/base_init.sh" + source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh" + base_gh_subcommand_main issue create --category bug --title "Unassigned Base repo issue" --repo basefoundry/base --no-assignee --no-project + ' + + [ "$status" -eq 0 ] + [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Unassigned Base repo issue --label bug --repo basefoundry/base" ] } @test "basectl gh issue create continues when auth status is transiently unavailable" { @@ -167,7 +223,7 @@ EOF bash -c ' source "$BASE_HOME/base_init.sh" source "$BASE_HOME/cli/bash/commands/basectl/subcommands/gh.sh" - base_gh_subcommand_main issue create --category bug --title "Make auth preflight resilient" --repo codeforester/base --no-project + base_gh_subcommand_main issue create --category bug --title "Make auth preflight resilient" --repo codeforester/base --assignee codeforester --no-project ' [ "$status" -eq 0 ] @@ -231,7 +287,7 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"https://github.com/codeforester/bankbuddy/issues/51"* ]] [[ "$output" == *"project metadata updated"* ]] - [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Add transaction filter --label enhancement --assignee codeforester --repo codeforester/bankbuddy" ] + [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Add transaction filter --label enhancement --repo codeforester/bankbuddy" ] [ "$(cat "$TEST_STATE_DIR/wrapper-args")" = "--project base base_github_projects project issue set-fields 51 --project bankbuddy --owner codeforester --repo codeforester/bankbuddy --config $repo_root/.github/base-project.yml" ] } @@ -285,7 +341,7 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"https://github.com/codeforester/bankbuddy/issues/52"* ]] [[ "$output" == *"project metadata updated"* ]] - [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Fix typo --label enhancement --assignee codeforester --repo codeforester/bankbuddy" ] + [ "$(cat "$TEST_STATE_DIR/gh-args")" = "issue create --title Fix typo --label enhancement --repo codeforester/bankbuddy" ] [ "$(cat "$TEST_STATE_DIR/wrapper-args")" = "--project base base_github_projects project issue set-fields 52 --project bankbuddy --owner codeforester --repo codeforester/bankbuddy --config $repo_root/.github/base-project.yml --size T" ] } diff --git a/cli/python/base_github_projects/project_config.py b/cli/python/base_github_projects/project_config.py index 1380381f..2bcdcc06 100644 --- a/cli/python/base_github_projects/project_config.py +++ b/cli/python/base_github_projects/project_config.py @@ -17,7 +17,7 @@ class ProjectConfig: ALLOWED_PROJECT_KEYS = {"areas", "initiatives", "issue_defaults"} -ALLOWED_DEFAULT_KEYS = {"status", "priority", "size", "area", "initiative"} +ALLOWED_DEFAULT_KEYS = {"status", "priority", "size", "area", "initiative", "assignee"} def read_project_config(path: Path) -> ProjectConfig: diff --git a/cli/python/base_github_projects/project_configure.py b/cli/python/base_github_projects/project_configure.py index fc01baeb..a830f02c 100644 --- a/cli/python/base_github_projects/project_configure.py +++ b/cli/python/base_github_projects/project_configure.py @@ -91,9 +91,11 @@ def render_project_config_dry_run(config: ProjectConfig) -> None: for option in config.initiatives: print(f"[DRY-RUN] Would ensure Initiative option {option}.") if config.issue_defaults: - rendered = ", ".join( + rendered_defaults = [ f"{FIELD_OPTION_TO_PROJECT_FIELD[key]}={value}" for key, value in config.issue_defaults.items() if key in FIELD_OPTION_TO_PROJECT_FIELD - ) - print(f"[DRY-RUN] Would apply issue defaults to missing Project item fields: {rendered}.") + ] + if rendered_defaults: + rendered = ", ".join(rendered_defaults) + print(f"[DRY-RUN] Would apply issue defaults to missing Project item fields: {rendered}.") diff --git a/cli/python/base_github_projects/tests/test_engine.py b/cli/python/base_github_projects/tests/test_engine.py index caf73edc..6e09f337 100644 --- a/cli/python/base_github_projects/tests/test_engine.py +++ b/cli/python/base_github_projects/tests/test_engine.py @@ -124,6 +124,7 @@ def test_read_project_config_loads_repo_taxonomy(tmp_path: Path) -> None: " status: Backlog", " priority: P2", " size: S", + " assignee: codeforester", ) ), encoding="utf-8", @@ -133,7 +134,12 @@ def test_read_project_config_loads_repo_taxonomy(tmp_path: Path) -> None: assert config.areas == ("Demo App", "Documentation") assert config.initiatives == ("Demo Polish", "Portfolio Dashboard") - assert config.issue_defaults == {"status": "Backlog", "priority": "P2", "size": "S"} + assert config.issue_defaults == { + "status": "Backlog", + "priority": "P2", + "size": "S", + "assignee": "codeforester", + } def test_read_project_config_rejects_non_string_options(tmp_path: Path) -> None: @@ -617,7 +623,8 @@ def test_configure_command_applies_issue_defaults_from_project_config( " priority: P2\n" " area: Product\n" " initiative: Adoption Polish\n" - " size: S\n", + " size: S\n" + " assignee: codeforester\n", encoding="utf-8", ) fields = ( diff --git a/docs/github-workflow.md b/docs/github-workflow.md index 4d231190..c63aff8e 100644 --- a/docs/github-workflow.md +++ b/docs/github-workflow.md @@ -82,9 +82,10 @@ by default when a GitHub repository is available. Base copies the repository, and backfills existing repository issues. When `.github/base-project.yml` exists, Base also adds missing repo-specific `Area` and `Initiative` options from that file and applies the same file's -`issue_defaults` to Project issue items that are missing those values. -`basectl gh issue create` uses the defaults immediately when it adds newly -created issues to the repo Project. +Project-field `issue_defaults` to Project issue items that are missing those +values. The same config can set `project.issue_defaults.assignee` as a +repo-local issue creation default. `basectl gh issue create` uses those +defaults immediately when it creates an issue and adds it to the repo Project. Base-managed repositories also carry `.github/workflows/project-intake.yml`. That workflow is a repo-visible fallback for issues created through GitHub UI, @@ -124,10 +125,13 @@ over hand-written `gh` commands when those commands are available and local tooling is authenticated. `basectl gh issue create` defaults to the `enhancement` category when -`--category` is omitted and prints that choice. `basectl gh pr create` -auto-injects `Fixes #<issue>` when the current branch follows the Base -`<category>/<issue>-<YYYYMMDD>-<slug>` convention; pass `--no-fixes` when the -PR should not close the issue automatically. +`--category` is omitted and prints that choice. Issues are unassigned unless +`--assignee <login>` is passed or `.github/base-project.yml` sets +`project.issue_defaults.assignee`; pass `--no-assignee` to ignore a repo-local +default for one issue. `basectl gh pr create` auto-injects `Fixes #<issue>` +when the current branch follows the Base `<category>/<issue>-<YYYYMMDD>-<slug>` +convention; pass `--no-fixes` when the PR should not close the issue +automatically. Fallbacks are allowed when `basectl gh` does not support the needed operation, when local GitHub CLI authentication is unavailable, or when the GitHub diff --git a/lib/shell/completions/basectl_completion.sh b/lib/shell/completions/basectl_completion.sh index acc6a473..e0655d4c 100644 --- a/lib/shell/completions/basectl_completion.sh +++ b/lib/shell/completions/basectl_completion.sh @@ -200,7 +200,7 @@ _base_basectl_completion() { if ((COMP_CWORD == 3)); then _base_basectl_completion_compgen "list create start" "$cur" else - _base_basectl_completion_compgen "--category --title --body --repo --project --project-owner --size --no-project -h --help" "$cur" + _base_basectl_completion_compgen "--category --title --body --repo --assignee --no-assignee --project --project-owner --size --no-project -h --help" "$cur" fi ;; pr)