Merge pull request #136 from open-webui/main #70
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to PyPI | |
| on: | |
| push: | |
| branches: [release] | |
| workflow_dispatch: | |
| concurrency: | |
| group: pypi-${{ github.ref }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| preflight: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.pkg.outputs.version }} | |
| publish_needed: ${{ steps.pypi.outputs.publish_needed }} | |
| release_assets_needed: ${{ steps.release.outputs.release_assets_needed }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Read version | |
| id: pkg | |
| run: | | |
| VERSION=$(python3 -c " | |
| import re, pathlib | |
| text = pathlib.Path('pyproject.toml').read_text() | |
| m = re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.M) | |
| print(m.group(1)) | |
| ") | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Check PyPI | |
| id: pypi | |
| env: | |
| VERSION: ${{ steps.pkg.outputs.version }} | |
| run: | | |
| python3 - <<'PY' | |
| import os | |
| import urllib.error | |
| import urllib.request | |
| version = os.environ["VERSION"] | |
| exists = False | |
| try: | |
| with urllib.request.urlopen(f"https://pypi.org/pypi/cptr/{version}/json", timeout=15): | |
| exists = True | |
| except urllib.error.HTTPError as exc: | |
| if exc.code != 404: | |
| raise | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output: | |
| output.write(f"publish_needed={'false' if exists else 'true'}\n") | |
| print(f"Version {version} {'already exists on PyPI' if exists else 'is not on PyPI'}") | |
| PY | |
| - name: Check GitHub release assets | |
| id: release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| VERSION: ${{ steps.pkg.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| expected=( | |
| "cptr-${VERSION}-py3-none-any.whl" | |
| "cptr-${VERSION}-linux-wheelhouse.tar.gz" | |
| "SHA256SUMS" | |
| ) | |
| assets="$(gh release view "v${VERSION}" --json assets --jq '.assets[].name' 2>/dev/null || true)" | |
| missing=false | |
| for name in "${expected[@]}"; do | |
| if ! grep -Fx "$name" <<< "$assets" >/dev/null; then | |
| missing=true | |
| echo "Missing release asset: $name" | |
| fi | |
| done | |
| echo "release_assets_needed=$missing" >> "$GITHUB_OUTPUT" | |
| build: | |
| needs: preflight | |
| if: github.ref == 'refs/heads/release' && (needs.preflight.outputs.publish_needed == 'true' || needs.preflight.outputs.release_assets_needed == 'true') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: cptr/frontend/package-lock.json | |
| - name: Build frontend | |
| working-directory: cptr/frontend | |
| run: | | |
| npm ci | |
| npm run build | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install build tools | |
| run: pip install hatchling build | |
| - name: Build package | |
| run: python -m build --wheel | |
| - name: Build Linux wheelhouse | |
| run: | | |
| VERSION="${{ needs.preflight.outputs.version }}" | |
| WHEEL="dist/cptr-${VERSION}-py3-none-any.whl" | |
| cp "$WHEEL" . | |
| mkdir -p wheelhouse | |
| python -m pip download --dest wheelhouse "${WHEEL}[all]" | |
| tar -czf "cptr-${VERSION}-linux-wheelhouse.tar.gz" -C wheelhouse . | |
| - name: Generate checksums | |
| run: | | |
| sha256sum cptr-*.whl cptr-*-linux-wheelhouse.tar.gz > SHA256SUMS | |
| - name: Upload dist artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Upload release artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-assets | |
| path: | | |
| cptr-*.whl | |
| cptr-*-linux-wheelhouse.tar.gz | |
| SHA256SUMS | |
| publish: | |
| needs: [preflight, build] | |
| if: github.ref == 'refs/heads/release' && needs.preflight.outputs.publish_needed == 'true' | |
| runs-on: ubuntu-latest | |
| environment: pypi | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Download dist artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Check if version already on PyPI | |
| id: check | |
| env: | |
| VERSION: ${{ needs.preflight.outputs.version }} | |
| run: | | |
| python3 - <<'PY' | |
| import os | |
| import urllib.error | |
| import urllib.request | |
| version = os.environ["VERSION"] | |
| exists = False | |
| try: | |
| with urllib.request.urlopen(f"https://pypi.org/pypi/cptr/{version}/json", timeout=15): | |
| exists = True | |
| except urllib.error.HTTPError as exc: | |
| if exc.code != 404: | |
| raise | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output: | |
| output.write(f"skip={'true' if exists else 'false'}\n") | |
| print(f"Version {version} {'already exists on PyPI, skipping publish' if exists else 'is not on PyPI'}") | |
| PY | |
| - name: Publish to PyPI | |
| if: steps.check.outputs.skip != 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| # No API token needed - uses OIDC trusted publishing. | |
| # Configure at: https://pypi.org/manage/project/cptr/settings/publishing/ | |
| github-release-assets: | |
| needs: [preflight, build] | |
| if: github.ref == 'refs/heads/release' && needs.preflight.outputs.release_assets_needed == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download release artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-assets | |
| path: release-assets/ | |
| - name: Attach GitHub release artifacts | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| VERSION: ${{ needs.preflight.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| ls -lah release-assets | |
| mapfile -t files < <(find release-assets -maxdepth 1 -type f -print | sort) | |
| if [ "${#files[@]}" -eq 0 ]; then | |
| echo "No release asset files found" >&2 | |
| exit 1 | |
| fi | |
| for attempt in {1..60}; do | |
| if gh release view "v${VERSION}" >/dev/null 2>&1; then | |
| gh release upload "v${VERSION}" "${files[@]}" --clobber | |
| assets="$(gh release view "v${VERSION}" --json assets --jq '.assets[].name')" | |
| for expected in \ | |
| "cptr-${VERSION}-py3-none-any.whl" \ | |
| "cptr-${VERSION}-linux-wheelhouse.tar.gz" \ | |
| "SHA256SUMS" | |
| do | |
| if ! grep -Fx "$expected" <<< "$assets" >/dev/null; then | |
| echo "Missing release asset after upload: $expected" >&2 | |
| exit 1 | |
| fi | |
| done | |
| exit 0 | |
| fi | |
| sleep 10 | |
| done | |
| echo "GitHub release v${VERSION} was not found" >&2 | |
| exit 1 |