Skip to content

Commit

Permalink
v0.0.1: initial CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
ryan-williams committed May 21, 2024
0 parents commit e05c1d2
Show file tree
Hide file tree
Showing 7 changed files with 809 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Release to PyPI
on:
push:
tags: [ "**" ]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.11
- name: Install
run: pip install -e .
- name: Release
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
pip install setuptools twine wheel
python setup.py sdist bdist_wheel
twine upload dist/*
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# `rtd`: simple [Readthedocs] CLI

## Install
```bash
pip install rtd-cli
# Set this env var, or write the token to ~/.config/rtd-cli/token
RTD_TOKEN=your_token
```

## Usage
```bash
rtd --help
# Usage: rtd [OPTIONS] COMMAND [ARGS]...
#
# Simple CLI wrapper for the Readthedocs REST API.
#
# Options:
# --help Show this message and exit.
#
# Commands:
# api Make a request to the Readthedocs REST API.
# deactivate Deactivate one or more versions
# hide Hide one or more versions
```

## Examples

List projects:
```bash
rtd api projects
# {
# "count": …,
# "next": null,
# "previous": null,
# "results": [
#
# ]
# }
```

Hide all versions except for a specific list:

```bash
project=your_project
keep=(latest 1.11.) # grep patterns to keep
limit=100

keep_args=()
for v in "${keep[@]}"; do
keep_args+=(-e "$v")
done

rtd api "projects/$project/versions?limit=$limit&active=true&built=true"
| jq -r '.results[] | select(.hidden | not) | .slug' \
| grep "${keep_args[@]}" \
| xargs rtd hide -p $p
```

[Readthedocs]: https://readthedocs.org
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
click
requests
Empty file added rtd/__init__.py
Empty file.
82 changes: 82 additions & 0 deletions rtd/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import json
from functools import partial
from os import getenv
from os.path import join, expanduser, exists
from sys import stdout, stderr

import click
import requests


URL_BASE = 'https://readthedocs.org/api/v3'
RTD_TOKEN_VAR = 'RTD_TOKEN'

err = partial(print, file=stderr)


def get_token():
token = getenv(RTD_TOKEN_VAR)
if token:
return token
config_dir = getenv('XDG_CONFIG_HOME', join(expanduser('~'), '.config'))
rtd_config_dir = join(config_dir, 'rtd-cli')
token_path = join(rtd_config_dir, 'token')
if exists(token_path):
with open(token_path, "r") as f:
return f.read().strip()

raise RuntimeError(f"Readthedocs API token not found in ${RTD_TOKEN_VAR} or {token_path}")


@click.group("rtd")
def cli():
"""Simple CLI wrapper for the Readthedocs REST API."""
pass


@cli.command("api")
@click.option('-b', '--body', help='JSON string to send in the body of a PATCH request; if absent, a GET request is sent')
@click.option('-u', '--show-updated', is_flag=True, help="After a PATCH request (with -b/--body), send a GET to the same endpoint, to verify the updated state of the resource")
@click.argument("endpoint")
def api(body, show_updated, endpoint):
"""Make a request to the Readthedocs REST API.
RTD API docs: https://docs.readthedocs.io/en/stable/api/v3.html
"""
token = get_token()
headers = { 'Authorization': f'token {token}' }
url = join(URL_BASE, endpoint)
if body:
body_obj = json.loads(body)
response = requests.patch(url, body_obj, headers=headers)
response.raise_for_status()
if response.status_code != 204:
text = response.text
err(text)

if body and show_updated or not body:
response = requests.get(url, headers=headers)
response.raise_for_status()
body = response.json()
json.dump(body, stdout, indent=2)


def patch_cmd(name, obj, docstr):
def cmd(project, no_show_updated, versions):
for version in versions:
body = json.dumps(obj)
api.callback(body=body, show_updated=not no_show_updated, endpoint=f"projects/{project}/versions/{version}/")

cmd.__doc__ = docstr

for deco in [
cli.command(name),
click.option('-p', '--project'),
click.option('-U', '--no-show-updated', is_flag=True),
click.argument("versions", nargs=-1),
]:
cmd = deco(cmd)


patch_cmd("deactivate", {"active": False}, "Deactivate one or more versions")
patch_cmd("hide", {"hidden": True}, "Hide one or more versions")
12 changes: 12 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from setuptools import setup

setup(
name="rtd-cli",
version="0.0.1",
install_requires=open("requirements.txt").read(),
entry_points={
"console_scripts": [
"rtd = rtd.main:cli",
],
},
)
Loading

0 comments on commit e05c1d2

Please sign in to comment.