Skip to content

Edit for release

Edit for release #74

Workflow file for this run

name: Publish to PyPI
on:
push:
branches: [main]
paths:
- 'cli/**'
- 'pyproject.toml'
- '.github/workflows/publish.yml'
permissions:
contents: write
jobs:
test:
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.10', '3.12', '3.13']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install pipx
run: pip install pipx
- name: Install package with pipx
run: pipx install .
- name: Install package editable for pytest (pipx env is isolated)
run: pip install -e ".[dev]"
- name: Check drp entrypoint is on PATH
run: drp --version
- name: Check fallback python -m cli also works
run: python -m cli --version
- name: Run unit tests
run: python -m pytest tests/unit/ -v
# ── Smoke tests (require DRP_SMOKE_HOST secret) ───────────────────────
- name: Smoke — text drop upload, get, delete
if: ${{ env.DRP_SMOKE_HOST != '' }}
env:
DRP_SMOKE_HOST: ${{ secrets.DRP_SMOKE_HOST }}
shell: bash
run: |
KEY="ci-smoke-$(python -c 'import uuid; print(uuid.uuid4().hex[:8])')"
python -c "
from cli import config
cfg = config.load()
cfg['host'] = '${{ secrets.DRP_SMOKE_HOST }}'
config.save(cfg)
"
URL=$(drp up "hello from ci ${{ matrix.os }} py${{ matrix.python-version }}" --key "$KEY")
echo "Uploaded: $URL"
[ -z "$URL" ] && { echo "Upload returned empty URL"; exit 1; }
RESULT=$(drp get "$KEY")
echo "Got: $RESULT"
echo "$RESULT" | grep -q "hello from ci" || { echo "Content mismatch"; exit 1; }
drp ls | grep -q "$KEY" || { echo "Key not found in drp ls"; exit 1; }
drp rm "$KEY"
drp get "$KEY" && { echo "Drop still accessible after delete"; exit 1; } || true
- name: Smoke — stdin pipe upload
if: ${{ env.DRP_SMOKE_HOST != '' }}
env:
DRP_SMOKE_HOST: ${{ secrets.DRP_SMOKE_HOST }}
shell: bash
run: |
KEY="ci-stdin-$(python -c 'import uuid; print(uuid.uuid4().hex[:8])')"
URL=$(echo "stdin test from ci" | drp up --key "$KEY")
echo "Uploaded via stdin: $URL"
[ -z "$URL" ] && { echo "Stdin upload returned empty URL"; exit 1; }
drp get "$KEY" | grep -q "stdin test" || { echo "Stdin content mismatch"; exit 1; }
drp rm "$KEY"
- name: Smoke — file drop upload, get
if: ${{ env.DRP_SMOKE_HOST != '' }}
env:
DRP_SMOKE_HOST: ${{ secrets.DRP_SMOKE_HOST }}
shell: bash
run: |
KEY="ci-file-$(python -c 'import uuid; print(uuid.uuid4().hex[:8])')"
CONTENT="file content from ${{ matrix.os }}"
python -c "
with open('ci_test_file.txt', 'w') as f:
f.write('$CONTENT')
"
URL=$(drp up ci_test_file.txt --key "$KEY")
echo "Uploaded file: $URL"
[ -z "$URL" ] && { echo "File upload returned empty URL"; exit 1; }
echo "$URL" | grep -q '/f/' || { echo "File URL missing /f/ prefix"; exit 1; }
drp get -f "$KEY" -o ci_downloaded.txt
python -c "
content = open('ci_downloaded.txt').read()
assert '$CONTENT' in content, f'Content mismatch: {content!r}'
print('File content verified')
"
drp rm -f "$KEY"
rm -f ci_test_file.txt ci_downloaded.txt
- name: Smoke — authenticated session persists
if: ${{ env.DRP_SMOKE_HOST != '' && env.DRP_SMOKE_EMAIL != '' }}
env:
DRP_SMOKE_HOST: ${{ secrets.DRP_SMOKE_HOST }}
DRP_SMOKE_EMAIL: ${{ secrets.DRP_SMOKE_EMAIL }}
DRP_SMOKE_PASSWORD: ${{ secrets.DRP_SMOKE_PASSWORD }}
shell: bash
run: |
python -c "
import requests
from cli import api, config
from cli.session import save_session
cfg = config.load()
host = cfg['host']
session = requests.Session()
ok = api.login(host, session, '${{ secrets.DRP_SMOKE_EMAIL }}', '${{ secrets.DRP_SMOKE_PASSWORD }}')
assert ok, 'Login failed'
cfg['email'] = '${{ secrets.DRP_SMOKE_EMAIL }}'
config.save(cfg)
save_session(session)
print('Logged in, session saved')
"
timeout 15 drp ls || { echo "drp ls timed out or failed"; exit 1; }
drp logout
timeout 5 drp ls || true
# ── Publish (only if all tests pass) ──────────────────────────────────────
publish:
needs: test
runs-on: ubuntu-latest
# Prevent concurrent publish runs if two pushes land close together
concurrency:
group: publish
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Bump patch version
id: bump
run: |
current=$(grep -oP "(?<=__version__ = ').*(?=')" cli/__init__.py)
IFS='.' read -r major minor patch <<< "$current"
new_version="$major.$minor.$((patch + 1))"
while git tag | grep -q "^v$new_version$"; do
patch=$((patch + 1))
new_version="$major.$minor.$patch"
done
sed -i "s/__version__ = '$current'/__version__ = '$new_version'/" cli/__init__.py
echo "version=$new_version" >> "$GITHUB_OUTPUT"
- name: Commit and push version bump
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add cli/__init__.py
git diff --cached --quiet && exit 0
git commit -m "v${{ steps.bump.outputs.version }}"
git tag -f "v${{ steps.bump.outputs.version }}"
# Pull and rebase in case a commit landed while CI was running
git pull --rebase origin main
git push --follow-tags --force-with-lease
- name: Collect commits since last release
run: |
prev_tag=$(git tag --sort=-v:refname | sed -n '2p')
if [ -z "$prev_tag" ]; then
log=$(git log --oneline --no-decorate HEAD)
else
log=$(git log --oneline --no-decorate "$prev_tag"..HEAD~1)
fi
{
echo "$log"
echo ""
echo "Install / upgrade:"
echo '```'
echo 'pipx install drp-cli'
echo '# or upgrade:'
echo 'pipx upgrade drp-cli'
echo '```'
} > /tmp/release_notes.txt
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.bump.outputs.version }}
name: v${{ steps.bump.outputs.version }}
body_path: /tmp/release_notes.txt
- name: Build and publish to PyPI
run: pip install build && python -m build
- uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}