From ccdb1d7cecb580dd29c07dcb8d3aa5dff11ef5b0 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 4 Feb 2026 12:38:44 -0300 Subject: [PATCH] chore: refactor nightly release workflow to follow Nextcloud patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add permission checks (actions:write, contents:write) - Extract version and appinfo data using xpath-action - Organize steps logically: setup → build → package → release - Simplify by removing redundant steps and duplications - Follow official Nextcloud appstore-build-publish.yml structure - Include LibreSign binary signing via Makefile - Generate release notes from recent commits - Publish to App Store with nightly:true flag Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .github/workflows/nightly-release.yml | 243 ++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 .github/workflows/nightly-release.yml diff --git a/.github/workflows/nightly-release.yml b/.github/workflows/nightly-release.yml new file mode 100644 index 0000000000..7db253514b --- /dev/null +++ b/.github/workflows/nightly-release.yml @@ -0,0 +1,243 @@ +# SPDX-FileCopyrightText: 2026 LibreCode coop and contributors +# SPDX-License-Identifier: AGPL-3.0-or-later + +name: Nightly Release + +on: + push: + branches: + - main + paths-ignore: + - '**.md' + - '.github/**' + - '!.github/workflows/nightly-release.yml' + + workflow_dispatch: + +permissions: + contents: write + actions: write + +jobs: + nightly-release: + runs-on: ubuntu-latest + + steps: + - name: Check actor permission + uses: skjnldsv/check-actor-permission@69e92a3c4711150929bca9fcf34448c5bf5526e7 # v3.0 + with: + require: write + + - name: Set app env + run: | + echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + submodules: true + path: ${{ env.APP_NAME }} + + - name: Get app version number + id: app-version + uses: skjnldsv/xpath-action@f5b036e9d973f42c86324833fd00be90665fbf77 # v1.0.0 + with: + filename: ${{ env.APP_NAME }}/appinfo/info.xml + expression: "//info//version/text()" + + - name: Set APP_VERSION env + run: | + echo "APP_VERSION=${{ fromJSON(steps.app-version.outputs.result).version }}" >> $GITHUB_ENV + + - name: Get appinfo data + id: appinfo + uses: skjnldsv/xpath-action@f5b036e9d973f42c86324833fd00be90665fbf77 # v1.0.0 + with: + filename: ${{ env.APP_NAME }}/appinfo/info.xml + expression: "//info//dependencies//nextcloud/@min-version" + + - name: Read package.json node and npm engines version + uses: skjnldsv/read-package-engines-version-actions@06d6baf7d8f41934ab630e97d9e6c0bc9c9ac5e4 # v3 + id: versions + # Continue if no package.json + continue-on-error: true + with: + path: ${{ env.APP_NAME }} + fallbackNode: '^20' + fallbackNpm: '^10' + + - name: Set up node ${{ steps.versions.outputs.nodeVersion }} + # Skip if no package.json + if: ${{ steps.versions.outputs.nodeVersion }} + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + with: + node-version: ${{ steps.versions.outputs.nodeVersion }} + + - name: Set up npm ${{ steps.versions.outputs.npmVersion }} + # Skip if no package.json + if: ${{ steps.versions.outputs.npmVersion }} + run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}' + + - name: Get php version + id: php-versions + uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 + with: + filename: ${{ env.APP_NAME }}/appinfo/info.xml + + - name: Set up php ${{ steps.php-versions.outputs.php-min }} + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0 + with: + php-version: ${{ steps.php-versions.outputs.php-min }} + coverage: none + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check composer.json + id: check_composer + uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 + with: + files: "${{ env.APP_NAME }}/composer.json" + + - name: Install composer dependencies + if: steps.check_composer.outputs.files_exists == 'true' + run: | + cd ${{ env.APP_NAME }} + composer install --no-dev + + - name: Build ${{ env.APP_NAME }} + # Skip if no package.json + if: ${{ steps.versions.outputs.nodeVersion }} + env: + CYPRESS_INSTALL_BINARY: 0 + run: | + cd ${{ env.APP_NAME }} + npm ci + npm run build --if-present + + - name: Check Krankerl config + id: krankerl + uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 + with: + files: ${{ env.APP_NAME }}/krankerl.toml + + - name: Install Krankerl + if: steps.krankerl.outputs.files_exists == 'true' + run: | + wget https://github.com/ChristophWurst/krankerl/releases/download/v0.14.0/krankerl_0.14.0_amd64.deb + sudo dpkg -i krankerl_0.14.0_amd64.deb + + - name: Package ${{ env.APP_NAME }} ${{ steps.version.outputs.version }} with krankerl + if: steps.krankerl.outputs.files_exists == 'true' + run: | + cd ${{ env.APP_NAME }} + krankerl package + + - name: Checkout server ${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }} + continue-on-error: true + id: server-checkout + run: | + NCVERSION='${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }}' + wget --quiet https://download.nextcloud.com/server/releases/latest-$NCVERSION.zip + unzip latest-$NCVERSION.zip + + - name: Checkout server master fallback + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + if: ${{ steps.server-checkout.outcome != 'success' }} + with: + persist-credentials: false + submodules: true + repository: nextcloud/server + path: nextcloud + + - name: Package ${{ env.APP_NAME }} ${{ steps.version.outputs.version }} with makefile + if: steps.krankerl.outputs.files_exists != 'true' + run: | + cd ${{ env.APP_NAME }} + # Setting up keys + mkdir -p build/tools/certificates/ + echo '${{ secrets.APP_PRIVATE_KEY }}' > build/tools/certificates/${{ env.APP_NAME }}.key + make appstore + + - name: Sign app + run: | + # Extracting release + cd ${{ env.APP_NAME }}/build/artifacts + tar -xvf ${{ env.APP_NAME }}.tar.gz + cd ../../../ + # Setting up keys + echo '${{ secrets.APP_PRIVATE_KEY }}' > ${{ env.APP_NAME }}.key + wget --quiet "https://github.com/nextcloud/app-certificate-requests/raw/master/${{ env.APP_NAME }}/${{ env.APP_NAME }}.crt" + # Signing + php nextcloud/occ integrity:sign-app --privateKey=../${{ env.APP_NAME }}.key --certificate=../${{ env.APP_NAME }}.crt --path=../${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }} + # Rebuilding archive + cd ${{ env.APP_NAME }}/build/artifacts + tar -zcvf ${{ env.APP_NAME }}.tar.gz ${{ env.APP_NAME }} + + - name: Extract version and create tag + id: version + run: | + TIMESTAMP=$(date -u +"%Y%m%d-%H%M%S") + TAG="nightly-${TIMESTAMP}" + + echo "version=${{ env.APP_VERSION }}" >> $GITHUB_OUTPUT + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Get recent commits for release notes + id: release-notes + run: | + cd ${{ env.APP_NAME }} + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null | grep -v nightly || echo "") + + if [ -z "$LAST_TAG" ]; then + COMMITS=$(git log -10 --pretty=format:"- %s (%h)" --no-merges) + else + COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges) + fi + + cat << EOF > release-notes.md + ## 🌙 Nightly Build - ${{ steps.version.outputs.version }} + + Automated nightly build from \`main\` branch. + + ⚠️ **Development version** - may contain bugs or unstable features. + + ### Recent Changes + + $COMMITS + + --- + 🤖 Generated from commit [\`${GITHUB_SHA:0:7}\`](https://github.com/${{ github.repository }}/commit/${{ github.sha }}) + EOF + + echo "notes<> $GITHUB_OUTPUT + cat release-notes.md >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create GitHub release + uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.2.0 + with: + tag_name: ${{ steps.version.outputs.tag }} + name: "Nightly ${{ steps.version.outputs.version }} (${{ steps.version.outputs.tag }})" + body: ${{ steps.release-notes.outputs.notes }} + prerelease: true + draft: false + + - name: Attach tarball to github release + uses: svenstaro/upload-release-action@6b7fa9f267e90b50a19fef07b3596790bb941741 # v2.11.3 + id: attach_to_release + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}.tar.gz + asset_name: ${{ env.APP_NAME }}-${{ steps.version.outputs.tag }}.tar.gz + tag: ${{ steps.version.outputs.tag }} + overwrite: true + + - name: Upload app to Nextcloud appstore (nightly) + uses: nextcloud-releases/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 # v1.0.3 + with: + app_name: ${{ env.APP_NAME }} + appstore_token: ${{ secrets.APPSTORE_TOKEN }} + download_url: ${{ steps.attach_to_release.outputs.browser_download_url }} + app_private_key: ${{ secrets.APP_PRIVATE_KEY }} + nightly: true