# SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: MIT name: Build and publish app release on: push: tags: - 'v*' permissions: contents: write env: SHARE_DIR: /ci-share/appstore-publish/${{ github.run_id }}-${{ github.run_attempt }} jobs: versions: runs-on: selfhosted container: options: -v tmp:/ci-share outputs: php-min: ${{ steps.versions.outputs.php-min }} steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Validate app version against tag run: | VERSION="$(sed -n 's/^[[:space:]]*\(.*\)<\/version>[[:space:]]*$/\1/p' appinfo/info.xml)" echo "tag=${GITHUB_REF_NAME}" echo "version=${VERSION}" [ -n "${VERSION}" ] && [ "${GITHUB_REF_NAME}" = "v${VERSION}" ] - name: Get version matrix id: versions uses: https://github.com/icewind1991/nextcloud-version-matrix@8a7bac6300b2f0f3100088b297995a229558ddba # v1.3.2 - name: Recreate share directory run: | rm -rf "$SHARE_DIR" mkdir -p "$SHARE_DIR" build-frontend: needs: [versions] runs-on: selfhosted container: image: node:24-bookworm options: -v tmp:/ci-share outputs: build-hash: ${{ steps.share.outputs.build-hash }} steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Cache node_modules id: node-modules-cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: node_modules key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node_modules- - name: Install dependencies if: steps.node-modules-cache.outputs.cache-hit != 'true' env: CYPRESS_INSTALL_BINARY: 0 PUPPETEER_SKIP_DOWNLOAD: true run: npm ci - name: Build run: npm run build - name: Share frontend build id: share run: | tar -czf "$SHARE_DIR/frontend.tar.gz" js css sha256sum "$SHARE_DIR/frontend.tar.gz" | tee "$SHARE_DIR/frontend.sha256" echo "build-hash=$(cut -d' ' -f1 "$SHARE_DIR/frontend.sha256")" >> "$GITHUB_OUTPUT" build-vendor: needs: [versions] runs-on: selfhosted container: image: docker.io/setupphp/node:php-${{ needs.versions.outputs.php-min }}-bookworm options: -v tmp:/ci-share outputs: build-hash: ${{ steps.share.outputs.build-hash }} steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Restore composer binary uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 id: composer-bin-cache with: path: .ci-bin/composer key: composer-2-${{ runner.os }}-php-${{ needs.versions.outputs.php-min }}-bookworm - name: Install composer if: steps.composer-bin-cache.outputs.cache-hit != 'true' run: | mkdir -p .ci-bin curl -sS https://getcomposer.org/installer | php -- --install-dir=.ci-bin --filename=composer - name: Save composer binary if: steps.composer-bin-cache.outputs.cache-hit != 'true' uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .ci-bin/composer key: ${{ steps.composer-bin-cache.outputs.cache-primary-key }} - name: Add composer to PATH run: | chmod +x .ci-bin/composer echo "$GITHUB_WORKSPACE/.ci-bin" >> "$GITHUB_PATH" - name: Install composer dependencies run: composer install --no-dev --prefer-dist - name: Share vendor id: share run: | tar -czf "$SHARE_DIR/vendor.tar.gz" vendor sha256sum "$SHARE_DIR/vendor.tar.gz" | tee "$SHARE_DIR/vendor.sha256" echo "build-hash=$(cut -d' ' -f1 "$SHARE_DIR/vendor.sha256")" >> "$GITHUB_OUTPUT" build_and_publish: needs: [versions, build-frontend, build-vendor] runs-on: selfhosted container: image: node:24-bookworm options: -v tmp:/ci-share # Must match in appinfo/info.xml (repo name is nextcloud-shortcuts). # Job-level env is reliable on Forgejo; GITHUB_ENV may not feed ${{ env.* }} in later steps. env: APP_NAME: shortcuts steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false path: ${{ env.APP_NAME }} - name: Restore and verify frontend build run: | EXPECTED='${{ needs.build-frontend.outputs.build-hash }}' STORED="$(cut -d' ' -f1 "$SHARE_DIR/frontend.sha256")" ACTUAL="$(sha256sum "$SHARE_DIR/frontend.tar.gz" | cut -d' ' -f1)" echo "expected=$EXPECTED" echo "stored=$STORED" echo "actual=$ACTUAL" [ "$ACTUAL" = "$EXPECTED" ] && [ "$STORED" = "$EXPECTED" ] tar -xzf "$SHARE_DIR/frontend.tar.gz" -C "${{ env.APP_NAME }}" - name: Restore and verify vendor run: | EXPECTED='${{ needs.build-vendor.outputs.build-hash }}' STORED="$(cut -d' ' -f1 "$SHARE_DIR/vendor.sha256")" ACTUAL="$(sha256sum "$SHARE_DIR/vendor.tar.gz" | cut -d' ' -f1)" echo "expected=$EXPECTED" echo "stored=$STORED" echo "actual=$ACTUAL" [ "$ACTUAL" = "$EXPECTED" ] && [ "$STORED" = "$EXPECTED" ] tar -xzf "$SHARE_DIR/vendor.tar.gz" -C "${{ env.APP_NAME }}" - name: Package ${{ env.APP_NAME }} ${{ github.ref_name }} run: | cd ${{ env.APP_NAME }} mkdir -p build/artifacts tar -czf "build/artifacts/${{ env.APP_NAME }}.tar.gz" \ --exclude='./build' \ --exclude='./.git' \ --exclude='./.github' \ --exclude='./scripts' \ --exclude='./node_modules' \ --exclude='./src' \ --exclude='./tests' \ --exclude='./vendor-bin' \ --exclude='./.php-cs-fixer*' \ --exclude='./package.json' \ --exclude='./package-lock.json' \ --exclude='./tsconfig.json' \ --exclude='./vite.config.ts' \ --exclude='./eslint.config.js' \ --exclude='./stylelint.config.cjs' \ --exclude='./psalm.xml' \ --exclude='./rector.php' \ --exclude='./renovate.json' \ --transform "s,^\./,${{ env.APP_NAME }}/," \ . # Stage under the public asset name; forgejo-release uploads filenames as-is. - name: Stage release asset run: | mkdir -p release-assets cp "${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}.tar.gz" \ "release-assets/${{ env.APP_NAME }}-${{ github.ref_name }}.tar.gz" - name: Extract latest changelog notes run: | "${{ env.APP_NAME }}/scripts/extract-latest-changelog.sh" \ "${{ env.APP_NAME }}/CHANGELOG.md" > release-notes.md - name: Create release and upload tarball uses: https://code.forgejo.org/actions/forgejo-release@98265452477dafb3f0f27ba9c462c90b18cb44fd # v2.13.4 with: direction: upload url: ${{ github.server_url }} repo: ${{ github.repository }} tag: ${{ github.ref_name }} sha: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} release-dir: release-assets release-notes-file: release-notes.md - name: Expose download URL id: attach_to_release run: | DOWNLOAD_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/${APP_NAME}-${GITHUB_REF_NAME}.tar.gz" echo "browser_download_url=${DOWNLOAD_URL}" >> "$GITHUB_OUTPUT" echo "Download URL: ${DOWNLOAD_URL}" # The push action needs openssl (sign); this image does not ship it. - name: Install appstore push tools run: | apt-get update apt-get install -y --no-install-recommends openssl - name: Upload app to Nextcloud appstore uses: https://github.com/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 }} cleanup: needs: [build-frontend, build-vendor, build_and_publish] if: always() runs-on: selfhosted container: image: node:24-bookworm options: -v tmp:/ci-share steps: - name: Remove shared build output run: rm -rf "$SHARE_DIR"