Skip to main content

License Build Quality Gate Minarca Client Coverage

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+
  • requests library

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 – Username
  • NEXUS_PASSWORD / NEXUS_PWD – Password
  • NEXUS_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

  1. Authenticate: Uses provided credentials (username/password or token)
  2. Discover Repository: Queries Nexus REST API to determine repository format (apt/yum/raw)
  3. Collect Files: Expands file/directory arguments, applying cp-like semantics
  4. Upload: Sends files to Nexus using the appropriate HTTP method:
    • apt: POST with multipart form data
    • yum/raw: PUT with raw file data
  5. Retry on Failure: Retries transient HTTP errors with exponential backoff
  6. Index Confirmation: Polls repository metadata until the uploaded file is visible:
    • apt: Queries Packages files for each distribution/architecture
    • yum: Decompresses primary.xml.gz and searches for the file
    • raw: Skips polling (immediate availability)

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-timeout if Nexus is slow to rebuild indexes
  • Use --wait-timeout 0 to skip polling (not recommended for CI)

"Upload attempt N/3 failed: Connection timeout"

  • Increase --timeout if network is slow
  • Increase --retries for flaky networks

Authentication fails

Ensure at least one of:

  • -u username:password provided
  • NEXUS_USERNAME and NEXUS_PASSWORD environment variables set
  • --token provided with NEXUS_TOKEN environment 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.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for nexus-pkg-push 1.2.0
File Interpreter ABI Platform
nexus_pkg_push-1.2.0-py3-none-any.whl Python 3 none any Details

Release files / nexus_pkg_push-1.2.0-py3-none-any.whl

Download URL nexus_pkg_push-1.2.0-py3-none-any.whl
Size 13.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ae13defb1dfc40513bca97b16ca9ba78aceee2ab528850f48aaa854d85909d2
BLAKE2b-256 checksum
How to use checksums
7a8ba623271fd1a0938b4924628320804b9dbf5e090948c15a830b312f956bc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.6

Release history Release notifications | RSS feed

This release

1.2.0 This release

1 release file

1.1.1

1 release file

1.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page