timed-pypi-uploader 0.1.0
Schedule automated builds and uploads of Python packages to PyPI
Requires Python: >=3.8
Keywords: automation, packaging, pypi, release, scheduler, upload

# timed-pypi-uploader

A lightweight Python tool for scheduling automated builds and uploads of Python packages to PyPI at specified times or on recurring intervals.

## Features

- **One-time or recurring scheduling** using cron expressions or specific dates/times
- **Automatic build backend detection** (Hatch, Poetry, setuptools, flit)
- **Secure token storage** via system keyring
- **Dry-run mode** for testing without actual uploads
- **Git change detection** to skip releases when no changes exist
- **TestPyPI support** for pre-production testing

## Installation

```bash
pip install timed-pypi-uploader
```

## Quick Start

### 1. Configure your PyPI token

```bash
# Store PyPI token securely
timed-pypi-uploader config --pypi-token pypi-XXXXXXXXXXXX

# Or for TestPyPI
timed-pypi-uploader config --test-pypi-token pypi-XXXXXXXXXXXX
```

### 2. Run an immediate release

```bash
# Build and upload to PyPI
timed-pypi-uploader run --project-dir .

# Dry run first
timed-pypi-uploader run --dry-run

# Upload to TestPyPI
timed-pypi-uploader run --test-pypi
```

### 3. Schedule a release

```bash
# One-time release at specific time
timed-pypi-uploader schedule --at "2026-02-01T09:00:00" --project-dir .

# Recurring release (daily at 3am)
timed-pypi-uploader schedule --cron "0 3 * * *"

# Only release if git changes exist
timed-pypi-uploader schedule --cron "0 3 * * *" --check-git-changes
```

## Commands

| Command | Description |
|---------|-------------|
| `config` | Configure tokens and settings |
| `schedule` | Schedule a future release |
| `run` | Run a release immediately |
| `build` | Build distributions only |
| `upload` | Upload existing distributions |
| `check` | Verify all dependencies are installed |

## Configuration

Create a `.timed-uploader.toml` file in your project:

```toml
[general]
project_dir = "."
build_backend = "auto"  # auto, hatch, poetry, build, flit
test_mode = false
clean_before_build = true

[schedule]
type = "cron"  # or "one-time"
cron = "0 3 * * *"  # Daily at 3am
# at = "2026-02-01T09:00:00"  # For one-time
check_git_changes = true

[tokens]
# Tokens stored via keyring, not in this file
pypi_keyring_service = "timed-pypi-uploader-pypi"
```

Or initialize with:

```bash
timed-pypi-uploader config --init
```

## Examples

### Build only (no upload)

```bash
timed-pypi-uploader build --project-dir /path/to/project
```

### Upload existing dist files

```bash
timed-pypi-uploader upload --project-dir /path/to/project
```

### Schedule with verbose logging

```bash
timed-pypi-uploader schedule --at "2026-02-01T09:00:00" --verbose
```

### Run in background

```bash
nohup timed-pypi-uploader schedule --cron "0 3 * * *" &
```

## Security

- Tokens are **never stored in plaintext files**
- Uses system keyring (macOS Keychain, Windows Credential Manager, Linux Secret Service)
- Always test with `--dry-run` and TestPyPI first

## Dependencies

- `typer` - CLI framework
- `apscheduler` - Job scheduling
- `keyring` - Secure credential storage
- `build` - PEP 517 package building
- `twine` - PyPI uploading

## License

MIT

## Support

[![Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/brody4321)

[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-support-yellow?logo=buymeacoffee)](https://buymeacoffee.com/brody4321)