diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..f3ab8538 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,156 @@ +name: Publish + +on: + push: + branches: + - main + +env: + PUB_CACHE: ~/.pub-cache + +jobs: + setup: + name: Setup + runs-on: ubuntu-22.04 + outputs: + flutter_version: ${{ steps.flutter_version.outputs.FLUTTER_VERSION }} + build_number: ${{ steps.build_number.outputs.BUILD_NUMBER }} + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set flutter version + id: flutter_version + run: echo "FLUTTER_VERSION=$(jq ".flutterSdkVersion" -r < .fvm/fvm_config.json | cut -d "@" -f 1)" >> $GITHUB_OUTPUT + - name: Set build number + id: build_number + run: echo "BUILD_NUMBER=$(date +"%s")" >> $GITHUB_OUTPUT + + android: + name: Android + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Checkout + uses: actions/checkout@v2 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ needs.setup.outputs.flutter_version }} + channel: 'stable' + cache: true + - name: Pub dependency cache + uses: actions/cache@v3 + with: + path: ${{ env.PUB_CACHE }} + key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }} + restore-keys: | + ${{ runner.os }}-pub- + - name: Gradle dependency cache + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'adopt' + java-version: 11 + + - name: Build + run: cd packages/neon && flutter build apk --split-per-abi --build-number="${{ needs.setup.outputs.build_number }}" + - uses: ilharp/sign-android-release@v1 + name: Sign + with: + releaseDir: packages/neon/build/app/outputs/flutter-apk + signingKey: ${{ secrets.SIGNING_KEY }} + keyAlias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + + - uses: actions/upload-artifact@v3 + with: + name: Android arm64-v8a + path: packages/neon/build/app/outputs/flutter-apk/app-arm64-v8a-release-signed.apk + if-no-files-found: error + - uses: actions/upload-artifact@v3 + with: + name: Android armeabi-v7a + path: packages/neon/build/app/outputs/flutter-apk/app-armeabi-v7a-release-signed.apk + if-no-files-found: error + - uses: actions/upload-artifact@v3 + with: + name: Android x86_64 + path: packages/neon/build/app/outputs/flutter-apk/app-x86_64-release-signed.apk + if-no-files-found: error + + linux_x86_64: + name: Linux x86_64 + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Checkout + uses: actions/checkout@v2 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ needs.setup.outputs.flutter_version }} + channel: 'stable' + cache: true + - name: Pub dependency cache + uses: actions/cache@v3 + with: + path: ${{ env.PUB_CACHE }} + key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }} + restore-keys: | + ${{ runner.os }}-pub- + - name: Install dependencies + run: | + sudo apt-get install \ + -y --no-install-recommends \ + clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev \ + libappindicator3-dev + + - name: Build + run: cd packages/neon && flutter build linux --build-number="${{ needs.setup.outputs.build_number }}" + + - uses: actions/upload-artifact@v3 + with: + name: Linux x86_64 + path: packages/neon/build/linux/x64/release/bundle/* + if-no-files-found: error + + linux_arm64: + name: Linux arm64 + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set docker image + id: docker_image + run: | + echo "local=nextcloud-neon-build-linux-arm64:${{ needs.setup.outputs.flutter_version }}" >> $GITHUB_OUTPUT + echo "remote=ghcr.io/$GITHUB_REPOSITORY/build-linux-arm64:${{ needs.setup.outputs.flutter_version }}" >> $GITHUB_OUTPUT + - run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: arm64 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + platforms: linux/arm64 + + - name: Build + env: + FLUTTER_VERSION: ${{ needs.setup.outputs.flutter_version }} + run: ./tool/build-neon.sh linux/arm64 --build-number="${{ needs.setup.outputs.build_number }}" + + - uses: actions/upload-artifact@v3 + with: + name: Linux arm64 + path: packages/neon/build/linux/arm64/release/bundle/* + if-no-files-found: error diff --git a/tool/build-neon.sh b/tool/build-neon.sh new file mode 100755 index 00000000..0f40fcbf --- /dev/null +++ b/tool/build-neon.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -euxo pipefail +cd "$(dirname "$0")/.." + +targets=("linux/arm64" "linux/amd64") + +target="$1" + +# shellcheck disable=SC2076 +if ! [[ ${targets[*]} =~ "$target" ]]; then + echo "Unknown target $target, must be one of ${targets[*]}" + exit 1 +fi + +if [ ! -v FLUTTER_VERSION ]; then + # shellcheck disable=SC2155 + export FLUTTER_VERSION="$(jq ".flutterSdkVersion" -r < .fvm/fvm_config.json | cut -d "@" -f 1)" +fi + +if [[ "$target" == "linux/arm64" ]] || [[ "$target" == "linux/amd64" ]]; then + os="$(echo "$target" | cut -d "/" -f 1)" + arch="$(echo "$target" | cut -d "/" -f 2)" + + build_args=() + if [ -v GITHUB_REPOSITORY ]; then + image="ghcr.io/$GITHUB_REPOSITORY/build-$os-$arch" + build_args+=( + "--push" + "--cache-from" "type=registry,ref=$image" + "--cache-to" "type=registry,ref=$image,mode=max" + ) + tag="$image:$FLUTTER_VERSION" + else + tag="nextcloud-neon-build-$os-$arch:$FLUTTER_VERSION" + fi + + # shellcheck disable=SC2086 + docker buildx build \ + --platform "$target" \ + --progress plain \ + --tag "$tag" \ + --build-arg="FLUTTER_VERSION=$FLUTTER_VERSION" \ + ${build_args[*]} \ + -f "tool/build/Dockerfile.$os" \ + ./tool/build + + paths=() + for path in packages/*; do + paths+=("$path/lib" "$path/pubspec.yaml") + done + run_args=() + for path in ${paths[*]} "packages/file_icons/fonts" "packages/neon/assets" "packages/neon/build" "packages/neon/linux"; do + run_args+=(-v "$(pwd)/$path:/src/$path") + done + mkdir -p "packages/neon/build" + + container_id="$( + # shellcheck disable=SC2086 + docker run \ + --platform "$target" \ + --rm -d \ + -e "ORIGINAL_USER=$(id -u)" \ + -e "ORIGINAL_GROUP=$(id -g)" \ + -e "BUILD_ARGS=${*:2}" \ + ${run_args[*]} \ + "$tag" + )" + + function cleanup() { + docker kill "$container_id" > /dev/null 2>&1 || true + } + trap cleanup EXIT + + docker logs -f "$container_id" +fi \ No newline at end of file diff --git a/tool/build/Dockerfile.linux b/tool/build/Dockerfile.linux new file mode 100644 index 00000000..a6996b8e --- /dev/null +++ b/tool/build/Dockerfile.linux @@ -0,0 +1,19 @@ +FROM debian:stable-slim + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + # dependencies to install flutter + git curl unzip ca-certificates \ + # dependencies to build for linux + clang cmake ninja-build pkg-config libgtk-3-dev \ + # dependencies for the app + libayatana-appindicator3-dev + +ARG FLUTTER_VERSION +RUN git clone -b $FLUTTER_VERSION https://github.com/flutter/flutter /flutter +ENV PATH=$PATH:/flutter/bin +RUN flutter doctor -v +RUN flutter precache --linux + +ADD linux.sh /build.sh +CMD /build.sh \ No newline at end of file diff --git a/tool/build/linux.sh b/tool/build/linux.sh new file mode 100755 index 00000000..13101b4f --- /dev/null +++ b/tool/build/linux.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -euxo pipefail + +if [ ! -f /.dockerenv ]; then + echo "This script needs to run in a specific docker container, use the build-neon.sh script" + exit 1 +fi + +function cleanup() { + chown -R "$ORIGINAL_USER:$ORIGINAL_GROUP" . +} +trap cleanup EXIT + +cd /src/packages/neon +# shellcheck disable=SC2086 +flutter build linux ${BUILD_ARGS[*]} \ No newline at end of file