diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile new file mode 100644 index 00000000..eb6f5a02 --- /dev/null +++ b/.github/container/Dockerfile @@ -0,0 +1,16 @@ +# Some dependencies conflict with the compilation tools of amd64 architecture. Use arm64 directly. container image +FROM --platform=linux/arm64/v8 debian:bullseye + +RUN dpkg --add-architecture arm64 && \ + apt-get update && \ + apt-get full-upgrade --no-install-recommends -y \ + build-essential crossbuild-essential-arm64 git \ + debhelper devscripts lintian abigail-tools debhelper-compat \ + dh-python dh-sequence-dkms libaio-dev libblkid-dev \ + libcurl4-openssl-dev libelf-dev libpam0g-dev \ + libssl-dev libtirpc-dev libtool libudev-dev \ + lsb-release po-debconf python3-all-dev python3-cffi \ + python3-setuptools python3-sphinx uuid-dev zlib1g-dev \ + dkms linux-headers-arm64 && \ + adduser --gecos runner --disabled-password runner && \ + rm -rf /var/lib/apt/lists/* diff --git a/.github/container/build-deb b/.github/container/build-deb new file mode 100755 index 00000000..521e2431 --- /dev/null +++ b/.github/container/build-deb @@ -0,0 +1,98 @@ +#!/bin/bash + +set -euo pipefail +shopt -s nullglob + +build() { + local SCRIPT_DIR="$(dirname "$(realpath "$0")")" + + local NATIVE_BUILD="false" + local CONTAINER_BACKEND="podman" + local CONTAINER_REGISTRY="" + local NO_CONTAINER_UPDATE="false" + local CONTAINER_SHELL="false" + + if ! $NATIVE_BUILD + then + if [[ "$(basename "$CONTAINER_BACKEND")" == "docker" ]] && "$CONTAINER_BACKEND" -h | grep -q podman + then + echo "'$CONTAINER_BACKEND' backend is selected, but the functionality is actually provided by 'podman' backend. Updating accordingly..." + CONTAINER_BACKEND="$(command -v podman)" + fi + + local CONTAINER_IMAGE="$($CONTAINER_BACKEND image ls "-qf=reference=${CONTAINER_REGISTRY}zfs:master")" + local CONTAINER_EXIT_CODE=0 + + if ! $NO_CONTAINER_UPDATE + then + if [[ -z $CONTAINER_REGISTRY ]] + then + $CONTAINER_BACKEND build --force-rm -t "${CONTAINER_REGISTRY}zfs:master" "$SCRIPT_DIR" + else + $CONTAINER_BACKEND pull "${CONTAINER_REGISTRY}zfs:master" + fi + fi + + if [[ $CONTAINER_IMAGE != "$($CONTAINER_BACKEND image ls "-qf=reference=${CONTAINER_REGISTRY}zfs:master")" ]] + then + $CONTAINER_BACKEND container rm zfs &>/dev/null || true + $CONTAINER_BACKEND image rm "${CONTAINER_REGISTRY}zfs:builder" &>/dev/null || true + fi + + CONTAINER_BUILDER="$($CONTAINER_BACKEND image ls "-qf=reference=${CONTAINER_REGISTRY}zfs:builder")" + if [[ -z $CONTAINER_BUILDER ]] + then + $CONTAINER_BACKEND tag "${CONTAINER_REGISTRY}zfs:master" "${CONTAINER_REGISTRY}zfs:builder" + fi + + CONTAINER_OPTIONS=( "--name" "zfs" ) + CONTAINER_OPTIONS+=( "--workdir" "$PWD" ) + CONTAINER_OPTIONS+=( "--mount" "type=bind,source=$PWD,destination=$PWD" ) + CONTAINER_OPTIONS+=( "--mount" "type=bind,source=$(realpath $SCRIPT_DIR/../../..),destination=$(realpath $SCRIPT_DIR/../../..)" ) + if [[ -t 0 ]] + then + CONTAINER_OPTIONS+=( "-it" ) + fi + if [[ "$PWD" != "$SCRIPT_DIR" ]] + then + CONTAINER_OPTIONS+=( "--mount" "type=bind,source=$SCRIPT_DIR,destination=$SCRIPT_DIR" ) + fi + $CONTAINER_BACKEND container kill zfs &>/dev/null || true + $CONTAINER_BACKEND container rm zfs &>/dev/null || true + if [[ "$(basename "$CONTAINER_BACKEND")" == "podman" ]] + then + CONTAINER_OPTIONS+=( "--user" "root" ) + if $CONTAINER_SHELL + then + if ! $CONTAINER_BACKEND run "${CONTAINER_OPTIONS[@]}" "${CONTAINER_REGISTRY}zfs:builder" bash + then + CONTAINER_EXIT_CODE="$($CONTAINER_BACKEND inspect zfs --format='{{.State.ExitCode}}')" + fi + else + if ! $CONTAINER_BACKEND run "${CONTAINER_OPTIONS[@]}" "${CONTAINER_REGISTRY}zfs:builder" make -f Makefile.mk deb + then + CONTAINER_EXIT_CODE="$($CONTAINER_BACKEND inspect zfs --format='{{.State.ExitCode}}')" + fi + $CONTAINER_BACKEND container rm zfs + fi + else + local CONTAINER_SUDO="sed -i -E \"s/^(runner):(x?):([0-9]+):([0-9]+):(.*):(.*):(.*)$/\1:\2:$(id -u):$(id -g):\5:\6:\7/\" /etc/passwd && sudo -u runner" + if $CONTAINER_SHELL + then + if ! $CONTAINER_BACKEND run "${CONTAINER_OPTIONS[@]}" "${CONTAINER_REGISTRY}zfs:builder" bash -c "$CONTAINER_SUDO -i" + then + CONTAINER_EXIT_CODE="$($CONTAINER_BACKEND inspect zfs --format='{{.State.ExitCode}}')" + fi + else + if ! $CONTAINER_BACKEND run "${CONTAINER_OPTIONS[@]}" "${CONTAINER_REGISTRY}zfs:builder" bash -c "$CONTAINER_SUDO make -f Makefile.mk deb" + then + CONTAINER_EXIT_CODE="$($CONTAINER_BACKEND inspect zfs --format='{{.State.ExitCode}}')" + fi + $CONTAINER_BACKEND container rm zfs + fi + fi + return $CONTAINER_EXIT_CODE + fi +} + +build diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2c7d1708 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/new_version.yml b/.github/workflows/new_version.yml new file mode 100644 index 00000000..f65a6f76 --- /dev/null +++ b/.github/workflows/new_version.yml @@ -0,0 +1,37 @@ +name: Create release +on: + workflow_dispatch: + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + token: ${{secrets.GIT_PUSH_TOKEN}} + - name: Create release commit + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y git-buildpackage + export DEBEMAIL="dev@radxa.com" + export DEBFULLNAME='"Radxa Computer Co., Ltd"' + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + make -f Makefile.mk dch + - name: Test + run: | + make -f Makefile.mk test + sudo apt-get update + sudo apt-get build-dep --no-install-recommends -y . + make -f Makefile.mk all + sudo apt install -y binfmt-support qemu-user-static + .github/container/build-deb + - name: Push + run: | + git push diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..8044cf75 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,100 @@ +name: Build & Release +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Test + run: | + make -f Makefile.mk test + - name: Build + run: | + sudo apt-get update + sudo apt-get build-dep --no-install-recommends -y . + make -f Makefile.mk all + sudo apt install -y binfmt-support qemu-user-static + .github/container/build-deb + - name: Workaround actions/upload-artifact#176 + run: | + echo "artifacts_path=$(realpath ..)" >> $GITHUB_ENV + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ github.event.repository.name }} + path: | + ${{ env.artifacts_path }}/*.deb + release: + runs-on: ubuntu-latest + needs: build + if: ${{ github.event_name != 'pull_request' && github.ref_name == 'master' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - uses: actions/download-artifact@v3 + with: + name: ${{ github.event.repository.name }} + - name: Check if the latest version is releasable + run: | + version="$(dpkg-parsechangelog -S Version)" + echo "version=$version" >> $GITHUB_ENV + echo "changes<> $GITHUB_ENV + echo '```' >> $GITHUB_ENV + echo "$(dpkg-parsechangelog -S Changes)" >> $GITHUB_ENV + echo '```' >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + if [[ -n "$(git tag -l "$version")" ]] + then + echo "distro=UNRELEASED" >> $GITHUB_ENV + else + echo "distro=$(dpkg-parsechangelog -S Distribution)" >> $GITHUB_ENV + fi + echo "$version" > VERSION + if [[ -f pkg.conf.template ]] + then + sed "s/VERSION/$(dpkg-parsechangelog -S Version)/g" pkg.conf.template > pkg.conf + fi + - name: Release + if: env.distro != 'UNRELEASED' + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.version }} + body_path: README.md + token: ${{ secrets.GITHUB_TOKEN }} + target_commitish: master + draft: false + fail_on_unmatched_files: true + files: | + *.deb + VERSION + - name: Append changelog + if: env.distro != 'UNRELEASED' + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ env.version }} + body: | + ## Changelog for ${{ env.version }} + ${{ env.changes }} + append_body: true + - name: Update Test repos + if: env.distro != 'UNRELEASED' + uses: radxa-repo/update-repo-action@main + with: + test-repo: true + token: ${{ secrets.RADXA_APT_TEST_REPO_TOKEN }} diff --git a/Makefile.mk b/Makefile.mk new file mode 100644 index 00000000..9d83e68e --- /dev/null +++ b/Makefile.mk @@ -0,0 +1,63 @@ +PROJECT ?= zfs + +.PHONY: all +all: build + +# +# Test +# +.PHONY: test +test: + +# +# Build +# +.PHONY: build +build: build-doc + +SRC-DOC := . +DOCS := $(SRC-DOC)/SOURCE +.PHONY: build-doc +build-doc: $(DOCS) + +$(SRC-DOC): + mkdir -p $(SRC-DOC) + +.PHONY: $(SRC-DOC)/SOURCE +$(SRC-DOC)/SOURCE: $(SRC-DOC) + echo -e "git clone $(shell git remote get-url origin)\ngit checkout $(shell git rev-parse HEAD)" > "$@" + +# +# Clean +# +.PHONY: distclean +distclean: clean + +.PHONY: clean +clean: clean-doc clean-deb + +.PHONY: clean-doc +clean-doc: + rm -rf $(DOCS) + +.PHONY: clean-deb +clean-deb: + # The packaging of the zfs team is not standard. There will be many *.install files generated during packaging, which need to be cleaned using GIT. + git clean -fx debian/*.install + dh_auto_clean + rm -rf debian/.debhelper debian/lib*/ debian/*pyzfs*/ debian/*zfs*/ debian/tmp/ debian/debhelper-build-stamp debian/files debian/*.debhelper.log debian/*.*.debhelper debian/*.substvars + +# +# Release +# +.PHONY: dch +dch: debian/changelog + EDITOR=true gbp dch --debian-branch=main --multimaint-merge --commit --release --dch-opt=--upstream + +.PHONY: deb +deb: debian + debuild --no-lintian --no-sign -b -aarm64 -Pcross + +.PHONY: release +release: + gh workflow run .github/workflows/new_version.yml