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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ You can also profile a command:
```shell
just profile --help
# or with arguments, e.g.:
just profile list-repo --format json
just profile repo list --format json
```

## Configuration
Expand Down
59 changes: 29 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@

A Python CLI for common [GitHub REST API](https://docs.github.com/en/rest) operations—list and inspect repositories, create or delete them, manage Dependabot security settings, and create deployment environments.

## Features

- Get repository details (`get-repo`)
- List repositories for the authenticated user (`list-repo`)
- Create and delete repositories (`create-repo`, `delete-repo`)
- Enable or disable Dependabot security updates (`dependabot`)
- Create deployment environments (`environment`)
- Table or JSON output for repository listings (`--format`)

## Installation

With `pip`:
Expand Down Expand Up @@ -60,20 +51,28 @@ github-rest-cli --help

## Commands

Top-level groups:

```shell
github-rest-cli repo --help
github-rest-cli dependabot --help
github-rest-cli environment --help
```

### Get a repository

```shell
github-rest-cli get-repo --name my-repo
github-rest-cli get-repo --name my-repo --org my-org
github-rest-cli get-repo --name my-repo --format json
github-rest-cli repo get --name my-repo
github-rest-cli repo get --name my-repo --org my-org
github-rest-cli repo get --name my-repo --format json
```

### List repositories

```shell
github-rest-cli list-repo
github-rest-cli list-repo --page 50 --sort pushed
github-rest-cli list-repo --role owner --format json
github-rest-cli repo list
github-rest-cli repo list --page 50 --sort pushed
github-rest-cli repo list --role owner --format json
```

| Flag | Description | Default |
Expand All @@ -86,47 +85,47 @@ github-rest-cli list-repo --role owner --format json
### Create a repository

```shell
github-rest-cli create-repo --name my-new-repo
github-rest-cli create-repo --name my-new-repo --visibility private
github-rest-cli create-repo --name my-new-repo --org my-org
github-rest-cli create-repo --name my-new-repo --empty
github-rest-cli repo create --name my-new-repo
github-rest-cli repo create --name my-new-repo --private
github-rest-cli repo create --name my-new-repo --org my-org
github-rest-cli repo create --name my-new-repo --empty
```

### Delete a repository

Prompts for confirmation unless `--yes` / `-y` is passed:

```shell
github-rest-cli delete-repo --name my-repo
github-rest-cli delete-repo --name my-repo --org my-org
github-rest-cli delete-repo --name my-repo --yes
github-rest-cli repo delete --name my-repo
github-rest-cli repo delete --name my-repo --org my-org
github-rest-cli repo delete --name my-repo --yes
```

### Dependabot security updates

```shell
github-rest-cli dependabot --name my-repo --enable
github-rest-cli dependabot --name my-repo --disable
github-rest-cli dependabot --name my-repo --org my-org --enable
github-rest-cli dependabot enable --name my-repo
github-rest-cli dependabot disable --name my-repo
github-rest-cli dependabot enable --name my-repo --org my-org
```

### Deployment environments

```shell
github-rest-cli environment --name my-repo --env production
github-rest-cli environment --name my-repo --env staging --org my-org
github-rest-cli environment create --name my-repo --env production
github-rest-cli environment create --name my-repo --env staging --org my-org
```

## Output format

`get-repo` and `list-repo` support:
`repo get` and `repo list` support:

- `table` (default) — PrettyTable display
- `json` — JSON string suitable for piping or scripting

```shell
github-rest-cli list-repo --format json
github-rest-cli get-repo --name my-repo --format table
github-rest-cli repo list --format json
github-rest-cli repo get --name my-repo --format table
```

## Contributing
Expand Down
256 changes: 3 additions & 253 deletions src/github_rest_cli/main.py
Original file line number Diff line number Diff line change
@@ -1,269 +1,19 @@
import argparse
from github_rest_cli.api import (
get_repository,
create_repository,
delete_repository,
list_repositories,
dependabot_security,
deployment_environment,
)
from importlib.metadata import version
import logging

from github_rest_cli.parser import build_parser


__version__ = version("github-rest-cli")
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")


def build_parser() -> argparse.ArgumentParser:
"""
Create parsers and subparsers for CLI arguments
"""
parser = argparse.ArgumentParser(
description="Python CLI for GitHub REST API",
)

parser.add_argument(
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
)

subparsers = parser.add_subparsers(help="GitHub REST API commands", dest="command")

# Subparser for "get-repo" function
get_repo_parser = subparsers.add_parser(
"get-repo", help="Get a repository's details"
)
get_repo_parser.add_argument(
"-n",
"--name",
help="The repository name",
required=True,
dest="name",
)
get_repo_parser.add_argument(
"-o", "--org", help="The organization name", required=False, dest="org"
)
get_repo_parser.add_argument(
"-f",
"--format",
required=False,
default="table",
choices=["table", "json"],
dest="format",
help="Format to display the repository in",
)
get_repo_parser.set_defaults(func=get_repository)

# Subparser for "list-repo" function
list_repo_parser = subparsers.add_parser(
"list-repo",
help="List your repositories",
)
list_repo_parser.add_argument(
"-r",
"--role",
required=False,
dest="role",
help="List repositories by role",
)
list_repo_parser.add_argument(
"-p",
"--page",
required=False,
default=20,
type=int,
dest="page",
help="The number of results",
)
list_repo_parser.add_argument(
"-s",
"--sort",
required=False,
default="pushed",
dest="sort",
help="List repositories sorted by",
)
list_repo_parser.add_argument(
"-f",
"--format",
required=False,
default="table",
choices=["table", "json"],
dest="format",
help="Format to display the list of repositories in",
)
list_repo_parser.set_defaults(func=list_repositories)

# Subparser for "create-repository" function
create_repo_parser = subparsers.add_parser(
"create-repo",
help="Create a new repository",
)
create_repo_parser.add_argument(
"-n",
"--name",
required=True,
dest="name",
help="The repository name",
)
create_repo_parser.add_argument(
"-v",
"--visibility",
required=False,
default="public",
dest="visibility",
help="Whether the repository is private",
)
create_repo_parser.add_argument(
"-o",
"--org",
required=False,
dest="org",
help="The organization name",
)
create_repo_parser.add_argument(
"-e",
"--empty",
required=False,
action="store_true",
dest="empty",
help="Create an empty repository",
)
create_repo_parser.set_defaults(func=create_repository)

# Subparser for "delete-repository" function
delete_repo_parser = subparsers.add_parser(
"delete-repo",
help="Delete an existing repository",
)
delete_repo_parser.add_argument(
"-n",
"--name",
required=True,
dest="name",
help="The repository name",
)
delete_repo_parser.add_argument(
"-o",
"--org",
required=False,
dest="org",
help="The organization name",
)
delete_repo_parser.add_argument(
"-y",
"--yes",
action="store_true",
dest="yes",
help="Skip the confirmation prompt and delete immediately",
)
delete_repo_parser.set_defaults(func=delete_repository)

# Subparser for "dependabot" function
dependabot_parser = subparsers.add_parser(
"dependabot",
help="Manage Dependabot settings",
)
dependabot_parser.add_argument(
"-n",
"--name",
required=True,
dest="name",
help="The repository name",
)
dependabot_parser.add_argument(
"-o",
"--org",
dest="org",
help="The organization name",
)
control_group = dependabot_parser.add_mutually_exclusive_group(required=True)
control_group.add_argument(
"--enable",
action="store_const",
const=True,
dest="control",
help="Enable dependabot security updates",
)
control_group.add_argument(
"--disable",
action="store_const",
const=False,
dest="control",
help="Disable dependabot security updates",
)
dependabot_parser.set_defaults(func=dependabot_security)

# Subparser for "deployment-environments" function
deploy_env_parser = subparsers.add_parser(
"environment",
help="Manage deployment environments",
)
deploy_env_parser.add_argument(
"-n",
"--name",
required=True,
dest="name",
help="The repository name",
)
deploy_env_parser.add_argument(
"-e",
"--env",
required=True,
dest="env",
help="Deployment environment name",
)
deploy_env_parser.add_argument(
"-o",
"--org",
required=False,
dest="org",
help="The organization name",
)
deploy_env_parser.set_defaults(func=deployment_environment)

return parser


def confirm_delete_repository(
name: str, org: str | None = None, *, yes: bool = False
) -> bool:
"""Return True if deletion should proceed."""
if yes:
return True

target = f"{org}/{name}" if org else name
answer = input(f"Delete repository '{target}'? This cannot be undone. [y/N] ")
return answer.strip().lower() in {"y", "yes"}


def cli():
parser = build_parser()
args = parser.parse_args()
command = args.command

if hasattr(args, "func"):
if command == "get-repo":
repo = args.func(args.name, args.org, args.format)
if repo is not None:
print(repo) # noqa: T201
elif command == "list-repo":
repos = args.func(args.page, args.sort, args.role, args.format)
if repos is not None:
print(repos) # noqa: T201
elif command == "create-repo":
args.func(args.name, args.visibility, args.org, args.empty)
elif command == "delete-repo":
if not confirm_delete_repository(args.name, args.org, yes=args.yes):
print("Aborted.") # noqa: T201
return
args.func(args.name, args.org)
elif command == "dependabot":
args.func(args.name, args.control, args.org)
elif command == "environment":
args.func(args.name, args.env, args.org)
else:
return False
args.func(args)
else:
parser.print_help()

Expand Down
Loading