fix(publish): ship only the installable payload in release assets

build_and_publish copied the entire tag archive (minus top dir + .git) into
the release zip, leaking dev/docs files to clients: ARCHITECTURE.md, README.md,
CHANGELOG.md, build.sh, .env.example, .taskmaster/, .claude/, the repo's own
composer.json. This raced n8n IcF30's clean upload under the same asset name,
producing two same-named assets per release (one clean, one junk).

Filter the copy loop to manifest.json + files/ + scripts/ only (composer.json
is generated), matching n8n IcF30 and build.sh. The /publish output is now the
clean installable package.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 18:22:34 +00:00
parent c2b88c5d33
commit 770ae1104f
+11 -2
View File
@@ -347,14 +347,23 @@ def build_and_publish(module, version):
with zipfile.ZipFile(ext_zip_path, 'w', zipfile.ZIP_DEFLATED) as ext_zip:
ext_zip.writestr('composer.json', json.dumps(composer, indent=2))
# Re-read archive and copy contents without the top-level dir
# Re-read archive and copy ONLY the installable payload, without the
# top-level dir. Mirror n8n IcF30 / build.sh: ship manifest.json +
# files/ + scripts/ only. Everything else (ARCHITECTURE.md, README.md,
# CHANGELOG.md, build.sh, .env.example, .taskmaster/, .claude/, .git,
# the repo's own composer.json) is dev/docs noise that must NOT reach a
# client install. composer.json is generated above.
INCLUDE_EXACT = {'manifest.json'}
INCLUDE_PREFIXES = ('files/', 'scripts/')
with zipfile.ZipFile(archive_path) as src_zip:
for item in src_zip.namelist():
if item.endswith('/'):
continue
# Strip top-level directory
rel_path = item[len(prefix):] if prefix and item.startswith(prefix) else item
if not rel_path or rel_path.startswith('.git'):
if not rel_path:
continue
if rel_path not in INCLUDE_EXACT and not rel_path.startswith(INCLUDE_PREFIXES):
continue
ext_zip.writestr(rel_path, src_zip.read(item))