Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/app-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ on:
manifest — side_menu). The build input stays the no-op; a package.json refuses it.
default: false
type: boolean
php-only:
description: The app has runtime PHP classes and no frontend manifest or JavaScript bundle.
default: false
type: boolean
publish:
description: Publish on a v* tag. False only builds and packs.
default: true
Expand Down Expand Up @@ -113,6 +117,7 @@ jobs:
- name: Pack
env:
SHIPPED_BUNDLE: ${{ inputs.shipped-bundle && '1' || '0' }}
PHP_ONLY: ${{ inputs.php-only && '1' || '0' }}
run: bash tools/scripts/pack-app.sh pack "$APP_ID" "$APP_DIR" dist
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
Expand Down
32 changes: 30 additions & 2 deletions scripts/pack-app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# input, for the one kind of app that may carry one: upstream unreachable and no build manifest
# (side_menu), so the bundle ships as vendored bytes. A package.json still refuses it: an app
# that can build ships nothing committed.
# PHP_ONLY=1 packs server apps without a browser bundle. Such an app has runtime PHP
# classes and carries neither a frontend build manifest nor a js/ directory.
#
# sign reads the app key from APP_SIGNING_KEY (the .sec file's contents) and its passphrase from
# APP_SIGNING_KEY_PASSWORD ("" for a key made with signify -G -n). APS_COMMON_URL overrides the
Expand Down Expand Up @@ -71,9 +73,15 @@ DEFAULT_EXCLUDES='+ /.htaccess

# pack ID DIR OUT — stage DIR's runtime files as ID/, tar them deterministically, write SHA256SUMS
pack() {
local id="$1" dir="$2" out="$3" ts rules tracked list
local id="$1" dir="$2" out="$3" ts rules tracked list php_only="${PHP_ONLY:-0}"
[ -f "$dir/appinfo/info.xml" ] || die "$dir/appinfo/info.xml not found"
[ "$(info_field "$dir/appinfo/info.xml" id)" = "$id" ] || die "info.xml's <id> is not $id"
[[ "$php_only" = 0 || "$php_only" = 1 ]] || die "PHP_ONLY must be 0 or 1"
if [ "$php_only" = 1 ]; then
if [ -f "$dir/package.json" ] || [ -e "$dir/js" ] || [ "${SHIPPED_BUNDLE:-0}" = 1 ]; then
die "PHP-only apps cannot carry a frontend manifest or bundle"
fi
fi
# The bundle rule and its one exception. The release builds the bundle, so a committed js/ is
# refused — unless the app ships it (SHIPPED_BUNDLE=1, the workflow's `shipped-bundle` input):
# the honest state of an app whose upstream is unreachable and whose tarball is the source of
Expand Down Expand Up @@ -106,7 +114,11 @@ pack() {
! grep -qv "^$id/" <<<"$list" || die "a member sits outside $id/"
! grep -qx "$id/appinfo/signature.json" <<<"$list" \
|| die "appinfo/signature.json is in the tarball; Nextcloud's integrity check would flag the app"
grep -qE "^$id/js/[^/]+\.m?js$" <<<"$list" || die "no bundle: $id/js/ has no .js or .mjs file after the build"
if [ "$php_only" = 1 ]; then
grep -qE "^$id/lib/.+\.php$" <<<"$list" || die "PHP-only app has no runtime PHP classes"
else
grep -qE "^$id/js/[^/]+\.m?js$" <<<"$list" || die "no bundle: $id/js/ has no .js or .mjs file after the build"
fi
tar -xOzf "$work/$id.tar.gz" "$id/appinfo/info.xml" | cmp -s - "$dir/appinfo/info.xml" \
|| die "the tarball's info.xml is not the app's"

Expand Down Expand Up @@ -255,6 +267,22 @@ if [ "${1:-}" = "--self-test" ]; then
check "shipped-bundle: a package.json refuses it — a buildable app never ships its bundle committed" \
'[ "$rc" -ne 0 ] && [ ! -e "$tmp/o10/demo.tar.gz" ]'

mk_app "$tmp/php-only" 1.2.3
( cd "$tmp/php-only" && git rm -q package.json \
&& git -c user.email=t@test.invalid -c user.name=t commit -qm "server app without a frontend" )
php_pack() { rc=0; PHP_ONLY=1 bash "$SELF" pack demo "$1" "$2" >/dev/null 2>&1 || rc=$?; }
php_pack "$tmp/php-only" "$tmp/php-runtime"
check "PHP-only: runtime classes pack without a JavaScript bundle" \
'[ "$rc" -eq 0 ] && has "$tmp/php-runtime" lib/Application.php appinfo/info.xml && lacks "$tmp/php-runtime" "src|tests|package.json"'
php_pack "$tmp/app" "$tmp/php-with-manifest"
check "PHP-only: a frontend build manifest refuses the exemption" '[ "$rc" -ne 0 ]'
mkdir -p "$tmp/php-only/js"; echo 'runtime' > "$tmp/php-only/js/demo.js"
php_pack "$tmp/php-only" "$tmp/php-with-js"
check "PHP-only: browser JavaScript refuses the exemption" '[ "$rc" -ne 0 ]'
rm -rf "$tmp/php-only/js" "$tmp/php-only/lib"
php_pack "$tmp/php-only" "$tmp/php-empty"
check "PHP-only: a missing runtime class refuses publication" '[ "$rc" -ne 0 ]'

# throwaway keys: a passphrase-less one, an encrypted one, and an unrelated public key
( umask 077 && signify -G -n -p "$tmp/plain.pub" -s "$tmp/plain.sec" -c test \
&& printf 'pw\npw\n' | signify -G -p "$tmp/enc.pub" -s "$tmp/enc.sec" -c test >/dev/null \
Expand Down