diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 838590053d..a958e80a8b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -516,6 +516,62 @@ jobs: files: binaries/* tag_name: v${{ inputs.tag }} + docker-publish: + # This action doesn't need to wait on any other task, it's easy to re-tag if something failed and we're validating + # the tag here also + name: Push Docker image ghcr.io/astral-sh/ruff + runs-on: ubuntu-latest + environment: + name: release + permissions: + # For the docker push + packages: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.sha }} + + - uses: docker/setup-buildx-action@v3 + + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: ghcr.io/astral-sh/ruff + + - name: Check tag consistency + # Unlike validate-tag we don't check if the commit is on the main branch, but it seems good enough since we can + # change docker tags + if: ${{ inputs.tag }} + run: | + version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g') + if [ "${{ inputs.tag }}" != "${version}" ]; then + echo "The input tag does not match the version from pyproject.toml:" >&2 + echo "${{ inputs.tag }}" >&2 + echo "${version}" >&2 + exit 1 + else + echo "Releasing ${version}" + fi + + - name: "Build and push Docker image" + uses: docker/build-push-action@v3 + with: + context: . + platforms: linux/amd64,linux/arm64 + # Reuse the builder + cache-from: type=gha + cache-to: type=gha,mode=max + push: ${{ inputs.tag != '' }} + tags: ghcr.io/astral-sh/ruff:latest,ghcr.io/astral-sh/ruff:${{ inputs.tag || 'dry-run' }} + labels: ${{ steps.meta.outputs.labels }} + # After the release has been published, we update downstream repositories # This is separate because if this fails the release is still fine, we just need to do some manual workflow triggers update-dependents: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..a6c2b7a823 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +FROM --platform=$BUILDPLATFORM ubuntu as build +ENV HOME="/root" +WORKDIR $HOME + +RUN apt update && apt install -y build-essential curl python3-venv + +# Setup zig as cross compiling linker +RUN python3 -m venv $HOME/.venv +RUN .venv/bin/pip install cargo-zigbuild +ENV PATH="$HOME/.venv/bin:$PATH" + +# Install rust +ARG TARGETPLATFORM +RUN case "$TARGETPLATFORM" in \ + "linux/arm64") echo "aarch64-unknown-linux-musl" > rust_target.txt ;; \ + "linux/amd64") echo "x86_64-unknown-linux-musl" > rust_target.txt ;; \ + *) exit 1 ;; \ + esac +# TODO: --default-toolchain none and use rust-toolchain.toml instead +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --target $(cat rust_target.txt) --profile minimal +ENV PATH="$HOME/.cargo/bin:$PATH" + +# Build +COPY crates crates +COPY Cargo.toml Cargo.toml +COPY Cargo.lock Cargo.lock +RUN cargo zigbuild --bin ruff --target $(cat rust_target.txt) --release +RUN cp target/$(cat rust_target.txt)/release/ruff /ruff +# TODO: Optimize binary size, with a version that also works when cross compiling +# RUN strip --strip-all /ruff + +FROM scratch +COPY --from=build /ruff /ruff +WORKDIR /io +ENTRYPOINT ["/ruff"] diff --git a/docs/installation.md b/docs/installation.md index 6456ade624..919289d14b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -41,4 +41,12 @@ on the testing repositories: apk add ruff ``` +On **Docker**, it is published as `ghcr.io/astral-sh/ruff`, tagged for each release and `latest` for +the latest release. + +```shell +docker run -v .:/io --rm ghcr.io/astral-sh/ruff check . +docker run -v .:/io --rm ghcr.io/astral-sh/ruff:0.1.3 check . +``` + [![Packaging status](https://repology.org/badge/vertical-allrepos/ruff-python-linter.svg?exclude_unsupported=1)](https://repology.org/project/ruff-python-linter/versions)