diff --git a/.dockerignore b/.dockerignore index 4f34bcf92..1acad6d4e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,3 +3,4 @@ !Source !Tests !Package.* +!tools/build-linux-release.sh diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 19cdec68e..e817b3039 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,9 +1,15 @@ -name: Docker Build +name: Docker on: + schedule: + - cron: '0 3 * * 3' # Every Wednesday at 03:00 UTC push: branches: - main + paths: + - '.github/workflows/docker.yml' + - 'Dockerfile' + - 'tools/build-linux-release.sh' release: types: published workflow_call: @@ -16,6 +22,11 @@ on: description: 'Docker tag' required: true type: string + pull_request: + paths: + - '.github/workflows/docker.yml' + - 'Dockerfile' + - 'tools/build-linux-release.sh' permissions: contents: read @@ -23,11 +34,11 @@ permissions: jobs: build: - name: Build Docker Image - runs-on: ubuntu-24.04 + name: Build Images + runs-on: ubuntu-24.04-arm steps: - name: Define variables on push to `main` - if: github.event_name == 'push' + if: github.event_name == 'schedule' || github.event_name == 'push' run: | { echo "CHECKOUT_REF=main" @@ -42,8 +53,16 @@ jobs: echo "DOCKER_TAG=${{ github.event.release.tag_name }}" echo "OUTPUT_TYPE=type=registry" } >> "$GITHUB_ENV" + - name: Define variables on pull request + if: github.event_name == 'pull_request' + run: | + { + echo "CHECKOUT_REF=pr" + echo "DOCKER_TAG=pr-${{ github.event.pull_request.number }}" + echo "OUTPUT_TYPE=type=local,dest=artifacts" + } >> "$GITHUB_ENV" - name: Define variables on workflow call - if: github.event_name != 'push' && github.event_name != 'release' + if: env.DOCKER_TAG == null run: | { echo "CHECKOUT_REF=${{ inputs.ref }}" @@ -51,12 +70,19 @@ jobs: echo "OUTPUT_TYPE=type=local,dest=artifacts" } >> "$GITHUB_ENV" - uses: actions/checkout@v4 + if: env.CHECKOUT_REF == 'pr' + - uses: actions/checkout@v4 + if: env.CHECKOUT_REF != 'pr' with: ref: ${{ env.CHECKOUT_REF }} - name: Set lowercase repository name run: echo "REPOSITORY_LC=${REPOSITORY,,}" >> "$GITHUB_ENV" env: REPOSITORY: ${{ github.repository }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: amd64 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub registry @@ -69,16 +95,16 @@ jobs: with: context: . tags: ghcr.io/${{ env.REPOSITORY_LC }}:${{ env.DOCKER_TAG }} - platforms: linux/amd64 + platforms: linux/amd64, linux/arm64 outputs: ${{ env.OUTPUT_TYPE }} - - name: Rename binary artifact + - name: Move binary artifacts if: contains(env.OUTPUT_TYPE, 'local') - run: mv artifacts/usr/bin/swiftlint artifacts/usr/bin/swiftlint_linux_amd64 - - name: Upload binary artifact + run: mv artifacts/linux_*/usr/bin/swiftlint_linux_* . + - name: Upload binary artifacts if: contains(env.OUTPUT_TYPE, 'local') uses: actions/upload-artifact@v4 with: - name: swiftlint_linux_amd64 - path: artifacts/usr/bin/swiftlint_linux_amd64 + name: swiftlint_linux + path: swiftlint_linux_* if-no-files-found: error retention-days: 2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06cd5b851..d58603378 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -148,12 +148,12 @@ jobs: - name: Download binary artifact for Linux uses: actions/download-artifact@v4 with: - name: swiftlint_linux_amd64 + name: swiftlint_linux path: ${{ env.LINUX_BUILD_DIR }} - name: Move Bazel release run: mv -f ${{ env.MACOS_BUILD_DIR }}/bazel.tar.gz ${{ env.MACOS_BUILD_DIR }}/bazel.tar.gz.sha256 . - name: Make binaries executable - run: chmod +x ${{ env.MACOS_BUILD_DIR }}/swiftlint ${{ env.LINUX_BUILD_DIR }}/swiftlint_linux_amd64 + run: chmod +x ${{ env.MACOS_BUILD_DIR }}/swiftlint ${{ env.LINUX_BUILD_DIR }}/swiftlint_linux_* - name: Create artifacts run: | make --debug spm_artifactbundle diff --git a/CHANGELOG.md b/CHANGELOG.md index c1043ac6c..bb68c752a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,12 @@ `redundant_optional_initialization` rule by default. `redundant_optional_initialization` is now an alias for `implicit_optional_initialization`. [leo-lem](https://github.com/leo-lem) - [#1940](https://github.com/realm/SwiftLint/issues/1940) + [#1940](https://github.com/realm/SwiftLint/issues/1940) + +* The `x86_64`/`amd64` binary in the `swiftlint_linux.zip` release archive has been renamed to + `swiftlint_amd64` from just `swiftlint` to avoid confusion with the new `swiftlint_arm64` binary. + [Bradley Mackey](https://github.com/bradleymackey) + [SimplyDanny](https://github.com/SimplyDanny) ### Experimental @@ -30,6 +35,14 @@ ### Enhancements +* Support for ARM64 Linux binaries has been added. The `swiftlint_linux.zip` release archive + now contains both `swiftlint_amd64` and `swiftlint_arm64` binaries. The `swiftlint_amd64` + binary was formerly named `swiftlint`. `SwiftLintBinary.artifactbundle.zip` now also provides + the new binary, making the [binary plugins](https://github.com/SimplyDanny/SwiftLintPlugins) + work on ARM64 Linux as well. + [Bradley Mackey](https://github.com/bradleymackey) + [SimplyDanny](https://github.com/SimplyDanny) + * Add `include_variables` configuration option to `non_optional_string_data_conversion` rule. When enabled, the rule will trigger on variables, properties, and function calls in addition to string literals. Defaults to `false` for backward compatibility. diff --git a/Dockerfile b/Dockerfile index d4b0c2f92..2b5a13b39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,27 @@ -# Explicitly specify `noble` to keep the Swift & Ubuntu images in sync. -ARG BUILDER_IMAGE=swift:6.0-noble -ARG RUNTIME_IMAGE=ubuntu:noble +# syntax=docker/dockerfile:1 + +# Base image and static SDK have to be updated together. +ARG SWIFT_VERSION=6.0.3 +ARG UBUNTU_VERSION=noble # Builder image -FROM ${BUILDER_IMAGE} AS builder -RUN apt-get update && apt-get install -y \ - libcurl4-openssl-dev \ - libxml2-dev \ - && rm -r /var/lib/apt/lists/* -WORKDIR /workdir/ +FROM swift:${SWIFT_VERSION}-${UBUNTU_VERSION} AS builder +WORKDIR /workspace COPY Plugins Plugins/ COPY Source Source/ COPY Tests Tests/ COPY Package.* ./ - -RUN swift package update -ARG SWIFT_FLAGS="-c release -Xswiftc -static-stdlib -Xlinker -l_CFURLSessionInterface -Xlinker -l_CFXMLInterface -Xlinker -lcurl -Xlinker -lxml2 -Xswiftc -I. -Xlinker -fuse-ld=lld -Xlinker -L/usr/lib/swift/linux" -RUN swift build $SWIFT_FLAGS --product swiftlint -RUN mv `swift build $SWIFT_FLAGS --show-bin-path`/swiftlint /usr/bin -RUN strip /usr/bin/swiftlint +COPY tools/build-linux-release.sh tools/ +ARG TARGETPLATFORM +RUN --mount=type=cache,target=/workspace/.build,id=build-$TARGETPLATFORM ./tools/build-linux-release.sh # Runtime image -FROM ${RUNTIME_IMAGE} +FROM ubuntu:${UBUNTU_VERSION} AS runtime LABEL org.opencontainers.image.source=https://github.com/realm/SwiftLint -RUN apt-get update && apt-get install -y \ - libcurl4 \ - libxml2 \ - && rm -r /var/lib/apt/lists/* +RUN apt-get update +RUN apt-get install -y libcurl4-openssl-dev libxml2-dev +RUN rm -r /var/lib/apt/lists/* + COPY --from=builder /usr/lib/libsourcekitdInProc.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftBasicFormat.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftCompilerPluginMessageHandling.so /usr/lib @@ -56,9 +51,12 @@ COPY --from=builder /usr/lib/swift/linux/libswiftDispatch.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswiftGlibc.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswiftSynchronization.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswiftSwiftOnoneSupport.so /usr/lib -COPY --from=builder /usr/bin/swiftlint /usr/bin +COPY --from=builder /workspace/swiftlint_linux_* /usr/bin + +RUN ln -s /usr/bin/swiftlint_linux_* /usr/bin/swiftlint RUN swiftlint version RUN echo "_ = 0" | swiftlint --use-stdin -CMD ["swiftlint"] +ENTRYPOINT [ "/usr/bin/swiftlint" ] +CMD ["."] diff --git a/Makefile b/Makefile index d96690f97..03b4b5a0d 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ SWIFTLINT_EXECUTABLE_PARENT=.build/universal SWIFTLINT_EXECUTABLE=$(SWIFTLINT_EXECUTABLE_PARENT)/swiftlint SWIFTLINT_EXECUTABLE_LINUX_PARENT=.build/linux SWIFTLINT_EXECUTABLE_LINUX_AMD64=$(SWIFTLINT_EXECUTABLE_LINUX_PARENT)/swiftlint_linux_amd64 +SWIFTLINT_EXECUTABLE_LINUX_ARM64=$(SWIFTLINT_EXECUTABLE_LINUX_PARENT)/swiftlint_linux_arm64 ARTIFACT_BUNDLE_PATH=$(TEMPORARY_FOLDER)/SwiftLintBinary.artifactbundle @@ -87,6 +88,11 @@ $(SWIFTLINT_EXECUTABLE_LINUX_AMD64): docker run --platform linux/amd64 "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" chmod +x "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" +$(SWIFTLINT_EXECUTABLE_LINUX_ARM64): + mkdir -p "$(SWIFTLINT_EXECUTABLE_LINUX_PARENT)" + docker run --platform linux/arm64 "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(SWIFTLINT_EXECUTABLE_LINUX_ARM64)" + chmod +x "$(SWIFTLINT_EXECUTABLE_LINUX_ARM64)" + build_with_disable_sandbox: swift build --disable-sandbox $(SWIFT_BUILD_FLAGS) @@ -102,9 +108,10 @@ installables: $(SWIFTLINT_EXECUTABLE) install -d "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" install "$(SWIFTLINT_EXECUTABLE)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" -installables_linux: $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) +installables_linux: $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) $(SWIFTLINT_EXECUTABLE_LINUX_ARM64) install -d "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" install "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" + install "$(SWIFTLINT_EXECUTABLE_LINUX_ARM64)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" prefix_install: build_with_disable_sandbox install -d "$(PREFIX)/bin/" @@ -115,26 +122,22 @@ portable_zip: installables cp -f "$(LICENSE_PATH)" "$(TEMPORARY_FOLDER)" (cd "$(TEMPORARY_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./portable_swiftlint.zip" -spm_artifactbundle: $(SWIFTLINT_EXECUTABLE) $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) +spm_artifactbundle: $(SWIFTLINT_EXECUTABLE) $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) $(SWIFTLINT_EXECUTABLE_LINUX_ARM64) mkdir -p "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin" mkdir -p "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-linux-gnu/bin" sed 's/__VERSION__/$(VERSION_STRING)/g' tools/info.json.template > "$(ARTIFACT_BUNDLE_PATH)/info.json" cp -f "$(SWIFTLINT_EXECUTABLE)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin/swiftlint" - cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-linux-gnu/bin/swiftlint" + cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-linux-gnu/bin/swiftlint_amd64" + cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_ARM64)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-linux-gnu/bin/swiftlint_arm64" cp -f "$(LICENSE_PATH)" "$(ARTIFACT_BUNDLE_PATH)" (cd "$(TEMPORARY_FOLDER)"; zip -yr - "SwiftLintBinary.artifactbundle") > "./SwiftLintBinary.artifactbundle.zip" -zip_linux: docker_image $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) +zip_linux_release: $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) $(SWIFTLINT_EXECUTABLE_LINUX_ARM64) $(eval TMP_FOLDER := $(shell mktemp -d)) - cp -f $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) "$(TMP_FOLDER)/swiftlint" + cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(TMP_FOLDER)/swiftlint_amd64" + cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_ARM64)" "$(TMP_FOLDER)/swiftlint_arm64" cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)" - (cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip" - -zip_linux_release: $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) - $(eval TMP_FOLDER := $(shell mktemp -d)) - cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(TMP_FOLDER)/swiftlint" - cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)" - (cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip" + (cd "$(TMP_FOLDER)"; zip -yr - "swiftlint_amd64" "swiftlint_arm64" "LICENSE") > "./swiftlint_linux.zip" package: $(SWIFTLINT_EXECUTABLE) $(eval PACKAGE_ROOT := $(shell mktemp -d)) diff --git a/tools/build-linux-release.sh b/tools/build-linux-release.sh new file mode 100755 index 000000000..e27d95946 --- /dev/null +++ b/tools/build-linux-release.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -eo pipefail + +pushd "$(dirname "${BASH_SOURCE[0]}")/.." > /dev/null + +if [[ "$TARGETPLATFORM" = "linux/amd64" ]]; then + ARCH="x86_64" + STRIP_CMD="strip" +elif [[ "$TARGETPLATFORM" = "linux/arm64" ]]; then + ARCH="aarch64" + STRIP_CMD="strip" +else + echo "Unsupported target platform: $TARGETPLATFORM" + exit 1 +fi + +BUILD_ARGS=( + --product swiftlint + --configuration release + -Xswiftc -I. + -Xswiftc -static-stdlib + -Xlinker -l_CFURLSessionInterface + -Xlinker -l_CFXMLInterface + -Xlinker -lcurl + -Xlinker -lxml2 + -Xlinker -fuse-ld=lld + -Xlinker -L/usr/lib/swift/linux +) + +swift build "${BUILD_ARGS[@]}" +mv ".build/release/swiftlint" "swiftlint_linux_${ARCH}" +${STRIP_CMD} "swiftlint_linux_${ARCH}" diff --git a/tools/info.json.template b/tools/info.json.template index 0829f935d..0b0590aca 100644 --- a/tools/info.json.template +++ b/tools/info.json.template @@ -10,8 +10,12 @@ "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] }, { - "path": "swiftlint-__VERSION__-linux-gnu/bin/swiftlint", + "path": "swiftlint-__VERSION__-linux-gnu/bin/swiftlint_amd64", "supportedTriples": ["x86_64-unknown-linux-gnu"] + }, + { + "path": "swiftlint-__VERSION__-linux-gnu/bin/swiftlint_arm64", + "supportedTriples": ["aarch64-unknown-linux-gnu", "arm64-unknown-linux-gnu"] } ] }