nexus-pkg-push – README
Overview
nexus-pkg-push is a command-line tool to publish Debian (.deb), RPM (.rpm), or raw packages to a Sonatype Nexus repository over its REST API. It automatically waits for the repository index to be rebuilt before confirming success, eliminating race conditions in CI/CD pipelines.
Supports:
- Debian (apt) repositories with distribution and component parameters
- RPM (yum) repositories with sub-path support
- Raw repositories with recursive directory uploads
- Automatic retry on transient failures
- Index confirmation polling
- Bearer token or username/password authentication
Installation
pip install nexus-pkg-push
Or install from source:
git clone <repo>
cd nexus-pkg-push
pip install .
Requirements
- Python 3.7+
requestslibrary
Quick Start
Upload a single .deb file
nexus-pkg-push \
-u admin:password \
--distribution bullseye,bookworm \
myapp_1.0_amd64.deb \
https://nexus.example.com/repository/apt-release/
Upload multiple .rpm files
nexus-pkg-push \
-u admin:password \
dist/*.rpm \
https://nexus.example.com/repository/yum-release/
Upload a directory recursively (raw)
nexus-pkg-push \
-u admin:password \
-R \
./dist/docs/ \
https://nexus.example.com/repository/archive/myapp/1.0/docs/
Rename a file on upload
nexus-pkg-push \
-u admin:password \
myapp.tar.gz \
https://nexus.example.com/repository/raw-release/myapp-latest.tar.gz
Usage
nexus-pkg-push [OPTIONS] FILE [FILE ...] REPOURL
Positional Arguments
| Argument | Description |
|---|---|
FILE |
One or more files or directories to upload |
REPOURL |
Full URL to the target Nexus repository (e.g., https://nexus.example.com/repository/apt-release/) |
Authentication
| Option | Description |
|---|---|
-u, --user USER[:PASS] |
Username, or user:password pair (like curl -U). Can omit password to prompt. |
--password PASSWORD |
Nexus password (alternative to embedding in -u) |
--token TOKEN |
Bearer token (alternative to username/password) |
Environment Variables:
NEXUS_USERNAME/NEXUS_USR– UsernameNEXUS_PASSWORD/NEXUS_PWD– PasswordNEXUS_TOKEN– Bearer token
Upload Options
| Option | Description |
|---|---|
-R, --recursive |
Upload directory contents recursively (required for directories) |
--distribution DIST[,DIST...] |
(deb only) Comma-separated list of target distributions (e.g., bullseye,bookworm,jammy). If omitted, auto-discovers available distributions. |
--component COMPONENT |
(deb only) APT component/section (default: main) |
Retry & Timeout Options
| Option | Description |
|---|---|
--retries N |
Number of upload retry attempts on transient failure (default: 3) |
--timeout SECONDS |
HTTP request timeout in seconds (default: 10) |
--wait-timeout SECONDS |
Max time to wait for index confirmation (default: 60). Use 0 to skip waiting. |
--wait-interval SECONDS |
Polling interval while waiting for index (default: 1) |
Other Options
| Option | Description |
|---|---|
--continue-on-error |
Attempt all uploads and report summary instead of stopping at first failure |
-d, --debug |
Increase verbosity (prints debug messages to stderr) |
--version |
Show version information and exit |
-h, --help |
Show help message and exit |
Examples
Example 1: Upload .deb with auto-discovery of distributions
nexus-pkg-push \
-u admin:password \
myapp_1.0_amd64.deb \
https://nexus.ikus-soft.com/repository/apt-dev/
The tool queries the repository and uploads to all available distributions.
Example 2: Upload multiple .rpm files with retries
nexus-pkg-push \
-u admin:password \
--retries 5 \
dist/myapp-1.0.x86_64.rpm \
dist/myapp-debuginfo-1.0.x86_64.rpm \
https://nexus.example.com/repository/yum-release/
Example 3: Upload documentation recursively
nexus-pkg-push \
-u admin:password \
-R \
./html/ \
https://nexus.example.com/repository/archive/rdiffweb/1.2.3/doc/
Preserves directory structure: html/index.html → archive/rdiffweb/1.2.3/doc/index.html
Example 4: Upload with token authentication and skip index wait
nexus-pkg-push \
--token my-bearer-token \
--wait-timeout 0 \
app.tar.gz \
https://nexus.example.com/repository/raw-release/builds/
Example 5: Continue on error
nexus-pkg-push \
-u admin:password \
--continue-on-error \
dist/pkg1.deb \
dist/pkg2.deb \
dist/pkg3.deb \
https://nexus.example.com/repository/apt-dev/
Even if pkg1 fails, will attempt pkg2 and pkg3, then report summary.
Exit Codes
| Code | Meaning |
|---|---|
0 |
All files uploaded and indexed successfully |
1 |
Upload failed (after retries) |
2 |
Invalid arguments or usage error |
3 |
Upload succeeded, but index confirmation timed out |
How It Works
- Authenticate: Uses provided credentials (username/password or token)
- Discover Repository: Queries Nexus REST API to determine repository format (apt/yum/raw)
- Collect Files: Expands file/directory arguments, applying
cp-like semantics - Upload: Sends files to Nexus using the appropriate HTTP method:
- apt:
POSTwith multipart form data - yum/raw:
PUTwith raw file data
- apt:
- Retry on Failure: Retries transient HTTP errors with exponential backoff
- Index Confirmation: Polls repository metadata until the uploaded file is visible:
- apt: Queries
Packagesfiles for each distribution/architecture - yum: Decompresses
primary.xml.gzand searches for the file - raw: Skips polling (immediate availability)
- apt: Queries
Special Behaviors
cp-like Semantics for Renaming
When uploading a single file to a REPOURL that includes a filename (no trailing /), the file is renamed:
# Uploads as 'myapp-latest.tar.gz'
nexus-pkg-push -u admin:pass app.tar.gz \
https://nexus.example.com/repository/raw/myapp-latest.tar.gz
With multiple files, this raises an error (cp behavior):
# ERROR: cannot rename multiple files
nexus-pkg-push -u admin:pass file1.deb file2.deb \
https://nexus.example.com/repository/apt/renamed.deb
Recursive Directory Upload
For raw repositories, use -R/--recursive to upload a directory tree:
nexus-pkg-push -u admin:pass -R ./docs/ \
https://nexus.example.com/repository/archive/v1.0/
Preserves structure: docs/api/index.html → archive/v1.0/api/index.html
Distribution Auto-Discovery (Debian)
If --distribution is omitted, the tool queries Nexus to find all available distributions and uploads to each:
nexus-pkg-push -u admin:pass myapp.deb \
https://nexus.example.com/repository/apt-dev/
# Discovers: bullseye, bookworm, trixie, jammy, noble, ...
Troubleshooting
"Repository not found via Nexus API"
- Verify the repository name in the URL
- Check Nexus credentials and permissions
- Confirm Nexus base URL is correct
"Index confirmation timed out"
- Increase
--wait-timeoutif Nexus is slow to rebuild indexes - Use
--wait-timeout 0to skip polling (not recommended for CI)
"Upload attempt N/3 failed: Connection timeout"
- Increase
--timeoutif network is slow - Increase
--retriesfor flaky networks
Authentication fails
Ensure at least one of:
-u username:passwordprovidedNEXUS_USERNAMEandNEXUS_PASSWORDenvironment variables set--tokenprovided withNEXUS_TOKENenvironment variable
Development
Run tests:
pip install -e '.[dev]'
python -m pytest test_nexus_pkg_push.py -v
Debug mode:
nexus-pkg-push -d -u admin:pass file.deb https://nexus.example.com/repository/apt-dev/
License
MIT © 2026 Patrik Dufresne
Contributing
Issues and pull requests welcome at the project repository.
Metadata
Release files for nexus-pkg-push 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nexus_pkg_push-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Release files / nexus_pkg_push-1.1.1-py3-none-any.whl
| Download URL | nexus_pkg_push-1.1.1-py3-none-any.whl |
|---|---|
| Size | 13.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1ec1b8b4b6e0c6a352a918380fba634dd514172e590cc79338cf27912b89b96f
|
|
BLAKE2b-256 checksum How to use checksums |
b2c6aa09ce5318833573104161e8fdf1a59139f4760e8e3dc3f87d5a7233f171
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.6
|