Skip to content

gitea.cli.utils.options

options

The options every resource command shares, and how they are read.

The CLI names a target the same way in every command family:

  • --owner names the user or organization that owns the target.
  • --repository narrows the target to one repository of that owner. It is optional everywhere. Omitting it asks for the owner-wide target, which is what the project commands act on; a command whose endpoint has no owner-wide form reports that it needs a repository, rather than leaving the parser to reject the invocation with a message that never mentions the organization case.
  • An entity is named by --<entity>-id: --issue-id, --project-id, --column-id, --label-id, --comment-id, --workflow-id, --run-id, --job-id, --artifact-id, --runner-id. The two entities Gitea addresses by name rather than by number - a secret and a variable - are named by --secret-name and --variable-name, since --secret-id would promise a number the API does not have.
  • --admin asks for the instance-wide form of an endpoint, where one exists. It belongs to no owner, so it is refused together with --owner.

A second target in the same command carries its own coordinates, and those are required together because there is no scope for them to fall back to: issue dependency takes --dependency-owner, --dependency-repository and --dependency-issue-id for the issue being depended on.

The helpers here are that reading, kept in one place so the wording of the errors does not drift between command families. They raise CommandError, so call them from inside the api_call that execute_api_command wraps and the user sees the message alone rather than a traceback.

Classes

Functions:

gitea.cli.utils.options.reporting_scope_errors

reporting_scope_errors(command: str) -> Iterator[None]

Report coordinates that name no endpoint as a CLI error rather than a traceback.

The rule about which scopes an Actions endpoint has lives in gitea.actions.scope, once, and is enforced there for every caller - so the CLI does not restate it, which is how the two would come to disagree. What it does instead is turn the library's ValueError into a CommandError, so the user sees the sentence and not a stack trace.

Parameters:

Name Type Description Default
command str

The command being run, named as the user invoked it.

required

Yields:

Type Description
None

Nothing; the block runs inside the conversion.

Raises:

Type Description
CommandError

If the block rejected the coordinates it was given.

Source code in src/gitea/cli/utils/options.py
@contextmanager
def reporting_scope_errors(command: str) -> Iterator[None]:
    """Report coordinates that name no endpoint as a CLI error rather than a traceback.

    The rule about which scopes an Actions endpoint has lives in
    `gitea.actions.scope`, once, and is enforced there for every caller - so the
    CLI does not restate it, which is how the two would come to disagree. What it
    does instead is turn the library's `ValueError` into a `CommandError`, so the
    user sees the sentence and not a stack trace.

    Args:
        command: The command being run, named as the user invoked it.

    Yields:
        Nothing; the block runs inside the conversion.

    Raises:
        CommandError: If the block rejected the coordinates it was given.

    """
    try:
        yield
    except ValueError as e:
        raise CommandError(f"'{command}' was given coordinates it cannot address: {e}") from e

gitea.cli.utils.options.require_repository

require_repository(
    repository: str | None, *, command: str
) -> str

Read --repository for a command whose endpoint always needs one.

--repository is optional on every command, so omitting it is a request for the owner-wide target. The commands here have no owner-wide endpoint to serve that with, and the error says so instead of letting the request reach a URL with an empty path segment in it.

Parameters:

Name Type Description Default
repository str | None

The value passed as --repository, or None when omitted.

required
command str

The command being run, named as the user invoked it.

required

Returns:

Type Description
str

The name of the repository.

Raises:

Type Description
CommandError

If --repository was omitted.

Source code in src/gitea/cli/utils/options.py
def require_repository(repository: str | None, *, command: str) -> str:
    """Read `--repository` for a command whose endpoint always needs one.

    `--repository` is optional on every command, so omitting it is a request
    for the owner-wide target. The commands here have no owner-wide endpoint to
    serve that with, and the error says so instead of letting the request reach
    a URL with an empty path segment in it.

    Args:
        repository: The value passed as --repository, or None when omitted.
        command: The command being run, named as the user invoked it.

    Returns:
        The name of the repository.

    Raises:
        CommandError: If --repository was omitted.

    """
    if repository is None:
        raise CommandError(
            f"'{command}' needs a repository: pass --repository REPOSITORY. "
            f"Omitting --repository asks for the target of the owner itself, which only the "
            f"'gitea-cli project' commands have."
        )
    return repository

gitea.cli.utils.options.resolve_issue_id

resolve_issue_id(
    *,
    issue_id: int | None,
    index: int | None,
    command: str,
    option: str = "--issue-id",
    deprecated_option: str = "--index",
) -> int

Read the option naming which issue a command acts on.

The issue is named by --issue-id in every command family. The older name --index is still accepted so that existing scripts keep working, and using it logs a deprecation warning naming its replacement.

Parameters:

Name Type Description Default
issue_id int | None

The value passed as the current option, or None when omitted.

required
index int | None

The value passed as the deprecated option, or None when omitted.

required
command str

The command being run, named as the user invoked it.

required
option str

The current name of the option.

'--issue-id'
deprecated_option str

The deprecated name of the option.

'--index'

Returns:

Type Description
int

The issue the command acts on.

Raises:

Type Description
CommandError

If neither option was passed, or both were passed with different values.

Source code in src/gitea/cli/utils/options.py
def resolve_issue_id(
    *,
    issue_id: int | None,
    index: int | None,
    command: str,
    option: str = "--issue-id",
    deprecated_option: str = "--index",
) -> int:
    """Read the option naming which issue a command acts on.

    The issue is named by `--issue-id` in every command family. The older name
    `--index` is still accepted so that existing scripts keep working, and
    using it logs a deprecation warning naming its replacement.

    Args:
        issue_id: The value passed as the current option, or None when omitted.
        index: The value passed as the deprecated option, or None when omitted.
        command: The command being run, named as the user invoked it.
        option: The current name of the option.
        deprecated_option: The deprecated name of the option.

    Returns:
        The issue the command acts on.

    Raises:
        CommandError: If neither option was passed, or both were passed with
            different values.

    """
    if index is None:
        if issue_id is None:
            raise CommandError(f"'{command}' needs an issue: pass {option} NUMBER.")
        return issue_id

    if issue_id is not None and issue_id != index:
        raise CommandError(
            f"{option} and {deprecated_option} name the same issue but were given different values "
            f"({issue_id} and {index}). {deprecated_option} is the deprecated name of {option}: pass only {option}."
        )

    logger.warning("%s is deprecated and will be removed; pass %s instead.", deprecated_option, option)
    return index if issue_id is None else issue_id