Fix second Codex finding: packaging symlink produced a dangling-symlink-only archive

The ensure-app-name-symlink fix from the previous commit created
../extended_occweb as a symlink so the inherited "../$(app_name)" tar
references would resolve regardless of the checkout's real directory
name - but the tar invocations ran without --dereference, so GNU tar
stored the symlink itself rather than following it into the real
files. make source/appstore therefore produced a 1-entry archive
containing nothing but a dangling absolute symlink, unusable on any
other machine. Caught by a second independent Codex pass; my own
"make appstore" test after the first fix only checked the archive's
top-level entry name, not its actual file count, so this went
unnoticed.

Rather than patch this with --dereference, replaced the whole
symlink+raw-tar approach with `git archive --prefix=$(app_name)/
HEAD`: it sets the correct top-level folder name directly (no symlink
needed at all), and - caught during this fix's own verification,
not by either Codex pass - it also closes a separate real leak the
symlink approach had: tarring the checkout directory directly
included every untracked/gitignored file too (e.g.
notes/deploy-nc01.md, which exists specifically because it must
never leave this machine). `git archive` only ever includes tracked
files. Dev/CI-only files (tests/, Makefile, composer.*, phpunit*.xml,
.travis.yml) are now stripped via `export-ignore` entries in a new
.gitattributes instead of a long list of tar --exclude flags repeated
per target - also means source and appstore now produce identical
output, which is fine given neither is part of our actual release
flow yet.

Verified end to end this time: extracted the resulting archive and
confirmed file count, absence of symlinks, absence of tests/notes/
dev files, and correct info.xml content - not just the archive's
top-level listing.
This commit is contained in:
2026-09-26 16:55:55 +02:00
parent 422748cace
commit 6016d0916c
2 changed files with 27 additions and 46 deletions
+11
View File
@@ -0,0 +1,11 @@
# Files excluded from `git archive` output - used by `make appstore` (and by
# our own nc01 deploy tarballs) to strip dev/CI-only files that don't belong
# in a running install, without needing them repeated as tar --exclude flags.
tests export-ignore
.travis.yml export-ignore
phpunit.xml export-ignore
phpunit.integration.xml export-ignore
composer.json export-ignore
composer.lock export-ignore
Makefile export-ignore
.gitattributes export-ignore
+16 -46
View File
@@ -110,60 +110,30 @@ dist:
make source
make appstore
# The source/appstore targets below reference ../$(app_name) throughout,
# inherited from the standard Nextcloud app Makefile template, which
# assumes CURDIR's own basename equals the app id. That's not true here
# (this checkout is "occweb", the app id is "extended_occweb"), so make
# ../$(app_name) resolve to this checkout regardless of what it's actually
# named, rather than rewriting every exclude pattern below.
.PHONY: ensure-app-name-symlink
ensure-app-name-symlink:
@if [ "$(notdir $(CURDIR))" != "$(app_name)" ]; then \
ln -sfn $(CURDIR) $(CURDIR)/../$(app_name); \
fi
# Builds the source package
# Both targets package via `git archive` rather than tarring the checkout
# directory directly: it only ever includes tracked files (so untracked/
# gitignored content - build/, notes/, any stray .env - can never leak into
# a release archive), it sets the correct top-level folder name via
# --prefix regardless of what this checkout is actually called (this repo
# is "occweb", the app id is "extended_occweb" - no symlink trick needed),
# and dev/CI-only files (tests/, Makefile, composer.*, phpunit*.xml,
# .travis.yml) are stripped via the `export-ignore` entries in
# .gitattributes instead of a long, easy-to-miss list of tar --exclude
# flags repeated per target. That also means source and appstore now
# produce the same archive; both targets are kept for compatibility with
# anything that invokes one of them by name.
.PHONY: source
source: ensure-app-name-symlink
source:
rm -rf $(source_build_directory)
mkdir -p $(source_build_directory)
tar \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/js/node_modules" \
--exclude="../$(app_name)/node_modules" \
--exclude="../$(app_name)/*.log" \
--exclude="../$(app_name)/js/*.log" \
-cvzf $(source_package_name).tar.gz ../$(app_name)
git archive --format=tar --prefix=$(app_name)/ HEAD | gzip > $(source_package_name).tar.gz
# Builds the source package for the app store, ignores php and js tests
.PHONY: appstore
appstore: ensure-app-name-symlink
appstore:
rm -rf $(appstore_build_directory)
mkdir -p $(appstore_build_directory)
tar \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/tests" \
--exclude="../$(app_name)/Makefile" \
--exclude="../$(app_name)/*.log" \
--exclude="../$(app_name)/phpunit*xml" \
--exclude="../$(app_name)/composer.*" \
--exclude="../$(app_name)/js/node_modules" \
--exclude="../$(app_name)/js/tests" \
--exclude="../$(app_name)/js/test" \
--exclude="../$(app_name)/js/*.log" \
--exclude="../$(app_name)/js/package.json" \
--exclude="../$(app_name)/js/bower.json" \
--exclude="../$(app_name)/js/karma.*" \
--exclude="../$(app_name)/js/protractor.*" \
--exclude="../$(app_name)/package.json" \
--exclude="../$(app_name)/bower.json" \
--exclude="../$(app_name)/karma.*" \
--exclude="../$(app_name)/protractor\.*" \
--exclude="../$(app_name)/.*" \
--exclude="../$(app_name)/js/.*" \
-cvzf $(appstore_package_name).tar.gz ../$(app_name)
git archive --format=tar --prefix=$(app_name)/ HEAD | gzip > $(appstore_package_name).tar.gz
.PHONY: test
test: composer