Bump conda-forge feedstock #31
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: Bump conda-forge feedstock | |
| on: | |
| workflow_dispatch: {} | |
| # auto-run when the PyPI publish workflow completes | |
| workflow_run: | |
| workflows: ["Upload BiaPy to PyPI"] # must match the other workflow's name | |
| types: [completed] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| env: | |
| PACKAGE_NAME: biapy | |
| GH_TOKEN: ${{ secrets.CF_GH_TOKEN }} | |
| FEEDSTOCK_FORK: ${{ secrets.CF_FEEDSTOCK_FORK }} | |
| # avoid overlapping bumps for the same workflow run | |
| concurrency: | |
| group: cf-bump-${{ github.workflow }}-${{ github.run_id }} | |
| cancel-in-progress: false | |
| jobs: | |
| bump-feedstock: | |
| if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out this repo | |
| uses: actions/checkout@v4 | |
| - name: Determine version from release tag (fallback to PyPI latest on manual run) | |
| id: ver | |
| shell: bash | |
| run: | | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| RAW_TAG="${{ github.event.release.tag_name }}" | |
| VERSION="${RAW_TAG#v}" | |
| else | |
| VERSION="$(python -c "import json,urllib.request;print(json.load(urllib.request.urlopen('https://pypi.org/pypi/${{ env.PACKAGE_NAME }}/json'))['info']['version'])")" | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Fetch PyPI sdist URL and SHA256 (with short retry to avoid race) | |
| id: sdist | |
| shell: bash | |
| env: | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| run: | | |
| PYPI_JSON="https://pypi.org/pypi/${PACKAGE_NAME}/${VERSION}/json" | |
| OUT=$(python -c "import json,urllib.request,hashlib,os; d=json.load(urllib.request.urlopen('${PYPI_JSON}')); sd=[u for u in d['urls'] if u.get('packagetype')=='sdist']; u=sd[0]['url'] if sd else (_ for _ in ()).throw(SystemExit(1)); h=hashlib.sha256(urllib.request.urlopen(u).read()).hexdigest(); print(u); print(h)") | |
| SDIST_URL="$(echo "$OUT" | sed -n '1p')" | |
| SDIST_SHA256="$(echo "$OUT" | sed -n '2p')" | |
| { | |
| echo "sdist_url=$SDIST_URL" | |
| echo "sha256=$SDIST_SHA256" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Set up conda (Miniforge) | |
| uses: conda-incubator/setup-miniconda@v3 | |
| with: | |
| miniforge-version: latest | |
| use-mamba: true | |
| auto-activate-base: true | |
| channels: conda-forge | |
| - name: Create env for conda-smithy | |
| run: mamba create -n cf -y conda-smithy ruamel.yaml | |
| - name: Authenticate gh CLI | |
| run: gh auth status | |
| - name: Clone your feedstock fork (track upstream/main) | |
| run: | | |
| test -n "$FEEDSTOCK_FORK" | |
| gh repo clone "$FEEDSTOCK_FORK" feedstock | |
| cd feedstock | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git remote remove upstream 2>/dev/null || true | |
| git remote add upstream https://github.com/conda-forge/${{ env.PACKAGE_NAME }}-feedstock.git | |
| git fetch upstream main | |
| git checkout main | |
| git reset --hard upstream/main | |
| - name: Copy your meta.yaml into the feedstock | |
| working-directory: feedstock | |
| run: | | |
| cp ../biapy/utils/env/conda_forge_meta.yaml recipe/meta.yaml | |
| git add recipe/meta.yaml | |
| git commit -m "Import project's conda_forge_meta.yaml as recipe/meta.yaml" | |
| - name: Create bump branch and update version + sha256 (robust) | |
| working-directory: feedstock | |
| env: | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| SDIST_SHA256: ${{ steps.sdist.outputs.sha256 }} | |
| shell: bash | |
| run: | | |
| BRANCH="bump-v$VERSION-${GITHUB_RUN_ID}" | |
| git checkout -B "$BRANCH" | |
| python - <<'PY' | |
| import os, re, pathlib | |
| p = pathlib.Path("recipe") / "meta.yaml" | |
| s = p.read_text(encoding="utf-8") | |
| ver = os.environ["VERSION"] | |
| sha = os.environ["SDIST_SHA256"] | |
| s, n1 = re.subn(r'{%\s*set\s+version\s*=\s*"[^"]+"\s*%}', | |
| '{% set version = "' + ver + '" %}', s) | |
| if re.search(r'(?m)^\s*sha256\s*:\s*[0-9A-Fa-f]+', s): | |
| s, n2 = re.subn(r'(?m)^(?P<indent>\s*sha256\s*:\s*)([0-9A-Fa-f]+)\s*$', | |
| r'\g<indent>' + sha, s) | |
| else: | |
| m = re.search(r'(?ms)^(?P<indent>\s*)source:\s*\n(?P<body>(?:^\s+.*\n)+)', s) | |
| if not m: | |
| raise SystemExit("Could not locate 'source:' block in recipe/meta.yaml") | |
| body = m.group('body') | |
| mu = re.search(r'(?m)^(?P<uindent>\s*)url\s*:\s*\S+\s*$', body) | |
| if not mu: | |
| raise SystemExit("Could not locate 'url:' line in source block") | |
| uindent = mu.group('uindent') | |
| def _ins_sha(murl): | |
| line = murl.group(0) | |
| return line + "\n" + f"{uindent}sha256: {sha}" | |
| body2, nurl = re.subn(r'(?m)^(%surl\s*:\s*\S+\s*)$' % re.escape(uindent), _ins_sha, body, count=1) | |
| s = s[:m.start('body')] + body2 + s[m.end('body'):] | |
| p.write_text(s, encoding="utf-8") | |
| PY | |
| git add recipe/meta.yaml | |
| git commit -m "Bump to v$VERSION (update version and sha256)" | |
| - name: Validate recipe YAML has sha256 under source | |
| working-directory: feedstock | |
| run: | | |
| conda run -n cf python - <<'PY' | |
| import sys | |
| from ruamel.yaml import YAML | |
| from pathlib import Path | |
| yaml = YAML(typ="safe") | |
| data = yaml.load(Path("recipe/meta.yaml").read_text()) | |
| src = data.get("source", {}) | |
| if isinstance(src, dict): | |
| ok = "sha256" in src | |
| elif isinstance(src, list) and src and isinstance(src[0], dict): | |
| ok = "sha256" in src[0] | |
| else: | |
| ok = False | |
| if not ok: | |
| print("ERROR: recipe/meta.yaml 'source' lacks 'sha256:'", file=sys.stderr) | |
| sys.exit(1) | |
| print("OK: sha256 present in source") | |
| PY | |
| - name: (Optional) conda-smithy rerender | |
| working-directory: feedstock | |
| run: | | |
| conda run -n cf conda-smithy rerender -c auto || true | |
| if ! git diff --quiet; then | |
| git add . | |
| git commit -m "conda-smithy rerender" | |
| fi | |
| - name: Configure git auth for push | |
| working-directory: feedstock | |
| run: | | |
| gh auth setup-git | |
| git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${FEEDSTOCK_FORK}.git" | |
| - name: Push branch to your fork | |
| working-directory: feedstock | |
| env: | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| run: | | |
| BRANCH="bump-v$VERSION-${GITHUB_RUN_ID}" | |
| git push --force --set-upstream origin "$BRANCH" | |
| - name: Open PR to conda-forge feedstock | |
| working-directory: feedstock | |
| env: | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| FORK: ${{ env.FEEDSTOCK_FORK }} | |
| run: | | |
| BRANCH="bump-v$VERSION-${GITHUB_RUN_ID}" | |
| TITLE="biapy v$VERSION" | |
| BODY="Automated bump to $VERSION after GitHub Release. Recipe copied from project: \`biapy/utils/env/conda_forge_meta.yaml\`. Version and sha256 updated from PyPI sdist." | |
| OWNER="${FORK%%/*}" | |
| gh pr create \ | |
| --repo conda-forge/biapy-feedstock \ | |
| --title "$TITLE" \ | |
| --body "$BODY" \ | |
| --head "${OWNER}:${BRANCH}" \ | |
| --base "main" | |
| - name: Enable auto-merge on PR | |
| working-directory: feedstock | |
| env: | |
| GH_TOKEN: ${{ secrets.CF_GH_TOKEN }} | |
| run: | | |
| # Get the last PR number created by this workflow run | |
| PR_NUMBER=$(gh pr list \ | |
| --repo conda-forge/${PACKAGE_NAME}-feedstock \ | |
| --head "$(echo $FEEDSTOCK_FORK | cut -d/ -f1):bump-v${{ steps.ver.outputs.version }}-${GITHUB_RUN_ID}" \ | |
| --json number --jq '.[0].number') | |
| echo "Enabling auto-merge for PR #$PR_NUMBER" | |
| gh pr merge "$PR_NUMBER" \ | |
| --repo conda-forge/${PACKAGE_NAME}-feedstock \ | |
| --auto --merge |