# jf twine Run twine commands to publish Python packages to Artifactory with optional build-info collection. ## When to Use Use `jf twine` to **publish** Python packages (wheels, sdists) to Artifactory. This is the upload counterpart to `jf pip` (which installs packages). **Typical Python publish workflow:** ```bash # 1. Build the package python -m build # 2. Upload to Artifactory with build-info jf twine upload dist/* --build-name=my-python-lib --build-number=$BUILD_NUMBER # 3. Publish build info jf rt build-publish my-python-lib $BUILD_NUMBER ``` ## Prerequisites * Twine must be installed separately (`pip install twine`). * Run `jf pip-config` or `jf pipenv-config` before using `jf twine` — twine uses the deployer repository from that configuration. * Configure a server with `jf config add` or `jf c add`. * Authentication to Artifactory is required. * Build your package (e.g., `python -m build`) before running `jf twine upload`. *** ## Build: `jf twine` Run twine commands to publish Python packages to Artifactory with optional build-info collection. **To publish Python packages with Twine:** ### Synopsis ``` jf twine [options] ``` **Aliases:** none ### Arguments | Argument | Required | Description | | ------------------- | -------- | ---------------------------------------------------------------------------- | | `` | Yes | Arguments and options for the twine command (for example, `upload`, `check`) | ### Build Options | Flag | Default | Description | | ---------------- | ------- | ---------------------------------------------------------------------------------- | | `--build-name` | — | Build name for build-info. Requires `--build-number`. | | `--build-number` | — | Build number for build-info. Requires `--build-name`. | | `--module` | — | Optional module name for build-info. Requires `--build-name` and `--build-number`. | | `--project` | — | JFrog Artifactory project key | ### Build Examples #### Help ```bash jf twine --help ``` #### Basic Usage ```bash jf twine upload dist/* --build-name= --build-number= ``` Where: * \: A name for the build (for example, `my-python-lib`) * \: A number or identifier for the build run (for example, `1`) For example: ```bash jf twine upload dist/* --build-name=my-python-lib --build-number=1 ``` #### Upload with Build-Info ```bash jf twine upload dist/*.whl dist/*.tar.gz --build-name=my-package --build-number=1 ``` #### Check Package ```bash jf twine check dist/* ``` *** ## Important Notes * **pip-config or pipenv-config covers twine**: The `jf twine` command reads its deployment repository from either a `jf pip-config` or `jf pipenv-config` configuration — whichever exists in your project. If both are present, the CLI checks for `pip` config first, then `pipenv`. You do not need a separate `jf twine-config` command. If neither config is found, you will see: `no config file was found! Before running the 'jf twine' command on a project for the first time, the project should be configured with the 'jf pip-config OR pipenv-config' command`. * Twine must be installed separately (`pip install twine`). * The `check` subcommand validates package metadata before upload — use it to catch issues early. ## CI/CD Example (GitHub Actions) ```yaml # .github/workflows/build.yml steps: - uses: actions/checkout@v4 - name: Setup JFrog CLI uses: jfrog/setup-jfrog-cli@v4 env: JF_URL: ${{ vars.JF_URL }} JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install build tools run: pip install build twine - name: Configure pip run: jf pip-config --server-id-resolve=setup-jfrog-cli-server --repo-resolve=pypi-virtual --server-id-deploy=setup-jfrog-cli-server --repo-deploy=pypi-local - name: Build package run: python -m build - name: Upload to Artifactory run: jf twine upload dist/* --build-name=my-python-lib --build-number=${{ github.run_number }} - name: Publish build info run: jf rt build-publish my-python-lib ${{ github.run_number }} ``` ## Troubleshooting | Symptom | Cause | Fix | | -------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------- | | `no config file was found` | Neither `jf pip-config` nor `jf pipenv-config` was run | Run `jf pip-config` (or `jf pipenv-config`) with `--repo-deploy` set | | 401 / 403 on upload | Invalid credentials or missing deploy permissions | Re-run `jf config add`; verify the user has deploy permissions on the target local repo | | "file not found" on `jf twine upload dist/*` | Package was not built first | Run `python -m build` before `jf twine upload` | | Upload succeeds but package not visible | Uploaded to wrong repository | Confirm `--repo-deploy` in your pip/pipenv config points to a PyPI **local** repository | | `twine` not found | Twine is not installed | Run `pip install twine` | **Enable debug logging:** `export JFROG_CLI_LOG_LEVEL=DEBUG`
## Related Topics * [Build Tools Overview](/artifactory/docs/build-tool-commands) — Capabilities matrix and tool reference * [Native Mode](/artifactory/docs/native-mode) — Supported packages with Native Mode