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
16 changes: 0 additions & 16 deletions .github/workflows/black.yml

This file was deleted.

37 changes: 20 additions & 17 deletions .github/workflows/pytest.yml → .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
name: tests
name: CI
on:
pull_request:
branches:
- '*'
- main
push:
branches:
- main


jobs:
build:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3

- name: Ruff check
run: uv run ruff check --output-format=github

- name: Ruff format
run: uv run ruff format --check

test:
needs: lint
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]

python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[dev]
- name: Build coverage file
run: |
pytest --junitxml=pytest.xml --cov-report "xml:coverage.xml" --cov=shbin tests/
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- run: UV_PYTHON=${{ matrix.python-version }} uv run pytest --junitxml=pytest.xml --cov-report "xml:coverage.xml" --cov=shbin tests/

- name: Pytest coverage comment
uses: MishaKav/pytest-coverage-comment@main
Expand Down
16 changes: 7 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
name: Publish Python 🐍 distributions 📦 to PyPI

on:
push:
tags:
- "*"
release:
types: [created]

permissions:
contents: read

jobs:
pypi-publish:
name: upload release to PyPI
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: install build
run: python -m pip install --upgrade build
- name: build
run: python -m build
- uses: astral-sh/setup-uv@v5
- run: uv build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
67 changes: 33 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,22 +90,16 @@ have the target repository fully cloned locally.

# Install

The recommended way is to use [pipx](https://pypa.github.io/pipx/)
The recommended way is to use [uv](https://docs.astral.sh/uv/)

```console
pipx install shbin
```

Alternatively, install directly with `pip`.

```console
pip install --user shbin
uv tool install shbin
```

To install the latest development version from the repository:

```console
pip install --user https://github.com/Shiphero/shbin/archive/refs/heads/main.zip
uv tool install https://github.com/Shiphero/shbin/archive/refs/heads/main.zip
```

## OSX
Expand All @@ -128,43 +122,48 @@ port install file

# Setup

Create a [new fine-grained personal token](https://github.com/settings/personal-access-tokens/new)
To authenticate, simply run:
```
shbin init
```

This command will guide you through creating a token and and selecting a repository,
then store them locally so that `shbin` can use them right away.

Alternatively, you can **manually** create a [new fine-grained personal token](https://github.com/settings/personal-access-tokens/new)
on Github restricted to your "pastebin" repository (under your user or
your organization's ownership), with read and write permissions on
"Contents".
your organization's ownership), with **read and write** permission on **Contents**:

![image](https://user-images.githubusercontent.com/2355719/238758491-9d15e7e6-e4b7-43c8-a321-b65c968fc7e0.png)

- Then set the environment variables in your preferred place:
Then set the environment variables:

```
export SHBIN_GITHUB_TOKEN="<your personal token>"
export SHBIN_REPO="<user_or_org>/<repo>" # example "Shiphero/pastebin"
```

- By default `shbin` assigns a top-level folder to separate the content
uploaded by each user. This can be changed using the `SHBIN_NAMESPACE`
environment variable or the `--namespace` argument from the command
line. For example:
export SHBIN_REPO="<user_or_org>/<repo>" # example "myorg/pastebin"
```

- `export SHBIN_NAMESPACE=""` # no namespace
- `export SHBIN_NAMESPACE="pastebin_folder"` # the full pastebin is inside pastebin_folder/"
- `export SHBIN_NAMESPACE="pastebin_folder/{user}"` # mix of both: each user has its own subfolder
inside `pastebin_folder/`

- [optional] To interact with the clipboard, we use the library `pyclip`.
This may require some additional system dependencies
depending your operating system.
See [these notes](https://github.com/spyoungtech/pyclip#platform-specific-notesissues).
By default `shbin` assigns a top-level folder to separate the content
uploaded by each user. This can be changed using the `SHBIN_NAMESPACE`
environment variable or the `--namespace` argument from the command
line. For example:

If you want to disable the automatic copying of the URL to the clipboard
you can set the environment variable `SHBIN_COPY_URL=false` (or "0" or "no").
- `export SHBIN_NAMESPACE=""` # no namespace
- `export SHBIN_NAMESPACE="pastebin_folder"` # the full pastebin is inside pastebin_folder/"
- `export SHBIN_NAMESPACE="pastebin_folder/{user}"` # mix of both: each user has its own subfolder
inside `pastebin_folder/`

This is useful in some Linux distributions that use Wayland as the call via `wl-copy`
that `pyclip` uses in such environment can be slow.
> [!NOTE]
> To interact with the clipboard, we use the library `pyclip`. This may require some additional system
> dependencies depending your operating system. See [these notes](https://github.com/spyoungtech/pyclip#platform-specific-notesissues).
> If you want to disable the automatic copying of the URL to the clipboard
> you can set the environment variable `SHBIN_COPY_URL=false` (or "0" or "no").
>
> This is useful in some Linux distributions that use Wayland as the call via `wl-copy`
> that `pyclip` uses in such environment can be slow.

Nice video courtesy of [tuterm](https://github.com/veracioux/tuterm), [asciinema](https://asciinema.org/)
and [svg-term-cli](https://github.com/marionebl/svg-term-cli)
Nice video courtesy of [tuterm](https://github.com/veracioux/tuterm), [asciinema](https://asciinema.org/) and [svg-term-cli](https://github.com/marionebl/svg-term-cli)

PRs are welcome!

Expand Down
2 changes: 1 addition & 1 deletion demo/demo.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import this
import this # noqa
2 changes: 1 addition & 1 deletion demo/demo_2.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
print(f"Hello World")
print("Hello World")
19 changes: 7 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies = [
"python-magic >= 0.4.27",
"docopt-ng >= 0.8.1",
"rich >= 12.5",
"platformdirs>=4.3.6",
]
dynamic = ["version", "description"]

Expand All @@ -35,20 +36,14 @@ Changelog = "https://github.com/Shiphero/shbin/blob/main/CHANGELOG.md"
[project.scripts]
shbin = "shbin:main"

[project.optional-dependencies]
[tool.ruff]
line-length = 120

[dependency-groups]
dev = [
"pytest",
"black",
"pytest-cov",
"flake8",
"pytest-mock>=3.14.0",
"ruff",
]

[tool.black]
target-version = ["py38"]
line-length = 120
color = true

[tool.ruff]
target-version = "py38"
line-length = 120

34 changes: 24 additions & 10 deletions shbin.py → shbin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Turns a Github repo into a pastebin.
"""

import itertools
import os
import pathlib
Expand All @@ -13,11 +14,14 @@
from docopt import DocoptExit, docopt
from github import Github, GithubException
from rich import print
from .auth import do_auth, load_config


usage = """

Usage:
shbin dl <url_or_path>
shbin auth
shbin (<path>... | -x | -) [-f <file-name>] [-n] [-m <message>] [-d <target-dir>]
[--namespace=<namespace>] [--url-link-to-pages]
shbin (-h | --help)
Expand All @@ -35,7 +39,7 @@
-p, --url-link-to-pages Reformat the url to link to Github pages.
"""

__version__ = "0.3.0"
__version__ = "0.4.0"


class FakePath:
Expand All @@ -56,8 +60,17 @@ def __getattr__(self, attr):


def get_repo_and_user():
gh = Github(os.environ["SHBIN_GITHUB_TOKEN"])
return gh.get_repo(os.environ["SHBIN_REPO"]), gh.get_user().login
data = load_config()
token = os.getenv("SHBIN_GITHUB_TOKEN", data.get("token"))
repo = os.getenv("SHBIN_REPO", data.get("repo"))
if not token or not repo:
print(
"[red]x[/red] Missing SHBIN_GITHUB_TOKEN or SHBIN_REPO environment variables. "
"Run [bold]shbin auth[/bold] to authenticate."
)
raise SystemExit(1)
gh = Github(token)
return gh.get_repo(repo), gh.get_user().login


def expand_paths(path_or_patterns):
Expand Down Expand Up @@ -122,12 +135,13 @@ def download(url_or_path, repo, user):

def main(argv=None) -> None:
args = docopt(__doc__ + usage, argv, version=__version__)
try:
repo, user = get_repo_and_user()
except Exception as e:
raise DocoptExit(
f"Ensure SHBIN_GITHUB_TOKEN and SHBIN_REPO environment variables are correctly set. (error {e})"
)

if args["auth"]:
do_auth()
return

repo, user = get_repo_and_user()

# resolves namespace + target-dir (without ending slash)
# it also interpolates {user}
namespace = args.get("--namespace")
Expand All @@ -150,7 +164,7 @@ def main(argv=None) -> None:
content = sys.stdin.buffer.read()

if args["--file-name"]:
file_name = f'{args["--file-name"]}'
file_name = f"{args['--file-name']}"
else:
extension = get_extension(content)
# TODO try autodectect extension via pygment if .txt was guessed.
Expand Down
Loading