├── .github ├── CODEOWNERS ├── dependabot.yml ├── release.yml ├── scripts │ └── release.sh └── workflows │ ├── bump-versions.yml │ ├── release.yml │ └── test.yml ├── LICENSE ├── README.md ├── action.yml ├── project.toml └── test ├── polarify └── recipe.yaml └── test-package └── recipe.yaml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @pavelzw 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | groups: 8 | dependencies: 9 | patterns: 10 | - "*" 11 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore for release 5 | categories: 6 | - title: 💥 Breaking changes 7 | labels: 8 | - breaking 9 | - title: ✨ New features 10 | labels: 11 | - enhancement 12 | - title: 👷🏻 CI 13 | labels: 14 | - ci 15 | - title: 🐛 Bug fixes 16 | labels: 17 | - bug 18 | - title: 📝 Documentation 19 | labels: 20 | - documentation 21 | - title: ⬆️ Dependency updates 22 | labels: 23 | - dependencies 24 | - title: 🤷🏻 Other changes 25 | labels: 26 | - "*" 27 | -------------------------------------------------------------------------------- /.github/scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | version="${TAG_NAME}" 4 | major="${version%%.*}" # see https://linuxjournal.com/article/8919 for an explanation of this bash magic 5 | 6 | git tag -d "${major}" 7 | local_delete=$? 8 | if [ $local_delete -eq 0 ]; then 9 | echo "Deleted local tag ${major}." 10 | echo "Deleted local tag \`${major}\`." >> "$GITHUB_STEP_SUMMARY" 11 | else 12 | echo "No local tag ${major} to delete." 13 | echo "No local tag \`${major}\` to delete." >> "$GITHUB_STEP_SUMMARY" 14 | fi 15 | git tag "${major}" 16 | 17 | git push -d origin "${major}" 18 | remote_delete=$? 19 | if [ $remote_delete -eq 0 ]; then 20 | echo "Deleted remote tag ${major}." 21 | echo "Deleted remote tag \`${major}\`." >> "$GITHUB_STEP_SUMMARY" 22 | else 23 | echo "No remote tag ${major} to delete." 24 | echo "No remote tag \`${major}\` to delete." >> "$GITHUB_STEP_SUMMARY" 25 | fi 26 | git push origin "${major}" 27 | push_worked=$? 28 | if [ $push_worked -ne 0 ]; then 29 | echo "Failed to push ${major} tag to remote." 30 | echo "Failed to push \`${major}\` tag to remote." >> "$GITHUB_STEP_SUMMARY" 31 | exit 1 32 | fi 33 | 34 | if [ $remote_delete -eq 0 ]; then 35 | echo "Result: moved ${major} -> ${version} tag on remote." 36 | echo "Result: moved \`${major}\` -> \`${version}\` tag on remote." >> "$GITHUB_STEP_SUMMARY" 37 | else 38 | echo "Result: created ${major} -> ${version} tag on remote." 39 | echo "Result: created \`${major}\` -> \`${version}\` tag on remote." >> "$GITHUB_STEP_SUMMARY" 40 | fi 41 | -------------------------------------------------------------------------------- /.github/workflows/bump-versions.yml: -------------------------------------------------------------------------------- 1 | name: Bump versions 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: 0 6 * * * 6 | 7 | jobs: 8 | bump: 9 | name: Bump ${{ matrix.tool }} 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | include: 14 | - tool: rattler-build 15 | repo: prefix-dev/rattler-build 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Bump versions 19 | id: bump 20 | run: | 21 | set -exuo pipefail 22 | new_version="$(gh repo view --json latestRelease ${{ matrix.repo }} | jq -r '.latestRelease.tagName')" 23 | echo "new-version=$new_version" >> "$GITHUB_OUTPUT" 24 | yq -i ".inputs.${{ matrix.tool }}-version.default = \"$new_version\"" action.yml 25 | env: 26 | GH_TOKEN: ${{ github.token }} 27 | - name: Create Pull Request 28 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e 29 | with: 30 | title: Bump ${{ matrix.tool }} to ${{ steps.bump.outputs.new-version }} 31 | delete-branch: true 32 | commit-message: Bump ${{ matrix.tool }} version to ${{ steps.bump.outputs.new-version }} 33 | branch: bump-${{ matrix.tool }}-${{ steps.bump.outputs.new-version }} 34 | labels: dependencies,enhancement 35 | body: | 36 | - [ ] Update version in [project.toml](https://github.com/prefix-dev/rattler-build-action/blob/bump-${{ matrix.tool }}-${{ steps.bump.outputs.new-version }}/project.toml) 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: main 6 | permissions: 7 | contents: write 8 | 9 | # To release a new version, update the version in `project.toml` and push to main. 10 | # This will create a draft release with the changelog and push a 'vx' tag that points to the new release as well as 'vx.y.z'. 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: quantco/ui-actions/version-metadata@v1 18 | id: version-metadata 19 | with: 20 | file: ./project.toml 21 | token: ${{ secrets.GITHUB_TOKEN }} 22 | version-extraction-override: 'regex:version = "(.*)"' 23 | - run: .github/scripts/release.sh 24 | if: steps.version-metadata.outputs.changed == 'true' 25 | env: 26 | TAG_NAME: v${{ steps.version-metadata.outputs.newVersion }} 27 | - name: Create release 28 | if: steps.version-metadata.outputs.changed == 'true' 29 | uses: softprops/action-gh-release@v2 30 | with: 31 | generate_release_notes: true 32 | tag_name: v${{ steps.version-metadata.outputs.newVersion }} 33 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | bump: 13 | name: Test action 14 | runs-on: ${{ matrix.os }} 15 | timeout-minutes: 10 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | recipe: 20 | - polarify 21 | - test-package 22 | os: 23 | - ubuntu-latest 24 | - macos-13 25 | - macos-latest 26 | - windows-latest 27 | - ubuntu-24.04-arm 28 | rattler-build-version: 29 | - '' # default 30 | - latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: ./ 34 | with: 35 | recipe-path: test/${{ matrix.recipe }}/recipe.yaml 36 | artifact-name: package-${{ matrix.recipe }}-${{ matrix.os }}-${{ matrix.rattler-build-version }} 37 | 38 | check-readme: 39 | name: Check versions in README.md 40 | runs-on: ubuntu-latest 41 | steps: 42 | - uses: actions/checkout@v4 43 | - name: Check rattler-build-action version mentions 44 | run: | 45 | project_version="$(yq '.version' project.toml)" 46 | count_expected=6 47 | count_actual="$(grep -c "prefix-dev/rattler-build-action@v${project_version}" README.md || true)" 48 | if [ "$count_actual" -ne "$count_expected" ]; then 49 | echo "::error file=README.md::Expected $count_expected mentions of \`rattler-build-action@v$project_version\` in README.md, but found $count_actual." 50 | exit 1 51 | fi 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Pavel Zwerschke 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | [![License][license-badge]][license] 4 | [![CI][test-badge]][test] 5 | [![Latest release][latest-release-badge]][releases] 6 | [![Project Chat][chat-badge]][chat-url] 7 | 8 | [license-badge]: https://img.shields.io/github/license/prefix-dev/rattler-build-action?style=flat-square 9 | [license]: ./LICENSE 10 | [test-badge]: https://img.shields.io/github/actions/workflow/status/prefix-dev/rattler-build-action/test.yml?style=flat-square 11 | [test]: https://github.com/prefix-dev/rattler-build-action/actions/ 12 | [latest-release-badge]: https://img.shields.io/github/v/tag/prefix-dev/rattler-build-action?style=flat-square&label=latest&sort=semver 13 | [releases]: https://github.com/prefix-dev/rattler-build-action/releases 14 | [chat-badge]: https://img.shields.io/discord/1082332781146800168.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2&style=flat-square 15 | [chat-url]: https://discord.gg/kKV8ZxyzY4 16 | 17 |

18 | 19 | # rattler-build-action 📦🐍 20 | 21 | `rattler-build-action` is a GitHub Action for building conda packages using [rattler-build](https://github.com/prefix-dev/rattler-build). 22 | 23 | ## Usage 24 | 25 | Create `.github/workflows/package.yml` in your repository. Here's a quick template: 26 | 27 | ```yml 28 | name: Package 29 | 30 | on: [push] 31 | 32 | jobs: 33 | build: 34 | name: Build package 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Build conda package 39 | uses: prefix-dev/rattler-build-action@v0.2.33 40 | ``` 41 | 42 | > [!WARNING] 43 | > Since rattler-build is still experimental and the API can change in minor versions, please pin this action to its minor version, i.e., `prefix-dev/rattler-build-action@v0.2.33`. 44 | 45 | > [!TIP] 46 | > You can use dependabot to automatically update the version of `rattler-build-action`. Add the following to your `.github/dependabot.yml`: 47 | > 48 | > ```yml 49 | > version: 2 50 | > updates: 51 | > - package-ecosystem: github-actions 52 | > directory: / 53 | > schedule: 54 | > interval: monthly 55 | > groups: 56 | > gh-actions: 57 | > patterns: 58 | > - "*" 59 | > ``` 60 | 61 | This action will build the conda recipe in `conda.recipe/recipe.yaml` and upload the built packages as a build artifact. 62 | 63 | ## Customizations 64 | 65 | - `rattler-build-version`: Define the version of rattler-build. Pins to the latest version that is available when releasing. 66 | - `recipe-path`: Path to the rattler recipe. Defaults to `conda.recipe/recipe.yaml`. 67 | - `upload-artifact`: Decide whether to upload the built packages as a build artifact. 68 | - `build-args`: Additional arguments to pass to `rattler-build build`. 69 | - `artifact-name`: Name of the artifact that is uploaded after build. If running `rattler-build-action` multiple times in a matrix, you need a distinct name for each workflow. 70 | 71 | ### `rattler-build-version` 72 | 73 | `rattler-build-version` is strictly pinned to the latest version of `rattler-build` that is available when releasing a new version of `rattler-build-action`. 74 | This is to ensure that no breakages occur if a new version of `rattler-build` is released. 75 | 76 | You can use dependabot to automatically update the version of `prefix-dev/rattler-build-action` which will also update the version of `rattler-build` to the latest version. 77 | 78 | ## Examples 79 | 80 | ### Build for multiple targets using matrix 81 | 82 | ```yml 83 | jobs: 84 | build: 85 | name: Build package 86 | runs-on: ${{ matrix.os }} 87 | strategy: 88 | matrix: 89 | include: 90 | - os: ubuntu-latest 91 | target-platform: linux-64 92 | - os: ubuntu-latest 93 | target-platform: linux-aarch64 94 | - os: windows-latest 95 | target-platform: win-64 96 | - os: macos-latest 97 | target-platform: osx-64 98 | - os: macos-14 99 | target-platform: osx-arm64 100 | steps: 101 | - uses: actions/checkout@v4 102 | - name: Build conda package 103 | uses: prefix-dev/rattler-build-action@v0.2.33 104 | with: 105 | # needs to be unique for each matrix entry 106 | artifact-name: package-${{ matrix.target-platform }} 107 | build-args: --target-platform ${{ matrix.target-platform }}${{ matrix.target-platform == 'linux-aarch64' && ' --no-test' || '' }} 108 | ``` 109 | 110 | ### Upload to quetz 111 | 112 | ```yml 113 | jobs: 114 | build: 115 | name: Build package 116 | runs-on: ubuntu-latest 117 | steps: 118 | - uses: actions/checkout@v4 119 | - name: Build conda package 120 | uses: prefix-dev/rattler-build-action@v0.2.33 121 | - run: | 122 | for pkg in $(find output -type f \( -name "*.conda" -o -name "*.tar.bz2" \) ); do 123 | echo "Uploading ${pkg}" 124 | rattler-build upload quetz "${pkg}" 125 | done 126 | env: 127 | QUETZ_SERVER_URL: https://my.quetz.server 128 | QUETZ_API_KEY: ${{ secrets.QUETZ_API_KEY }} 129 | QUETZ_CHANNEL: my-channel 130 | ``` 131 | 132 | ### Upload to prefix.dev via OIDC from GitHub Actions 133 | 134 | This requires you to configure the workflow as a trusted publisher for your target channel (see [Trusted Publishing to Conda Channels](https://prefix.dev/blog/trusted_publishing_to_conda_channels)). 135 | 136 | ```yml 137 | jobs: 138 | build: 139 | name: Build package 140 | runs-on: ubuntu-latest 141 | 142 | permissions: 143 | id-token: write 144 | contents: read 145 | 146 | steps: 147 | - uses: actions/checkout@v4 148 | - name: Build conda package 149 | uses: prefix-dev/rattler-build-action@v0.2.33 150 | - run: | 151 | for pkg in $(find output -type f \( -name "*.conda" -o -name "*.tar.bz2" \) ); do 152 | echo "Uploading ${pkg}" 153 | rattler-build upload prefix -c my-channel "${pkg}" 154 | done 155 | ``` 156 | 157 | ### Use private channel 158 | 159 | You can use a private channel while building your conda package by setting the `RATTLER_AUTH_FILE` environment variable. 160 | As of now, `rattler-build` does not support a `login` command [prefix-dev/rattler-build#334](https://github.com/prefix-dev/rattler-build/issues/334), so you need to create the `RATTLER_AUTH_FILE` manually. 161 | 162 | ```yml 163 | jobs: 164 | build: 165 | name: Build package 166 | runs-on: ubuntu-latest 167 | steps: 168 | - uses: actions/checkout@v4 169 | - name: Authenticate with private channel 170 | run: | 171 | RATTLER_AUTH_FILE=${{ runner.temp }}/credentials.json 172 | echo '{"my.quetz.server": {"CondaToken": "${{ secrets.QUETZ_API_KEY }}"}}' > "$RATTLER_AUTH_FILE" 173 | echo "RATTLER_AUTH_FILE=$RATTLER_AUTH_FILE" >> "$GITHUB_ENV" 174 | - name: Build conda package 175 | uses: prefix-dev/rattler-build-action@v0.2.33 176 | with: 177 | build-args: -c conda-forge -c https://my.quetz.server/get/my-channel 178 | ``` 179 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: rattler-build-action 2 | description: GitHub action to build conda packages using rattler-build 3 | author: Pavel Zwerschke 4 | branding: 5 | icon: package 6 | color: yellow 7 | inputs: 8 | rattler-build-version: 9 | description: Version of rattler-build to use 10 | required: false 11 | default: 'v0.39.0' 12 | recipe-path: 13 | description: Path to the recipe.yaml file 14 | required: true 15 | default: conda.recipe/recipe.yaml 16 | upload-artifact: 17 | description: whether to upload the built packages as a build artifact 18 | required: false 19 | default: 'true' 20 | artifact-name: 21 | description: Package name of the uploaded artifact 22 | required: false 23 | default: 'package' 24 | build-args: 25 | description: arguments to pass to rattler-build 26 | required: false 27 | default: '' 28 | runs: 29 | using: composite 30 | steps: 31 | - name: Generate rattler-build URL 32 | shell: bash 33 | id: url 34 | run: | 35 | arch=$(uname -m) 36 | if [ "$arch" = "arm64" ]; then 37 | arch="aarch64" 38 | fi 39 | platform=${{ runner.os == 'macOS' && 'apple-darwin' || '' }}${{ runner.os == 'Linux' && 'unknown-linux-musl' || '' }}${{ runner.os == 'Windows' && 'pc-windows-msvc' || '' }} 40 | if [ ${{ inputs.rattler-build-version }} = "latest" ]; then 41 | url="https://github.com/prefix-dev/rattler-build/releases/latest/download/rattler-build-$arch-$platform${{ runner.os == 'Windows' && '.exe' || '' }}" 42 | else 43 | url="https://github.com/prefix-dev/rattler-build/releases/download/${{ inputs.rattler-build-version }}/rattler-build-$arch-$platform${{ runner.os == 'Windows' && '.exe' || '' }}" 44 | fi 45 | echo "url=$url" >> $GITHUB_OUTPUT 46 | - name: Install rattler-build (Unix) 47 | shell: bash 48 | if: ${{ runner.os != 'Windows' }} 49 | run: | 50 | mkdir -p ${{ runner.temp }}/rattler-build 51 | curl -Ls \ 52 | ${{ steps.url.outputs.url }} \ 53 | -o ${{ runner.temp }}/rattler-build/rattler-build 54 | chmod +x ${{ runner.temp }}/rattler-build/rattler-build 55 | echo ${{ runner.temp }}/rattler-build >> $GITHUB_PATH 56 | - name: Install rattler-build (Windows) 57 | shell: powershell 58 | if: ${{ runner.os == 'Windows' }} 59 | run: | 60 | New-Item -ItemType Directory -Path "${{ runner.temp }}\rattler-build" -Force 61 | Invoke-WebRequest -Uri "${{ steps.url.outputs.url }}" -OutFile "${{ runner.temp }}\rattler-build\rattler-build.exe" 62 | Add-Content -Path $env:GITHUB_PATH -Value "${{ runner.temp }}\rattler-build" 63 | - name: Build conda package (non-Windows) 64 | shell: bash 65 | if: ${{ runner.os != 'Windows' }} 66 | run: | 67 | rattler-build build --recipe "${{ inputs.recipe-path }}" ${{ inputs.build-args }} 68 | env: 69 | RATTLER_BUILD_ENABLE_GITHUB_INTEGRATION: 'true' 70 | RATTLER_BUILD_COLOR: 'always' 71 | - name: Build conda package (Windows) 72 | shell: powershell 73 | if: ${{ runner.os == 'Windows' }} 74 | run: | 75 | rattler-build build --recipe "${{ inputs.recipe-path }}" ${{ inputs.build-args }} 76 | env: 77 | RATTLER_BUILD_ENABLE_GITHUB_INTEGRATION: 'true' 78 | RATTLER_BUILD_COLOR: 'always' 79 | - name: Upload build artifacts 80 | uses: actions/upload-artifact@v4 81 | if: ${{ inputs.upload-artifact == 'true' }} 82 | with: 83 | name: ${{ inputs.artifact-name }} 84 | path: | 85 | output/**/*.tar.bz2 86 | output/**/*.conda 87 | -------------------------------------------------------------------------------- /project.toml: -------------------------------------------------------------------------------- 1 | version = "0.2.33" 2 | -------------------------------------------------------------------------------- /test/polarify/recipe.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/prefix-dev/recipe-format/main/schema.json 2 | context: 3 | name: polarify 4 | version: 0.1.3 5 | 6 | source: 7 | - url: https://github.com/quantco/polarify/archive/refs/tags/v${{ version }}.tar.gz 8 | sha256: 93441164c23b764d72c8a66d14b11d5bbd353ed6112ccf3b35efda2a98f9df02 9 | 10 | outputs: 11 | - package: 12 | name: ${{ name }} 13 | version: ${{ version }} 14 | build: 15 | noarch: python 16 | script: 17 | - python -m pip install . --no-deps --ignore-installed -vv --no-build-isolation --disable-pip-version-check 18 | requirements: 19 | host: 20 | - python >=3.9 21 | - pip 22 | - hatchling 23 | run: 24 | - python >=3.9 25 | - polars >=0.14.24,<0.20 26 | tests: 27 | - python: 28 | imports: 29 | - polarify 30 | pip_check: true 31 | 32 | about: 33 | homepage: https://github.com/quantco/polarify 34 | license: BSD-3-Clause 35 | -------------------------------------------------------------------------------- /test/test-package/recipe.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/prefix-dev/recipe-format/main/schema.json 2 | 3 | context: 4 | name: test-package 5 | version: 0.1.0 6 | 7 | outputs: 8 | - package: 9 | name: ${{ name }} 10 | version: ${{ version }} 11 | build: 12 | noarch: python 13 | script: 14 | - echo "Hello, world!" 15 | requirements: 16 | host: 17 | - python >=3.9 18 | run: 19 | - python >=3.9 20 | --------------------------------------------------------------------------------