From 7409aff8ba9948cb56423ddb6af8b75b0b12d272 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 1 Apr 2026 16:47:46 +0100 Subject: [PATCH 1/9] add oidc + cleanup --- .circleci/config.yml | 76 ++++++++------ README.md | 107 ++++++++++++++++++-- src/@orb.yaml | 3 +- src/commands/authenticate-with-oidc.yml | 94 +++++++++++++++--- src/commands/ensure-api-key.yml | 5 +- src/commands/install-cli.yml | 127 +++++++++++++++++++++--- src/commands/publish.yml | 74 ++++++++------ src/examples/authenticate-with-oidc.yml | 24 +++++ src/examples/cli-with-oidc.yml | 31 ++++++ src/examples/command-publish.yml | 13 ++- src/executors/default.yml | 9 +- 11 files changed, 460 insertions(+), 103 deletions(-) create mode 100644 src/examples/authenticate-with-oidc.yml create mode 100644 src/examples/cli-with-oidc.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index a9948b9..f4fa5ec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,43 +1,61 @@ version: 2.1 orbs: - cli: circleci/circleci-cli@0.1.5 - orb-tools: circleci/orb-tools@8.27.3 + orb-tools: circleci/orb-tools@12.4.0 -jobs: - publish-orb: - description: Publishes an orb to CircleCI - executor: - cli/default - steps: - - attach_workspace: - at: workspace - - run: - name: > - Publish orb to CircleCI - command: | - if [[ -n $CIRCLE_TAG ]]; then - ORB_REF=$CIRCLE_TAG - else - ORB_REF="dev:$CIRCLE_BRANCH" - fi - circleci orb publish workspace/orb.yml cloudsmith/cloudsmith@$ORB_REF +# Run jobs on all branches and tags +filters: &filters + tags: + only: /.*/ + +# Run jobs only on semver release tags (e.g. v2.0.0) +release-filters: &release-filters + branches: + ignore: /.*/ + tags: + only: /^v[0-9]+\.[0-9]+\.[0-9]+$/ workflows: - verify-and-publish: + lint-pack-publish: jobs: + # Lint all YAML files in src/ - orb-tools/lint: - filters: - tags: - only: /.*/ + filters: *filters + # Pack src/ into a single orb.yml and validate it - orb-tools/pack: + filters: *filters + # Review orb source against CircleCI best practices + - orb-tools/review: + filters: *filters + orb_name: cloudsmith + # RC009: long inline commands (we use inline bash intentionally) + # RC010: snake_case naming (our params use kebab-case by convention) + exclude: RC009,RC010 + # Publish a dev version on every push (except release tags and PRs) + - orb-tools/publish: + name: publish-dev + orb_name: cloudsmith/cloudsmith + vcs_type: << pipeline.project.type >> + pub_type: dev + context: orb-publishing + requires: + - orb-tools/lint + - orb-tools/pack + - orb-tools/review filters: + branches: + ignore: /^pull\/[0-9]+/ tags: - only: /.*/ - - publish-orb: - filters: - tags: - only: /.*/ + ignore: /^v[0-9]+\.[0-9]+\.[0-9]+$/ + # Publish a production version when a semver tag is pushed + - orb-tools/publish: + name: publish-production + orb_name: cloudsmith/cloudsmith + vcs_type: << pipeline.project.type >> + pub_type: production + context: orb-publishing requires: - orb-tools/lint - orb-tools/pack + - orb-tools/review + filters: *release-filters diff --git a/README.md b/README.md index 01314d8..b3bb7bb 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,104 @@ CircleCI orb for publishing packages to (and interacting with) Cloudsmith reposi See [onsite documentation](https://circleci.com/orbs/registry/orb/cloudsmith/cloudsmith) for further details. +## Commands + +### `authenticate-with-oidc` + +Authenticate with Cloudsmith using OpenID Connect (OIDC) to obtain a short-lived API token. The token is exported as the `CLOUDSMITH_API_KEY` environment variable for use by the Cloudsmith CLI or any subsequent steps. + +| Parameter | Type | Default | Description | +|---|---|---|---| +| `organization` | string | *required* | Cloudsmith organization name | +| `service-account` | string | *required* | Cloudsmith service account name | +| `oidc-audience` | string | `""` | Custom audience for the OIDC token exchange (omitted when empty) | +| `oidc-auth-retry` | integer | `3` | Number of token exchange attempts (5 s delay between retries) | + + +### `install-cli` + +Installs the Cloudsmith CLI by downloading the zipapp from Cloudsmith. Set `pip-install: true` to install via pip instead. Optional parameters configure the CLI via `~/.cloudsmith/config.ini`. + +| Parameter | Type | Default | Description | +|---|---|---|---| +| `cli-version` | string | `""` | Pin a specific CLI version (e.g. `"1.2.0"`). Empty installs the latest | +| `pip-install` | boolean | `false` | Install via pip instead of the default zipapp | +| `install-path` | string | `/usr/local/bin` | Directory where the zipapp binary is installed (ignored when using pip) | +| `api-host` | string | `""` | Override `api_host` in config.ini (default: `api.cloudsmith.io`) | +| `api-proxy` | string | `""` | HTTP/HTTPS proxy (`api_proxy` in config.ini) | +| `api-ssl-verify` | boolean | `true` | Enable/disable SSL verification (`api_ssl_verify` in config.ini) | +| `api-user-agent` | string | `""` | Custom user-agent (`api_user_agent` in config.ini) | + +### `ensure-api-key` + +Validates that the `CLOUDSMITH_API_KEY` environment variable is set. Fails the build immediately if it is missing. + +### `publish` *(deprecated)* + +Wraps individual `cloudsmith push` calls. This command will be removed in a future major version. The recommended approach is to call `install-cli` and `authenticate-with-oidc` (or `ensure-api-key`), then invoke the Cloudsmith CLI directly in your run steps. + +## Executor + +The `default` executor uses the `cimg/python` convenience image (default tag `3.12`), which has the prerequisites for installing the Cloudsmith CLI. + +## Usage + +### Recommended — OIDC authentication with direct CLI usage + +```yaml +version: 2.1 + +orbs: + cloudsmith: cloudsmith/cloudsmith@2.0.0 + +workflows: + publish: + jobs: + - publish + +jobs: + publish: + executor: cloudsmith/default + steps: + - checkout + - cloudsmith/authenticate-with-oidc: + organization: my-org + service-account: my-service-account + - cloudsmith/install-cli + - run: + name: Build and publish Python package + command: | + pip install build + python -m build --wheel + cloudsmith push python my-org/my-repo dist/*.whl +``` + +### API key authentication + +```yaml +version: 2.1 + +orbs: + cloudsmith: cloudsmith/cloudsmith@2.0.0 + +jobs: + publish: + executor: cloudsmith/default + steps: + - checkout + - cloudsmith/ensure-api-key + - cloudsmith/install-cli + - run: + name: Build and publish + command: | + pip install build + python -m build --wheel + cloudsmith push python cloudsmith/examples dist/*.whl +``` + ## Development -We use the [CircleCI CLI](https://circleci.com/docs/2.0/local-cli/) to perform common development and release tasks for this orb. Please first ensure you have it installed and configured with appropriate credentials. +We use the [CircleCI CLI](https://circleci.com/docs/guides/toolkit/local-cli/) to perform common development and release tasks for this orb. Please first ensure you have it installed and configured with appropriate credentials. ### Generating the orb @@ -26,14 +121,12 @@ $ circleci orb validate orb.yml ## Release Management -Releasing the orb happens automatically from CI. The orb is linted (`yamllint`) and validated (`circleci orb validate`) as part of the CI process. +Releasing the orb happens automatically from CI using the [`circleci/orb-tools`](https://circleci.com/developer/orbs/orb/circleci/orb-tools) orb. The orb source is linted, reviewed for best practices, packed, and validated as part of the pipeline. -### Dev/Alpha releases +### Dev releases -To make an development (or alpha) release, simply push your changes to a branch on Github. CircleCI will automatically build the orb and push a development release to the version `cloudsmith/cloudsmith@dev:$BRANCH_NAME`. +Dev releases are published automatically on every push that is not a release tag. They are mutable and expire after 90 days. ### Production releases -Once happy with your changes, merge to master as normal via a PR and then tag a new release (either via CI or the Github UI) with an appropriate version number (must be semver compatible). - -For example, if you create a tag named `2.0.0` it'll result in a public release to `cloudsmith/cloudsmith@2.0.0`. +Once your PR is approved, a Cloudsmith maintainer will merge it and tag a new release using a `v`-prefixed semver tag. For example, tagging `v2.0.0` publishes the orb as `cloudsmith/cloudsmith@2.0.0`. diff --git a/src/@orb.yaml b/src/@orb.yaml index f7243b5..95a2bcc 100644 --- a/src/@orb.yaml +++ b/src/@orb.yaml @@ -1,7 +1,8 @@ version: 2.1 description: | - Install the Cloudsmith CLI and publish packages to Cloudsmith. + Install the Cloudsmith CLI and publish packages to Cloudsmith repositories. + Supports OIDC and API key authentication with configurable CLI options. display: home_url: https://cloudsmith.io/ diff --git a/src/commands/authenticate-with-oidc.yml b/src/commands/authenticate-with-oidc.yml index 08906ab..4d7bea3 100644 --- a/src/commands/authenticate-with-oidc.yml +++ b/src/commands/authenticate-with-oidc.yml @@ -1,39 +1,103 @@ description: > Authenticate with Cloudsmith using OpenID Connect (OIDC) to generate a - short-lived OIDC token for use in subsequent Cloudsmith requests. This + short-lived API token for use in subsequent Cloudsmith requests. This sets the CLOUDSMITH_API_KEY environment variable to the retrieved token - for use with the Cloudsmith CLI. + for use with the Cloudsmith CLI. Retries the token exchange up to + oidc-auth-retry times (default 3) with a 5-second delay between attempts. + To use OIDC authentication without installing the CLI, simply call this + command on its own and omit install-cli from your workflow steps. parameters: organization: type: string - description: The name of the Cloudsmith organization to use for authentication + description: > + The name of the Cloudsmith organization to use for authentication. service-account: type: string - description: The name of the Cloudsmith service account to use for authentication + description: > + The name of the Cloudsmith service account to use for authentication. + oidc-audience: + type: string + default: "" + description: > + Custom audience value sent in the OIDC token exchange request body. + Leave empty to omit the field and use Cloudsmith's default audience. + oidc-auth-retry: + type: integer + default: 3 + description: > + Total number of attempts for the OIDC token exchange. Each retry waits + 5 seconds before the next attempt. The step fails if all attempts are + exhausted without a valid token. steps: - run: name: Authenticate to Cloudsmith with OIDC command: | organization="<>" service_account="<>" + oidc_audience="<>" + max_retries=<> oidc_endpoint="https://api.cloudsmith.io/openid/$organization/" - payload=$(jq -n \ + # Verify required tools are available + for cmd in curl jq; do + if ! command -v "$cmd" > /dev/null; then + echo "$cmd is required but not found. Ensure it is installed." + exit 1 + fi + done + + if [[ -z "$CIRCLE_OIDC_TOKEN_V2" ]]; then + echo "CIRCLE_OIDC_TOKEN_V2 is not set." + echo "Enable OIDC: Project Settings -> Advanced -> Enable OIDC." + exit 1 + fi + + attempt=0 + while [[ $attempt -lt $max_retries ]]; do + attempt=$((attempt + 1)) + echo "OIDC authentication attempt $attempt of $max_retries" + + payload=$(jq -n \ --arg oidc_token "$CIRCLE_OIDC_TOKEN_V2" \ --arg service_slug "$service_account" \ '{ - oidc_token: $oidc_token, - service_slug: $service_slug - }' - ) + oidc_token: $oidc_token, + service_slug: $service_slug + }') + + if [[ -n "$oidc_audience" ]]; then + payload=$(echo "$payload" | jq \ + --arg audience "$oidc_audience" \ + '. + {audience: $audience}') + fi - response=$(curl -X POST \ + http_code=$(curl -X POST \ -H "Content-Type: application/json" \ -d "$payload" \ --silent \ - "$oidc_endpoint" - ) + --output /tmp/cloudsmith_oidc_response.json \ + --write-out '%{http_code}' \ + "$oidc_endpoint") || true + + if [[ "$http_code" -ge 200 && "$http_code" -lt 300 ]]; then + token=$(jq -r '.token // empty' /tmp/cloudsmith_oidc_response.json) + + if [[ -n "$token" ]]; then + echo "export CLOUDSMITH_API_KEY=\"$token\"" >> "$BASH_ENV" + echo "Successfully authenticated with Cloudsmith via OIDC." + rm -f /tmp/cloudsmith_oidc_response.json + exit 0 + fi + fi + + echo "OIDC token exchange failed (attempt $attempt, HTTP $http_code)." + + if [[ $attempt -lt $max_retries ]]; then + echo "Retrying in 5 seconds..." + sleep 5 + fi + done - token=$(echo "$response" | jq -r '.token') - echo "export CLOUDSMITH_API_KEY=$token" >> "$BASH_ENV" - source "$BASH_ENV" + rm -f /tmp/cloudsmith_oidc_response.json + echo "OIDC authentication failed after $max_retries attempt(s)." + exit 1 diff --git a/src/commands/ensure-api-key.yml b/src/commands/ensure-api-key.yml index 91051d3..daf9716 100644 --- a/src/commands/ensure-api-key.yml +++ b/src/commands/ensure-api-key.yml @@ -6,5 +6,6 @@ steps: - run: name: Check for CLOUDSMITH_API_KEY environment variable command: | - : "${CLOUDSMITH_API_KEY?CLOUDSMITH_API_KEY must be set in the build environment}" - echo "Checking for the Cloudsmith API key" + : "${CLOUDSMITH_API_KEY?CLOUDSMITH_API_KEY must be set in the build \ + environment}" + echo "Cloudsmith API key found." diff --git a/src/commands/install-cli.yml b/src/commands/install-cli.yml index dbf4e39..cc99fcd 100644 --- a/src/commands/install-cli.yml +++ b/src/commands/install-cli.yml @@ -1,25 +1,124 @@ description: > - This command uses pip to install the Cloudsmith CLI from PyPI into the CI - environment, or falls back to downloading the latest zipapp if pip is not - available. The Cloudsmith CLI is used for publishing packages to Cloudsmith - from your build jobs. + Installs the Cloudsmith CLI by downloading the zipapp from Cloudsmith. + Set pip-install to true to install via pip instead. Pass cli-version to + pin a specific release. Optional API configuration parameters are written + to the CLI config file (~/.cloudsmith/config.ini) for use in subsequent steps. +parameters: + cli-version: + type: string + default: "" + description: > + Pin a specific Cloudsmith CLI version (e.g. "1.2.0"). Leave empty to + install the latest available release. + pip-install: + type: boolean + default: false + description: > + Install via pip instead of the default zipapp. When true pip must be + available — the step fails if pip is not found. + install-path: + type: string + default: /usr/local/bin + description: > + Directory where the Cloudsmith CLI zipapp binary is installed. Ignored + when installing via pip. + api-host: + type: string + default: "" + description: > + Override the Cloudsmith API host (api_host in config.ini). Leave empty + to use the default (api.cloudsmith.io). + api-proxy: + type: string + default: "" + description: > + HTTP/HTTPS proxy URL for Cloudsmith API calls (api_proxy in config.ini). + Leave empty for no proxy. + api-ssl-verify: + type: boolean + default: true + description: > + Enable or disable SSL certificate verification for Cloudsmith API calls + (api_ssl_verify in config.ini). + api-user-agent: + type: string + default: "" + description: > + Custom user-agent string sent with Cloudsmith API requests (api_user_agent + in config.ini). Leave empty to use the default. steps: - run: name: Install Cloudsmith CLI command: | - if [[ $(command -v cloudsmith) == "" ]]; then - export PIP=$(which pip pip3 | head -1) - if [[ -n $PIP ]]; then - if which sudo > /dev/null; then - sudo $PIP install cloudsmith-cli --upgrade + cli_version="<>" + force_pip="<>" + install_path="<>" + api_host="<>" + api_proxy="<>" + api_ssl_verify="<>" + api_user_agent="<>" + + # Write CLI configuration to config.ini if any api-* parameters are set + if [[ -n "$api_host" || -n "$api_proxy" || "$api_ssl_verify" == "false" || -n "$api_user_agent" ]]; then + config_dir="${HOME}/.cloudsmith" + config_file="${config_dir}/config.ini" + mkdir -p "$config_dir" + { + echo "[default]" + echo "api_host=${api_host}" + echo "api_proxy=${api_proxy}" + echo "api_ssl_verify=${api_ssl_verify}" + echo "api_user_agent=${api_user_agent}" + } > "$config_file" + echo "Cloudsmith CLI config written to $config_file" + fi + + # Install the Cloudsmith CLI + if command -v cloudsmith > /dev/null && [[ "$force_pip" != "true" ]]; then + if [[ -n "$cli_version" ]]; then + echo "Warning: Cloudsmith CLI is already installed." \ + "cli-version='$cli_version' was ignored. Set pip-install: true" \ + "to enforce the version." + else + echo "Cloudsmith CLI is already installed." + fi + + elif [[ "$force_pip" == "true" ]]; then + # Pip installation (only when explicitly requested) + PIP=$(command -v pip 2>/dev/null || command -v pip3 2>/dev/null) + if [[ -z "$PIP" ]]; then + echo "pip-install is true but pip was not found. Ensure pip is" \ + "available in this executor." + exit 1 + fi + + if [[ -n "$cli_version" ]]; then + if command -v sudo > /dev/null; then + sudo "$PIP" install "cloudsmith-cli==$cli_version" else - $PIP install cloudsmith-cli --upgrade --user + "$PIP" install "cloudsmith-cli==$cli_version" --user fi else - latest_pyz=$(curl -s https://api.github.com/repos/cloudsmith-io/cloudsmith-cli/releases/latest | jq -r '.assets[] | select(.name | endswith(".pyz")) | .browser_download_url') - curl -L $latest_pyz -o /home/circleci/bin/cloudsmith - chmod +x /home/circleci/bin/cloudsmith + if command -v sudo > /dev/null; then + sudo "$PIP" install cloudsmith-cli --upgrade + else + "$PIP" install cloudsmith-cli --upgrade --user + fi fi + else - echo "Cloudsmith CLI is already installed." + # Default: download zipapp from Cloudsmith + if [[ -n "$cli_version" ]]; then + pyz_url="https://dl.cloudsmith.io/public/cloudsmith/cli-zipapp/raw/names/cloudsmith-cli/versions/${cli_version}/cloudsmith.pyz" + else + pyz_url="https://dl.cloudsmith.io/public/cloudsmith/cli-zipapp/raw/names/cloudsmith-cli/versions/latest/cloudsmith.pyz" + fi + + mkdir -p "$install_path" + if ! curl -1sLf "$pyz_url" -o "${install_path}/cloudsmith"; then + echo "Failed to download Cloudsmith CLI zipapp from:" + echo " $pyz_url" + exit 1 + fi + chmod +x "${install_path}/cloudsmith" fi diff --git a/src/commands/publish.yml b/src/commands/publish.yml index 9a0d64c..d91eefe 100644 --- a/src/commands/publish.yml +++ b/src/commands/publish.yml @@ -1,9 +1,10 @@ description: > - This command uses the Cloudsmith CLI to publish packages to Cloudsmith. - Packages are uploaded and then verified with the CLI. If the upload (or - subsequent server-side processing) fails then this command will also exit - with a failing status. Most common configuration parameters are exposed via - the orb to allow seamless integration with your existing CircleCI workflows. + DEPRECATED: This command wraps individual cloudsmith push calls and will be + removed in a future major version. The recommended approach is to call + install-cli and authenticate-with-oidc (or ensure-api-key), then invoke the + Cloudsmith CLI directly in your run steps — e.g. "cloudsmith push python + my-org/my-repo dist/package-*.whl". All existing parameters continue to work + as before. parameters: cloudsmith-repository: type: string @@ -17,19 +18,27 @@ parameters: package-distribution: type: string default: "" - description: distro/release for which the package is built (required only for deb, rpm and alpine). + description: > + distro/release for which the package is built (required only for deb, + rpm and alpine). package-pom-file: type: string default: "" - description: Path to the POM file associated with a maven release (required only for maven). + description: > + Path to the POM file associated with a maven release (required only + for maven). allow-republish: type: boolean default: false - description: Allow publishing a package that overwrites an existing version on Cloudsmith. + description: > + Allow publishing a package that overwrites an existing version on + Cloudsmith. package-description: type: string default: "" - description: Optional description for the package being published (applied only to raw). + description: > + Optional description for the package being published (applied only to + raw). package-name: type: string default: "" @@ -55,44 +64,53 @@ steps: package_summary="<>" package_version="<>" - # Use `ls` to resolve any shell globs in parameters.package-path - package_path="$(ls <>)" + # Resolve shell globs in package-path + # shellcheck disable=SC2086 + package_path=$(echo <>) + if [[ -z "$package_path" ]]; then + echo "No files matched the package-path pattern." + exit 1 + fi # Handle optional arguments - additional_args= + additional_args=() <<# parameters.allow-republish >> - additional_args+="--republish" + additional_args+=("--republish") <> # Handle per-format required arguments - if [[ "$package_format" == "alpine" || "$package_format" == "deb" || "$package_format" == "rpm" ]]; then - if [[ "$package_distribution" == "" ]]; then - echo "\"package-distribution\" parameter is required when \"package-format\" is alpine, deb, or rpm" + if [[ "$package_format" == "alpine" || "$package_format" == "deb" || + "$package_format" == "rpm" ]]; then + if [[ -z "$package_distribution" ]]; then + echo "\"package-distribution\" parameter is required when" \ + "\"package-format\" is alpine, deb, or rpm" exit 1 fi cloudsmith_repository+="/$package_distribution" fi if [[ "$package_format" == "maven" ]]; then - if [[ "$package_pom_file" == "" ]]; then - echo "\"package-pom-file\" parameter is required when \"package-format\" is maven" + if [[ -z "$package_pom_file" ]]; then + echo "\"package-pom-file\" parameter is required when" \ + "\"package-format\" is maven" exit 1 fi - additional_args+=" --pom-file $package_pom_file" + additional_args+=("--pom-file" "$package_pom_file") fi if [[ "$package_format" == "raw" ]]; then - if [[ ! -z "$package_description" ]]; then - additional_args+=" --description $package_description" + if [[ -n "$package_description" ]]; then + additional_args+=("--description" "$package_description") fi - if [[ ! -z "$package_name" ]]; then - additional_args+=" --name $package_name" + if [[ -n "$package_name" ]]; then + additional_args+=("--name" "$package_name") fi - if [[ ! -z "$package_summary" ]]; then - additional_args+=" --summary $package_summary" + if [[ -n "$package_summary" ]]; then + additional_args+=("--summary" "$package_summary") fi - if [[ ! -z "$package_version" ]]; then - additional_args+=" --version $package_version" + if [[ -n "$package_version" ]]; then + additional_args+=("--version" "$package_version") fi fi # Publish package using the Cloudsmith CLI - cloudsmith push $package_format $additional_args $cloudsmith_repository $package_path + cloudsmith push "$package_format" "${additional_args[@]}" \ + "$cloudsmith_repository" $package_path diff --git a/src/examples/authenticate-with-oidc.yml b/src/examples/authenticate-with-oidc.yml new file mode 100644 index 0000000..36d8058 --- /dev/null +++ b/src/examples/authenticate-with-oidc.yml @@ -0,0 +1,24 @@ +description: > + Authenticate with Cloudsmith using OpenID Connect (OIDC) to obtain a + short-lived API token. The token is exported as CLOUDSMITH_API_KEY and can + be used in subsequent steps without installing the Cloudsmith CLI. +usage: + version: 2.1 + + orbs: + cloudsmith: cloudsmith/cloudsmith@2.0.0 + + workflows: + cloudsmith_oidc_auth: + jobs: + - authenticate + + jobs: + authenticate: + executor: + cloudsmith/default + steps: + - checkout + - cloudsmith/authenticate-with-oidc: + organization: my-org + service-account: my-service-account diff --git a/src/examples/cli-with-oidc.yml b/src/examples/cli-with-oidc.yml new file mode 100644 index 0000000..5df0f9f --- /dev/null +++ b/src/examples/cli-with-oidc.yml @@ -0,0 +1,31 @@ +description: > + Recommended workflow — authenticate with Cloudsmith via OIDC and install the + CLI, then invoke the CLI directly in your run steps. This pattern gives you + full access to all Cloudsmith CLI commands. +usage: + version: 2.1 + + orbs: + cloudsmith: cloudsmith/cloudsmith@2.0.0 + + workflows: + cloudsmith_oidc_publish: + jobs: + - publish + + jobs: + publish: + executor: + cloudsmith/default + steps: + - checkout + - cloudsmith/authenticate-with-oidc: + organization: my-org + service-account: my-service-account + - cloudsmith/install-cli + - run: + name: Build and publish Python package + command: | + pip install build + python -m build --wheel + cloudsmith push python my-org/my-repo dist/*.whl diff --git a/src/examples/command-publish.yml b/src/examples/command-publish.yml index 581987b..72d17cd 100644 --- a/src/examples/command-publish.yml +++ b/src/examples/command-publish.yml @@ -1,9 +1,12 @@ -description: Customize your Cloudsmith workflow using the commands from this orb +description: >- + Legacy workflow — authenticate with a static API key and use the deprecated + publish command. For new projects prefer the OIDC-based approach shown in + the cli-with-oidc example. usage: version: 2.1 orbs: - cloudsmith: cloudsmith/cloudsmith@1.0.3 + cloudsmith: cloudsmith/cloudsmith@2.0.0 workflows: cloudsmith_publish: @@ -20,8 +23,10 @@ usage: - cloudsmith/install-cli - run: name: Build Python package - command: python setup.py bdist_wheel + command: | + pip install build + python -m build --wheel - cloudsmith/publish: cloudsmith-repository: cloudsmith/examples - package-path: dist/package-*.whl + package-path: dist/*.whl package-format: python diff --git a/src/executors/default.yml b/src/executors/default.yml index a52f0e8..0665cc6 100644 --- a/src/executors/default.yml +++ b/src/executors/default.yml @@ -1,8 +1,11 @@ description: | - Uses the basic circleci/python image, which has the prerequisites for installing Cloudsmith's CLI. + Uses the cimg/python convenience image, which has the prerequisites for installing Cloudsmith's CLI. parameters: tag: type: string - default: "3.7.4" + default: "3.12" + description: >- + Pick a specific cimg/python image version tag: + https://circleci.com/developer/images/image/cimg/python docker: - - image: circleci/python:<> + - image: cimg/python:<> From 86be1373a40a8a619943edb6248e83fef9a7d740 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 1 Apr 2026 16:49:17 +0100 Subject: [PATCH 2/9] add oidc + cleanup --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3bb7bb..c0649de 100644 --- a/README.md +++ b/README.md @@ -129,4 +129,4 @@ Dev releases are published automatically on every push that is not a release tag ### Production releases -Once your PR is approved, a Cloudsmith maintainer will merge it and tag a new release using a `v`-prefixed semver tag. For example, tagging `v2.0.0` publishes the orb as `cloudsmith/cloudsmith@2.0.0`. +Once your PR is approved, a Cloudsmith maintainer will merge it and tag a new release. From cb7cfcaef5865feebfdddc09af0d8b81c62a0e9a Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 1 Apr 2026 16:53:36 +0100 Subject: [PATCH 3/9] add oidc + cleanup --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c0649de..6c4c783 100644 --- a/README.md +++ b/README.md @@ -123,10 +123,10 @@ $ circleci orb validate orb.yml Releasing the orb happens automatically from CI using the [`circleci/orb-tools`](https://circleci.com/developer/orbs/orb/circleci/orb-tools) orb. The orb source is linted, reviewed for best practices, packed, and validated as part of the pipeline. -### Dev releases - -Dev releases are published automatically on every push that is not a release tag. They are mutable and expire after 90 days. +### Dev/Alpha releases +To make an development (or alpha) release, simply push your changes to a branch on Github. CircleCI will automatically build the orb and push a development release to the version `cloudsmith/cloudsmith@dev:$BRANCH_NAME`. ### Production releases +Once happy with your changes, merge to master as normal via a PR and then tag a new release (either via CI or the Github UI) with an appropriate version number (must be semver compatible). -Once your PR is approved, a Cloudsmith maintainer will merge it and tag a new release. +For example, if you create a tag named `2.0.0` it'll result in a public release to `cloudsmith/cloudsmith@2.0.0`. From 659ea9243893b71b804564419121f7d666ec6e9a Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 1 Apr 2026 17:08:15 +0100 Subject: [PATCH 4/9] small changes --- src/commands/authenticate-with-oidc.yml | 14 +++--- src/commands/publish.yml | 63 +++++++++---------------- src/examples/command-publish.yml | 13 ++--- 3 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/commands/authenticate-with-oidc.yml b/src/commands/authenticate-with-oidc.yml index 4d7bea3..a8c8f84 100644 --- a/src/commands/authenticate-with-oidc.yml +++ b/src/commands/authenticate-with-oidc.yml @@ -71,21 +71,21 @@ steps: '. + {audience: $audience}') fi - http_code=$(curl -X POST \ + response=$(curl -s -X POST \ -H "Content-Type: application/json" \ -d "$payload" \ - --silent \ - --output /tmp/cloudsmith_oidc_response.json \ - --write-out '%{http_code}' \ + --write-out '\n%{http_code}' \ "$oidc_endpoint") || true + http_code=$(echo "$response" | tail -n1) + body=$(echo "$response" | sed '$d') + if [[ "$http_code" -ge 200 && "$http_code" -lt 300 ]]; then - token=$(jq -r '.token // empty' /tmp/cloudsmith_oidc_response.json) + token=$(echo "$body" | jq -r '.token // empty') if [[ -n "$token" ]]; then echo "export CLOUDSMITH_API_KEY=\"$token\"" >> "$BASH_ENV" echo "Successfully authenticated with Cloudsmith via OIDC." - rm -f /tmp/cloudsmith_oidc_response.json exit 0 fi fi @@ -97,7 +97,5 @@ steps: sleep 5 fi done - - rm -f /tmp/cloudsmith_oidc_response.json echo "OIDC authentication failed after $max_retries attempt(s)." exit 1 diff --git a/src/commands/publish.yml b/src/commands/publish.yml index d91eefe..db7f5e3 100644 --- a/src/commands/publish.yml +++ b/src/commands/publish.yml @@ -18,27 +18,19 @@ parameters: package-distribution: type: string default: "" - description: > - distro/release for which the package is built (required only for deb, - rpm and alpine). + description: distro/release for which the package is built (required only for deb, rpm and alpine). package-pom-file: type: string default: "" - description: > - Path to the POM file associated with a maven release (required only - for maven). + description: Path to the POM file associated with a maven release (required only for maven). allow-republish: type: boolean default: false - description: > - Allow publishing a package that overwrites an existing version on - Cloudsmith. + description: Allow publishing a package that overwrites an existing version on Cloudsmith. package-description: type: string default: "" - description: > - Optional description for the package being published (applied only to - raw). + description: Optional description for the package being published (applied only to raw). package-name: type: string default: "" @@ -64,53 +56,44 @@ steps: package_summary="<>" package_version="<>" - # Resolve shell globs in package-path - # shellcheck disable=SC2086 - package_path=$(echo <>) - if [[ -z "$package_path" ]]; then - echo "No files matched the package-path pattern." - exit 1 - fi + # Use `ls` to resolve any shell globs in parameters.package-path + package_path="$(ls <>)" # Handle optional arguments - additional_args=() + additional_args= <<# parameters.allow-republish >> - additional_args+=("--republish") + additional_args+="--republish" <> # Handle per-format required arguments - if [[ "$package_format" == "alpine" || "$package_format" == "deb" || - "$package_format" == "rpm" ]]; then - if [[ -z "$package_distribution" ]]; then - echo "\"package-distribution\" parameter is required when" \ - "\"package-format\" is alpine, deb, or rpm" + if [[ "$package_format" == "alpine" || "$package_format" == "deb" || "$package_format" == "rpm" ]]; then + if [[ "$package_distribution" == "" ]]; then + echo "\"package-distribution\" parameter is required when \"package-format\" is alpine, deb, or rpm" exit 1 fi cloudsmith_repository+="/$package_distribution" fi if [[ "$package_format" == "maven" ]]; then - if [[ -z "$package_pom_file" ]]; then - echo "\"package-pom-file\" parameter is required when" \ - "\"package-format\" is maven" + if [[ "$package_pom_file" == "" ]]; then + echo "\"package-pom-file\" parameter is required when \"package-format\" is maven" exit 1 fi - additional_args+=("--pom-file" "$package_pom_file") + additional_args+=" --pom-file $package_pom_file" fi if [[ "$package_format" == "raw" ]]; then - if [[ -n "$package_description" ]]; then - additional_args+=("--description" "$package_description") + if [[ ! -z "$package_description" ]]; then + additional_args+=" --description $package_description" fi - if [[ -n "$package_name" ]]; then - additional_args+=("--name" "$package_name") + if [[ ! -z "$package_name" ]]; then + additional_args+=" --name $package_name" fi - if [[ -n "$package_summary" ]]; then - additional_args+=("--summary" "$package_summary") + if [[ ! -z "$package_summary" ]]; then + additional_args+=" --summary $package_summary" fi - if [[ -n "$package_version" ]]; then - additional_args+=("--version" "$package_version") + if [[ ! -z "$package_version" ]]; then + additional_args+=" --version $package_version" fi fi # Publish package using the Cloudsmith CLI - cloudsmith push "$package_format" "${additional_args[@]}" \ - "$cloudsmith_repository" $package_path + cloudsmith push $package_format $additional_args $cloudsmith_repository $package_path \ No newline at end of file diff --git a/src/examples/command-publish.yml b/src/examples/command-publish.yml index 72d17cd..929697f 100644 --- a/src/examples/command-publish.yml +++ b/src/examples/command-publish.yml @@ -1,7 +1,4 @@ -description: >- - Legacy workflow — authenticate with a static API key and use the deprecated - publish command. For new projects prefer the OIDC-based approach shown in - the cli-with-oidc example. +description: Customize your Cloudsmith workflow using the commands from this orb usage: version: 2.1 @@ -23,10 +20,8 @@ usage: - cloudsmith/install-cli - run: name: Build Python package - command: | - pip install build - python -m build --wheel + command: python setup.py bdist_wheel - cloudsmith/publish: cloudsmith-repository: cloudsmith/examples - package-path: dist/*.whl - package-format: python + package-path: dist/package-*.whl + package-format: python \ No newline at end of file From 8d8c2ea10ed678e64fc14666de22fd376cc49abe Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 1 Apr 2026 17:41:46 +0100 Subject: [PATCH 5/9] pipeline fixes --- .yamllint | 11 +++++++++++ src/{@orb.yaml => @orb.yml} | 1 + src/commands/authenticate-with-oidc.yml | 1 + src/commands/ensure-api-key.yml | 1 + src/commands/install-cli.yml | 1 + src/commands/publish.yml | 3 ++- src/examples/authenticate-with-oidc.yml | 1 + src/examples/cli-with-oidc.yml | 1 + src/examples/command-publish.yml | 3 ++- src/executors/default.yml | 1 + 10 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .yamllint rename src/{@orb.yaml => @orb.yml} (98%) diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..0e7e28c --- /dev/null +++ b/.yamllint @@ -0,0 +1,11 @@ +--- +extends: default + +rules: + line-length: + max: 200 + truthy: + check-keys: true + comments: + min-spaces-from-content: 1 + document-start: enable diff --git a/src/@orb.yaml b/src/@orb.yml similarity index 98% rename from src/@orb.yaml rename to src/@orb.yml index 95a2bcc..56d8ecf 100644 --- a/src/@orb.yaml +++ b/src/@orb.yml @@ -1,3 +1,4 @@ +--- version: 2.1 description: | diff --git a/src/commands/authenticate-with-oidc.yml b/src/commands/authenticate-with-oidc.yml index a8c8f84..99c997b 100644 --- a/src/commands/authenticate-with-oidc.yml +++ b/src/commands/authenticate-with-oidc.yml @@ -1,3 +1,4 @@ +--- description: > Authenticate with Cloudsmith using OpenID Connect (OIDC) to generate a short-lived API token for use in subsequent Cloudsmith requests. This diff --git a/src/commands/ensure-api-key.yml b/src/commands/ensure-api-key.yml index daf9716..378c71b 100644 --- a/src/commands/ensure-api-key.yml +++ b/src/commands/ensure-api-key.yml @@ -1,3 +1,4 @@ +--- description: > This command checks and ensures that a Cloudsmith API key has been configured correctly in the CI environment such that the Cloudsmith CLI will be able to diff --git a/src/commands/install-cli.yml b/src/commands/install-cli.yml index cc99fcd..0d77d19 100644 --- a/src/commands/install-cli.yml +++ b/src/commands/install-cli.yml @@ -1,3 +1,4 @@ +--- description: > Installs the Cloudsmith CLI by downloading the zipapp from Cloudsmith. Set pip-install to true to install via pip instead. Pass cli-version to diff --git a/src/commands/publish.yml b/src/commands/publish.yml index db7f5e3..5d13edc 100644 --- a/src/commands/publish.yml +++ b/src/commands/publish.yml @@ -1,3 +1,4 @@ +--- description: > DEPRECATED: This command wraps individual cloudsmith push calls and will be removed in a future major version. The recommended approach is to call @@ -96,4 +97,4 @@ steps: fi # Publish package using the Cloudsmith CLI - cloudsmith push $package_format $additional_args $cloudsmith_repository $package_path \ No newline at end of file + cloudsmith push $package_format $additional_args $cloudsmith_repository $package_path diff --git a/src/examples/authenticate-with-oidc.yml b/src/examples/authenticate-with-oidc.yml index 36d8058..5768444 100644 --- a/src/examples/authenticate-with-oidc.yml +++ b/src/examples/authenticate-with-oidc.yml @@ -1,3 +1,4 @@ +--- description: > Authenticate with Cloudsmith using OpenID Connect (OIDC) to obtain a short-lived API token. The token is exported as CLOUDSMITH_API_KEY and can diff --git a/src/examples/cli-with-oidc.yml b/src/examples/cli-with-oidc.yml index 5df0f9f..27e4a74 100644 --- a/src/examples/cli-with-oidc.yml +++ b/src/examples/cli-with-oidc.yml @@ -1,3 +1,4 @@ +--- description: > Recommended workflow — authenticate with Cloudsmith via OIDC and install the CLI, then invoke the CLI directly in your run steps. This pattern gives you diff --git a/src/examples/command-publish.yml b/src/examples/command-publish.yml index 929697f..cdfd752 100644 --- a/src/examples/command-publish.yml +++ b/src/examples/command-publish.yml @@ -1,3 +1,4 @@ +--- description: Customize your Cloudsmith workflow using the commands from this orb usage: version: 2.1 @@ -24,4 +25,4 @@ usage: - cloudsmith/publish: cloudsmith-repository: cloudsmith/examples package-path: dist/package-*.whl - package-format: python \ No newline at end of file + package-format: python diff --git a/src/executors/default.yml b/src/executors/default.yml index 0665cc6..ee19d2d 100644 --- a/src/executors/default.yml +++ b/src/executors/default.yml @@ -1,3 +1,4 @@ +--- description: | Uses the cimg/python convenience image, which has the prerequisites for installing Cloudsmith's CLI. parameters: From 1acb4b946bd6bc987564aee27597469a2567aa7a Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 1 Apr 2026 18:27:19 +0100 Subject: [PATCH 6/9] make install more readable, seperate into functions --- .circleci/config.yml | 1 + README.md | 8 +- src/commands/install-cli.yml | 143 ++++++++++++++++++++++++++--------- 3 files changed, 112 insertions(+), 40 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f4fa5ec..4226ce7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,3 +1,4 @@ +--- version: 2.1 orbs: diff --git a/README.md b/README.md index 6c4c783..c5e4d0c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Installs the Cloudsmith CLI by downloading the zipapp from Cloudsmith. Set `pip- |---|---|---|---| | `cli-version` | string | `""` | Pin a specific CLI version (e.g. `"1.2.0"`). Empty installs the latest | | `pip-install` | boolean | `false` | Install via pip instead of the default zipapp | -| `install-path` | string | `/usr/local/bin` | Directory where the zipapp binary is installed (ignored when using pip) | +| `install-path` | string | `$HOME/bin` | Directory where the zipapp binary is installed and added to `PATH` (ignored when using pip) | | `api-host` | string | `""` | Override `api_host` in config.ini (default: `api.cloudsmith.io`) | | `api-proxy` | string | `""` | HTTP/HTTPS proxy (`api_proxy` in config.ini) | | `api-ssl-verify` | boolean | `true` | Enable/disable SSL verification (`api_ssl_verify` in config.ini) | @@ -124,9 +124,9 @@ $ circleci orb validate orb.yml Releasing the orb happens automatically from CI using the [`circleci/orb-tools`](https://circleci.com/developer/orbs/orb/circleci/orb-tools) orb. The orb source is linted, reviewed for best practices, packed, and validated as part of the pipeline. ### Dev/Alpha releases -To make an development (or alpha) release, simply push your changes to a branch on Github. CircleCI will automatically build the orb and push a development release to the version `cloudsmith/cloudsmith@dev:$BRANCH_NAME`. +To make a development (or alpha) release, simply push your changes to a branch on GitHub. CircleCI will automatically build the orb and push a development release to the version `cloudsmith/cloudsmith@dev:$BRANCH_NAME`. ### Production releases -Once happy with your changes, merge to master as normal via a PR and then tag a new release (either via CI or the Github UI) with an appropriate version number (must be semver compatible). +Once happy with your changes, merge to master as normal via a PR and then tag a new release (either via CI or the GitHub UI) with an appropriate `v`-prefixed semver version. -For example, if you create a tag named `2.0.0` it'll result in a public release to `cloudsmith/cloudsmith@2.0.0`. +For example, if you create a tag named `v2.0.0` it'll result in a public release to `cloudsmith/cloudsmith@2.0.0`. diff --git a/src/commands/install-cli.yml b/src/commands/install-cli.yml index 0d77d19..13b9ccf 100644 --- a/src/commands/install-cli.yml +++ b/src/commands/install-cli.yml @@ -19,7 +19,7 @@ parameters: available — the step fails if pip is not found. install-path: type: string - default: /usr/local/bin + default: "$HOME/bin" description: > Directory where the Cloudsmith CLI zipapp binary is installed. Ignored when installing via pip. @@ -59,10 +59,14 @@ steps: api_ssl_verify="<>" api_user_agent="<>" - # Write CLI configuration to config.ini if any api-* parameters are set - if [[ -n "$api_host" || -n "$api_proxy" || "$api_ssl_verify" == "false" || -n "$api_user_agent" ]]; then - config_dir="${HOME}/.cloudsmith" - config_file="${config_dir}/config.ini" + write_cli_config() { + if [[ -z "$api_host" && -z "$api_proxy" && "$api_ssl_verify" != "false" && -z "$api_user_agent" ]]; then + return + fi + + local config_dir="${HOME}/.cloudsmith" + local config_file="${config_dir}/config.ini" + mkdir -p "$config_dir" { echo "[default]" @@ -71,55 +75,122 @@ steps: echo "api_ssl_verify=${api_ssl_verify}" echo "api_user_agent=${api_user_agent}" } > "$config_file" + echo "Cloudsmith CLI config written to $config_file" - fi + } - # Install the Cloudsmith CLI - if command -v cloudsmith > /dev/null && [[ "$force_pip" != "true" ]]; then - if [[ -n "$cli_version" ]]; then - echo "Warning: Cloudsmith CLI is already installed." \ - "cli-version='$cli_version' was ignored. Set pip-install: true" \ - "to enforce the version." - else - echo "Cloudsmith CLI is already installed." - fi + add_install_path() { + case ":$PATH:" in + *":$install_path:"*) ;; + *) + export PATH="$install_path:$PATH" + echo "export PATH=\"$install_path:\$PATH\"" >> "$BASH_ENV" + ;; + esac + } - elif [[ "$force_pip" == "true" ]]; then - # Pip installation (only when explicitly requested) - PIP=$(command -v pip 2>/dev/null || command -v pip3 2>/dev/null) - if [[ -z "$PIP" ]]; then + install_with_pip() { + local pip_cmd + local install_args=("install") + + pip_cmd=$(command -v pip 2>/dev/null || command -v pip3 2>/dev/null) + if [[ -z "$pip_cmd" ]]; then echo "pip-install is true but pip was not found. Ensure pip is" \ "available in this executor." exit 1 fi if [[ -n "$cli_version" ]]; then - if command -v sudo > /dev/null; then - sudo "$PIP" install "cloudsmith-cli==$cli_version" - else - "$PIP" install "cloudsmith-cli==$cli_version" --user - fi + install_args+=("cloudsmith-cli==$cli_version") else - if command -v sudo > /dev/null; then - sudo "$PIP" install cloudsmith-cli --upgrade - else - "$PIP" install cloudsmith-cli --upgrade --user - fi + install_args+=("cloudsmith-cli" "--upgrade") fi - else - # Default: download zipapp from Cloudsmith + if command -v sudo > /dev/null; then + sudo "$pip_cmd" "${install_args[@]}" + else + "$pip_cmd" "${install_args[@]}" --user + fi + } + + zipapp_url() { if [[ -n "$cli_version" ]]; then - pyz_url="https://dl.cloudsmith.io/public/cloudsmith/cli-zipapp/raw/names/cloudsmith-cli/versions/${cli_version}/cloudsmith.pyz" + echo "https://dl.cloudsmith.io/public/cloudsmith/cli-zipapp/raw/names/cloudsmith-cli/versions/${cli_version}/cloudsmith.pyz" else - pyz_url="https://dl.cloudsmith.io/public/cloudsmith/cli-zipapp/raw/names/cloudsmith-cli/versions/latest/cloudsmith.pyz" + echo "https://dl.cloudsmith.io/public/cloudsmith/cli-zipapp/raw/names/cloudsmith-cli/versions/latest/cloudsmith.pyz" fi + } + + download_zipapp() { + local pyz_url="$1" + local destination="$2" - mkdir -p "$install_path" - if ! curl -1sLf "$pyz_url" -o "${install_path}/cloudsmith"; then + if ! curl -sSfL "$pyz_url" -o "$destination"; then echo "Failed to download Cloudsmith CLI zipapp from:" echo " $pyz_url" exit 1 fi - chmod +x "${install_path}/cloudsmith" + } + + install_zipapp() { + local pyz_url + local target + local probe_file + local tmpfile + + pyz_url="$(zipapp_url)" + target="${install_path}/cloudsmith" + probe_file="${install_path}/.cloudsmith-write-test-$$" + + if mkdir -p "$install_path" 2>/dev/null && touch "$probe_file" 2>/dev/null; then + rm -f "$probe_file" + download_zipapp "$pyz_url" "$target" + chmod +x "$target" + elif command -v sudo > /dev/null; then + tmpfile="$(mktemp)" + download_zipapp "$pyz_url" "$tmpfile" + + if ! sudo mkdir -p "$install_path"; then + echo "Failed to create install path '$install_path'." + rm -f "$tmpfile" + exit 1 + fi + + if ! sudo mv "$tmpfile" "$target"; then + echo "Failed to move Cloudsmith CLI zipapp into '$install_path'." + rm -f "$tmpfile" + exit 1 + fi + + sudo chmod +x "$target" + else + echo "Install path '$install_path' is not writable and sudo is not available." + echo "Set 'install-path' to a user-writable directory such as \$HOME/bin." + exit 1 + fi + + add_install_path + echo "Cloudsmith CLI installed to $target" + } + + if [[ "$install_path" == ~* ]]; then + install_path="${install_path/#\~/$HOME}" + fi + + write_cli_config + + # Install the Cloudsmith CLI + if command -v cloudsmith > /dev/null && [[ "$force_pip" != "true" ]]; then + if [[ -n "$cli_version" ]]; then + echo "Warning: Cloudsmith CLI is already installed." \ + "cli-version='$cli_version' was ignored. Set pip-install: true" \ + "to enforce the version." + else + echo "Cloudsmith CLI is already installed." + fi + + elif [[ "$force_pip" == "true" ]]; then + install_with_pip + else + install_zipapp fi From 043c1af434675083ec8701268dda55120b5fef50 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Thu, 2 Apr 2026 09:31:44 +0100 Subject: [PATCH 7/9] final orb testing --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4226ce7..b1d136b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,7 +35,7 @@ workflows: # Publish a dev version on every push (except release tags and PRs) - orb-tools/publish: name: publish-dev - orb_name: cloudsmith/cloudsmith + orb_name: bartoszblizniak/cloudsmith vcs_type: << pipeline.project.type >> pub_type: dev context: orb-publishing @@ -51,7 +51,7 @@ workflows: # Publish a production version when a semver tag is pushed - orb-tools/publish: name: publish-production - orb_name: cloudsmith/cloudsmith + orb_name: bartoszblizniak/cloudsmith vcs_type: << pipeline.project.type >> pub_type: production context: orb-publishing From 9e3c7dba7cda35c990bb641b17a2a4d224b749b0 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Thu, 2 Apr 2026 11:11:49 +0100 Subject: [PATCH 8/9] set value back to cloudsmith --- .circleci/config.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b1d136b..95f98f8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,11 @@ --- version: 2.1 +parameters: + publish-orb-name: + type: string + default: cloudsmith/cloudsmith + orbs: orb-tools: circleci/orb-tools@12.4.0 @@ -35,7 +40,7 @@ workflows: # Publish a dev version on every push (except release tags and PRs) - orb-tools/publish: name: publish-dev - orb_name: bartoszblizniak/cloudsmith + orb_name: << pipeline.parameters.publish-orb-name >> vcs_type: << pipeline.project.type >> pub_type: dev context: orb-publishing @@ -51,7 +56,7 @@ workflows: # Publish a production version when a semver tag is pushed - orb-tools/publish: name: publish-production - orb_name: bartoszblizniak/cloudsmith + orb_name: << pipeline.parameters.publish-orb-name >> vcs_type: << pipeline.project.type >> pub_type: production context: orb-publishing From 5a9d3dde41dcc67203bf35b3f70928fa186923c2 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Thu, 2 Apr 2026 13:00:35 +0100 Subject: [PATCH 9/9] Use min python required for cloudsmith-cli 3.12 -> 3.10 --- README.md | 2 +- src/executors/default.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c5e4d0c..d273528 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Wraps individual `cloudsmith push` calls. This command will be removed in a futu ## Executor -The `default` executor uses the `cimg/python` convenience image (default tag `3.12`), which has the prerequisites for installing the Cloudsmith CLI. +The `default` executor uses the `cimg/python` convenience image (default tag `3.10`), which has the prerequisites for installing the Cloudsmith CLI. ## Usage diff --git a/src/executors/default.yml b/src/executors/default.yml index ee19d2d..89e10b8 100644 --- a/src/executors/default.yml +++ b/src/executors/default.yml @@ -4,7 +4,7 @@ description: | parameters: tag: type: string - default: "3.12" + default: "3.10" description: >- Pick a specific cimg/python image version tag: https://circleci.com/developer/images/image/cimg/python