Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,9 @@ jobs:
Configure pip build environment with build number, authentication, and default settings.

This action configures pip to pull packages from the internal JFrog Artifactory registry instead of the default PyPI.
It writes `~/.pip/pip.conf` and exports environment variables so pip, uv, pipx, and mise also resolve Python packages from Repox.

> **Note:** Run `config-pip` **before** `setup-python`, `mise`, `pipx`, or `uv` in the same job. Those tools read `PIP_INDEX_URL`, `UV_DEFAULT_INDEX`, and `MISE_PIPX_REGISTRY_URL` at install time; `pip.conf` alone is not enough for them.
> **Note:** This action automatically calls [`get-build-number`](#get-build-number) to manage the build number.
> **Note:** This action replaces the deprecated `configure-pipx-repox` action from `sonarqube-cloud-github-actions` repository.

Expand Down Expand Up @@ -1286,6 +1288,10 @@ steps:
| `ARTIFACTORY_ACCESS_TOKEN` | Access token for Artifactory authentication |
| `ARTIFACTORY_USERNAME` | Username for Artifactory authentication |
| `ARTIFACTORY_URL` | Artifactory (Repox) URL. E.x.: `https://repox.jfrog.io/artifactory` |
| `PIP_INDEX_URL` | Authenticated Repox simple index for pip and setup-python bootstrap |
| `UV_DEFAULT_INDEX` | Authenticated Repox simple index for uv |
| `MISE_PIPX_REGISTRY_URL` | Authenticated Repox index template for mise pipx backends |
| `PIP_CONFIG_FILE` | Path to the generated `pip.conf` |

See also [`get-build-number`](#get-build-number) output environment variables.

Expand Down
31 changes: 23 additions & 8 deletions config-pip/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,41 @@
# - ARTIFACTORY_ACCESS_TOKEN: Access token to read Repox repositories
#
# GitHub Actions auto-provided:
# - GITHUB_REPOSITORY: Repository name in format "owner/repo"
# - GITHUB_ENV: Path to GitHub Actions environment file

set -euo pipefail

: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_USERNAME:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}"
: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_USERNAME:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" "${GITHUB_ENV:?}"

configure_pip() {
echo "Configuring pip to use Artifactory..."

# Extract the host from ARTIFACTORY_URL
local repox_host="${ARTIFACTORY_URL#https://}"
local repox_host pip_conf_file authenticated_index registry_url

repox_host="${ARTIFACTORY_URL#https://}"
repox_host="${repox_host#http://}"
echo "Repox host: $repox_host"

mkdir -p "$HOME/.pip"
cat > "${HOME}/.pip/pip.conf" <<EOF
pip_conf_file="${HOME}/.pip/pip.conf"
authenticated_index="https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${repox_host}/api/pypi/sonarsource-pypi/simple"
registry_url="${authenticated_index}/{}/"
Comment on lines +26 to +27

@gitar-bot gitar-bot Bot Aug 27, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: MISE_PIPX_REGISTRY_URL simple-index breaks wheel-only pipx tools

MISE_PIPX_REGISTRY_URL is set to …/api/pypi/sonarsource-pypi/simple/{}/. In every released mise version (checked v2026.5.9, v2026.6.14, v2026.8.1 — the versions this repo pins in config-uv/action.yml:103 and .github/workflows/test-shell-scripts.yml:25), a registry_url that does not contain /json is fetched as HTML and versions are extracted with the regex href=["'][^"']*/([^/]+)\.tar\.gz… (src/backend/pipx.rs:144-160 and :209-220). Only sdist links are recognised, so for any wheel-only package (no .tar.gz on the index) mise gets an empty version list and mise install pipx:<pkg> / @latest resolution fails, where previously the pypi.org JSON API returned all versions. Wheel support for the simple index exists only on mise main (versions_from_simple_index handling .whl), not in a release. Either wait for/require a mise version with wheel support, or document the limitation and the requirement to pin sdist-publishing packages in the README note added at README.md:1218.

Document the wheel-only limitation next to the new ordering note so consumers are not surprised by "no versions found" failures.:

# README.md (config-pip section)
> **Note:** `MISE_PIPX_REGISTRY_URL` points at the Repox PEP 503 simple index. Released mise
> versions only discover versions from sdist (`.tar.gz`) links on a simple index, so
> `pipx:` tools that publish wheels only cannot be resolved via `@latest`; pin such tools to
> an exact version or install them with `uv tool` / `pipx` directly (they use `PIP_INDEX_URL`).

Was this helpful? React with 👍 / 👎


mkdir -p "${HOME}/.pip"
cat > "$pip_conf_file" <<EOF
[global]
index-url = https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@$repox_host/api/pypi/sonarsource-pypi/simple
index-url = ${authenticated_index}
EOF
echo "Configuration file: ${HOME}/.pip/pip.conf"
echo "Configuration file: ${pip_conf_file}"

echo "::add-mask::${authenticated_index}"
echo "::add-mask::${registry_url}"
{
echo "PIP_INDEX_URL=${authenticated_index}"
echo "UV_DEFAULT_INDEX=${authenticated_index}"
echo "MISE_PIPX_REGISTRY_URL=${registry_url}"
echo "PIP_CONFIG_FILE=${pip_conf_file}"
} >> "$GITHUB_ENV"
Comment on lines +38 to +43

@gitar-bot gitar-bot Bot Aug 27, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: Repo's own mise workflows still resolve pipx tools from pypi.org

The PR's test plan is to observe "Repox traffic and no pypi.org / files.pythonhosted.org" on this repo's mise workflows, but the only workflow that runs ./config-pip is pre-commit.yml:13; test-shell-scripts.yml (and test-build-number.yml, test-update-release-channel.yml) invoke jdx/mise-action — which installs pipx and pipx:check-jsonschema — without ever running config-pip, so no PIP_INDEX_URL / MISE_PIPX_REGISTRY_URL is present and those installs still hit pypi.org. Add a ./config-pip step before the jdx/mise-action step in those workflows (or state in the PR that consumer wiring is out of scope) so the stated verification is actually possible.

Run config-pip before mise-action in test-shell-scripts.yml (and the other mise-based test workflows) so pipx/mise resolve from Repox.:

- uses: ./config-npm
- uses: ./config-pip
- uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
  with:
    version: 2026.6.14

Was this helpful? React with 👍 / 👎


return 0
}

Expand Down
35 changes: 29 additions & 6 deletions spec/config-pip_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
eval "$(shellspec - -c) exit 1"

# Set up environment variables
export GITHUB_REPOSITORY="my-org/test-project"
export GITHUB_ENV=/dev/null
export GITHUB_OUTPUT=/dev/null
export ARTIFACTORY_URL="https://repox.jfrog.io/artifactory"
export ARTIFACTORY_USERNAME="test-user"
export ARTIFACTORY_ACCESS_TOKEN="test-token"

AUTHENTICATED_INDEX="https://test-user:test-token@repox.jfrog.io/artifactory/api/pypi/sonarsource-pypi/simple"
MISE_REGISTRY_URL="${AUTHENTICATED_INDEX}/{}/"

# Expected output messages
MESSAGE_CONFIGURING_PIP="Configuring pip to use Artifactory..."
MESSAGE_REPOX_HOST="Repox host: repox.jfrog.io/artifactory"
MESSAGE_MASK_INDEX="::add-mask::${AUTHENTICATED_INDEX}"
MESSAGE_MASK_REGISTRY="::add-mask::${MISE_REGISTRY_URL}"

Describe 'config-pip/config.sh'
It 'does not run main when sourced'
Expand Down Expand Up @@ -44,28 +48,45 @@ Describe 'configure_pip()'
It 'creates pip config directory, file and correct content'
When call configure_pip
The status should be success
The lines of output should equal 3
The lines of output should equal 5
The lines of error should equal 0
The line 1 should equal "$MESSAGE_CONFIGURING_PIP"
The line 2 should equal "$MESSAGE_REPOX_HOST"
The line 3 should start with "Configuration file: "
The line 3 should end with "/.pip/pip.conf"
The line 4 should equal "$MESSAGE_MASK_INDEX"
The line 5 should equal "$MESSAGE_MASK_REGISTRY"
The path "${HOME}/.pip" should be directory
The path "${HOME}/.pip/pip.conf" should be file
The contents of file "${HOME}/.pip/pip.conf" should equal "[global]
index-url = https://test-user:test-token@repox.jfrog.io/artifactory/api/pypi/sonarsource-pypi/simple"
index-url = ${AUTHENTICATED_INDEX}"
End

It 'exports index environment variables for pip, uv, mise, and pipx'
GITHUB_ENV=$(mktemp)
export GITHUB_ENV
When call configure_pip
The status should be success
The lines of output should equal 5
The contents of file "$GITHUB_ENV" should include "PIP_INDEX_URL=${AUTHENTICATED_INDEX}"
The contents of file "$GITHUB_ENV" should include "UV_DEFAULT_INDEX=${AUTHENTICATED_INDEX}"
The contents of file "$GITHUB_ENV" should include "MISE_PIPX_REGISTRY_URL=${MISE_REGISTRY_URL}"
The contents of file "$GITHUB_ENV" should include "PIP_CONFIG_FILE=${HOME}/.pip/pip.conf"
rm -f "$GITHUB_ENV"
End

It 'handles URL with custom port'
export ARTIFACTORY_URL="https://repox.jfrog.io:8080/artifactory"
When call configure_pip
The status should be success
The lines of output should equal 3
The lines of output should equal 5
The lines of error should equal 0
The line 1 should equal "$MESSAGE_CONFIGURING_PIP"
The line 2 should equal "Repox host: repox.jfrog.io:8080/artifactory"
The line 3 should start with "Configuration file: "
The line 3 should end with "/.pip/pip.conf"
The line 4 should equal "::add-mask::https://test-user:test-token@repox.jfrog.io:8080/artifactory/api/pypi/sonarsource-pypi/simple"
The line 5 should equal "::add-mask::https://test-user:test-token@repox.jfrog.io:8080/artifactory/api/pypi/sonarsource-pypi/simple/{}/"
The contents of file "${HOME}/.pip/pip.conf" should equal "[global]
index-url = https://test-user:test-token@repox.jfrog.io:8080/artifactory/api/pypi/sonarsource-pypi/simple"
End
Expand All @@ -80,14 +101,16 @@ Describe 'main()'
export ARTIFACTORY_ACCESS_TOKEN="my-secret-token"
When run script config-pip/config.sh
The status should be success
The lines of output should equal 5
The lines of output should equal 7
The lines of error should equal 0
The line 1 should equal "::group::Configure pip"
The line 2 should equal "$MESSAGE_CONFIGURING_PIP"
The line 3 should equal "$MESSAGE_REPOX_HOST"
The line 4 should start with "Configuration file: "
The line 4 should end with "/.pip/pip.conf"
The line 5 should equal "::endgroup::"
The line 5 should equal "::add-mask::https://my-user:my-secret-token@repox.jfrog.io/artifactory/api/pypi/sonarsource-pypi/simple"
The line 6 should equal "::add-mask::https://my-user:my-secret-token@repox.jfrog.io/artifactory/api/pypi/sonarsource-pypi/simple/{}/"
The line 7 should equal "::endgroup::"
The path "${HOME}/.pip/pip.conf" should be file
The contents of file "${HOME}/.pip/pip.conf" should equal "[global]
index-url = https://my-user:my-secret-token@repox.jfrog.io/artifactory/api/pypi/sonarsource-pypi/simple"
Expand Down
Loading