{"id":16886800,"url":"https://github.com/jlevy/ghizmo","last_synced_at":"2025-05-07T15:21:47.800Z","repository":{"id":57434222,"uuid":"41706495","full_name":"jlevy/ghizmo","owner":"jlevy","description":"The missing command line for GitHub","archived":false,"fork":false,"pushed_at":"2024-04-01T06:30:46.000Z","size":75,"stargazers_count":88,"open_issues_count":2,"forks_count":15,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-18T08:18:47.675Z","etag":null,"topics":["command-line","github","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jlevy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-31T23:52:33.000Z","updated_at":"2025-03-06T12:23:39.000Z","dependencies_parsed_at":"2024-10-27T12:12:12.029Z","dependency_job_id":"8424f741-8bb8-42f9-8bdc-93bb315f1291","html_url":"https://github.com/jlevy/ghizmo","commit_stats":{"total_commits":31,"total_committers":1,"mean_commits":31.0,"dds":0.0,"last_synced_commit":"a4f38f8efec5246f181ee47333a76a81ca9cf5bb"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fghizmo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fghizmo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fghizmo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jlevy%2Fghizmo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jlevy","download_url":"https://codeload.github.com/jlevy/ghizmo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252902730,"owners_count":21822292,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line","github","python"],"created_at":"2024-10-13T16:41:25.562Z","updated_at":"2025-05-07T15:21:47.774Z","avatar_url":"https://github.com/jlevy.png","language":"Python","readme":"# Ghizmo\n\n![Octopus hose](images/xk8-octopus-hose-180.png)\n\nGhizmo is an extensible command line for GitHub.\n\n[GitHub's APIs](https://developer.github.com/v3/)\nare exceptionally powerful, but the friction to using them can be a bit high.\nYou have to [look up which library is best](https://developer.github.com/libraries/),\nthen write code to use that library,\nspending time on trial and error with setup, authentication, etc.\nOnce you get something working, the result is probably not a reusable script without additional effort.\n\nGhizmo lets you do complex things with the GitHub APIs from the command line,\nso you can automate reading, creating, or managing GitHub\nrepos, contributor statistics, pull requests, teams, etc.\nIts JSON output is modeled directly off the APIs,\nand can be piped into other tools.\nIt's also easy to add, save, and share more commands you perform frequently,\nby putting them into a simple `ghizmo_commands.py` file,\nand they become automatically available.\n\nEssentially, it's just a harness around the clean and complete [github3.py](https://github.com/sigmavirus24/github3.py) library.\nIt differs from the standard option [hub](https://github.com/github/hub) in that it's not focusing key features to augment the `git` command.\nRather, it's a way to use the full GitHub APIs more easily.\n(Also, since it's in Python, not Go, it can be extended without a compile step.)\n\n## Examples\n\nCommands are all defined [here](ghizmo/commands) and [below](#custom-commands).\n\nRun `ghizmo --help` for a list of commands -- and see below on how to add new commands.\n\n### Simple commands\n\nBasic access to API, showing responses in JSON:\n\n```bash\n$ ghizmo tags --repo torvalds/linux\n{\n  \"commit\": {\n    \"sha\": \"c13dcf9f2d6f5f06ef1bf79ec456df614c5e058b\",\n    \"url\": \"https://api.github.com/repos/torvalds/linux/commits/c13dcf9f2d6f5f06ef1bf79ec456df614c5e058b\"\n  },\n  \"name\": \"v4.2-rc8\",\n  \"tarball_url\": \"https://api.github.com/repos/torvalds/linux/tarball/v4.2-rc8\",\n  \"zipball_url\": \"https://api.github.com/repos/torvalds/linux/zipball/v4.2-rc8\"\n}\n...\n```\n\nThe advantage to JSON is it's easy to combine with other tools.\nHere's a histogram of number contributions for all Linux kernel contributors:\n\n```bash\n$ ghizmo tags --repo torvalds/linux | jq '.tarball_url' | head -1\n\"https://api.github.com/repos/torvalds/linux/tarball/v4.2-rc8\"\n...\n$ ghizmo contributors --repo torvalds/linux | jq '.contributions' | histogram.py -B400,800,1600,3200,6400 -p\n# NumSamples = 232; Min = 207.00; Max = 15475.00\n# Mean = 792.982759; Variance = 1594202.232461; SD = 1262.617215; Median 464.500000\n# each ∎ represents a count of 1\n  207.0000 -   400.0000 [   100]: ∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ (43.10%)\n  400.0000 -   800.0000 [    68]: ∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ (29.31%)\n  800.0000 -  1600.0000 [    47]: ∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ (20.26%)\n 1600.0000 -  3200.0000 [    10]: ∎∎∎∎∎∎∎∎∎∎ (4.31%)\n 3200.0000 - 15475.0000 [     7]: ∎∎∎∎∎∎∎ (3.02%)\n```\n\nYou may skip the `--repo` option and Ghizmo will infer the current repository if you are in a working directory with a GitHub origin:\n\n```bash\n$ ghizmo branches\n{\n  \"commit\": {\n    \"sha\": \"4c41820409e9394778b7b17d9b831f81d51a03bc\",\n    \"url\": \"https://api.github.com/repos/jlevy/ghizmo/commits/4c41820409e9394778b7b17d9b831f81d51a03bc\"\n  },\n  \"name\": \"master\"\n}\n$ ghizmo releases\n...\n```\n\n### Command arguments\n\nCommands can take arguments.\nThis command lists teams, and requires an organization name\n(should you forget an argument required by a command, you'll be rudely advised of your oversight):\n\n```bash\n$ ghizmo teams -a org_name=OctoTech\n{\n  \"description\": \"OctoTech\",\n  \"id\": 999,\n  \"members_url\": \"https://api.github.com/teams/999/members{/member}\",\n  \"name\": \"Owners\",\n  \"permission\": \"admin\",\n  \"repositories_url\": \"https://api.github.com/teams/999/repos\",\n  \"slug\": \"owners\",\n  \"url\": \"https://api.github.com/teams/999\"\n}\n```\n\nIt's also helpful for scripting releases:\n\n```bash\n$ ghizmo create-release -a name=0.9.99 -a tag_name=0.9.99 -a prerelease=true\n```\n\n### A more complex example\n\nIf you've ever had a messy GitHub repository to clean up, you might like this command,\nwhich looks for non-deleted branches on closed PRs.\n```bash\n$ ghizmo stale-pr-branches \u003e stale-pr-branches.json\n```\n\nYou edit/review that file, then test and perform deletions:\n\n```\n$ jq '.head_branch' stale-pr-branches.json | ghizmo delete-branches --dry-run\n{\n  \"message\": \"Deleted heads/aaa\",\n  \"dry_run\": true\n}\n...\n$ jq '.head_branch' stale-pr-branches.json | ghizmo delete-branches\n{\n  \"message\": \"Deleted heads/aaa\",\n  \"dry_run\": false\n}\n...\n```\n\n### Tracking contributors\n\nAnother command of interest may be `assemble-authors`.\nIt looks at GitHub history and creates an `AUTHORS.md` file, also including role information and additional configurable headers and footers. See [this example](https://github.com/jlevy/the-art-of-command-line/blob/master/AUTHORS.md).\n\n\n## Installation\n\nRequires Python 3.6+. Then (with sudo if desired):\n\n```\npip install ghizmo\n```\n\nGhizmo benefits if `git` is in your path so it can auto-detect your repository config.\nYou may also want to install tools like\n[`jq`](https://github.com/stedolan/jq) or [data_hacks](https://github.com/bitly/data_hacks)\nso you can perform operations such as the ones above that process JSON outputs.\n\n\n## Configuration\n\nYou can supply username and password from the command line, but you probably want to be able to use APIs without typing your\npassword. To do this, create a `~/.ghizmo.yml` file:\n\n```yaml\n# Ghizmo configuration\n# Default GitHub login name:\nusername: my-github-id\n# Personal access token for the above GitHub account:\naccess_token: aaaaaaaaaabbbbbbbbbbbccccccccc1234567890\n```\n\nCreate an access token on [your GitHub settings page](https://github.com/settings/tokens) to use with Ghizmo.\n\n## Custom commands\n\nTo add a new command, create a file `ghizmo_commands.py` in your current directory.\nFor example, here is one that counts pull requests by user:\n\n```python\nimport ghizmo.commands.lib as lib\nfrom collections import defaultdict\n\ndef count_prs(config, args):\n  \"\"\"\n  Show tallies of pull requests by author login name.\n  \"\"\"\n  counts = defaultdict(int)\n  for pr in config.repo.pull_requests(state=\"closed\"):\n    counts[pr.user.login] += 1\n    yield { \"status\": \"I'm at PR %s!\" % pr.number }\n\n  yield counts\n\ndef octotech_create_repo(config, args):\n  \"\"\"\n  If you like, your command can be custom, e.g. to your organization.\n  This creates a repo within your org owned by a specific team.\n  \"\"\"\n  org = config.github.organization(\"OctoTech\")\n  team_id = 1234567890  # OctoTech engineering team\n  repo = org.create_repository(args.name, description=args.description, private=True,\n    has_issues=False, has_wiki=False, team_id=team_id)\n```\n\nNow running\n```bash\nghizmo count-prs\n```\n(note the dash) will stream JSON messages as it tallies,\nthen write a tally of closed PRs for each user.\n\nTo use the second command, you need to specify custom arguments:\n\n```bash\nghizmo octotech-create-repo -a name=ninth-leg -a description=\"Yet another repository!\"\n```\n\n## Convenience\n\nThe idea here is both to provide simple commands, but also to allow more custom or complex use.\nYou can easily save/commit commands you write to `ghizmo_commands.py` file to Git,\nand your teammates can then use the same commands.\nThis means you can automate setup and configuration of GitHub repositories, teams, etc. in a flexible way.\nIf there're generally useful, please submit a PR and I'll gladly merge it for use by everyone.\n\n## Maturity\n\nMostly a one-day hack. Could be extended a lot, but seems to work.\n\n## Contributing\n\nYes, please!\nWe need more commands in the library.\nFile issues for bugs or general discussion.\n\n## License\n\nApache 2\n","funding_links":[],"categories":["Tips, tricks, tools, and add-ons for GitHub power users"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlevy%2Fghizmo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjlevy%2Fghizmo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjlevy%2Fghizmo/lists"}