You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2026/09/30 16:16:45 UTC
(skywalking-horizon-ui) branch fix/release-tar-mac-metadata created (now a3853230)
This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a change to branch fix/release-tar-mac-metadata
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
at a3853230 docs(image): name the image tag as <version>, and stop the release rewriting it
This branch includes the following new commits:
new 76e890ed fix(release): pack both tarballs without macOS metadata
new a3853230 docs(image): name the image tag as <version>, and stop the release rewriting it
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(skywalking-horizon-ui) 01/02: fix(release): pack both tarballs without macOS metadata
Posted by wu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch fix/release-tar-mac-metadata
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
commit 76e890ed88cad6cd506cb63b7cad9c56d0e6861a
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Wed Sep 30 22:42:24 2026 +0800
fix(release): pack both tarballs without macOS metadata
On macOS, tar writes each file's extended attributes as a `._` AppleDouble
entry beside it, plus pax xattr headers. The 1.0.0 binary tarball carried
one for every file; on Linux, node-gyp-build loaded `._argon2.glibc.node`
and the server stopped at boot with "invalid ELF header"
(apache/skywalking#14119).
Pack with COPYFILE_DISABLE=1 and --no-xattrs, and fail Step 11 when either
tarball still carries a `._` entry. The check lists with `tar:!mac-ext`,
since macOS tar hides those entries from a plain `tar -t`.
A patch release (X.Y.Z, Z > 0) now proposes the next patch, not the next
minor, as the following version.
(cherry picked from commit a94f93314122714efb90a4d63525631a5de00442)
---
scripts/release.sh | 56 +++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 45 insertions(+), 11 deletions(-)
diff --git a/scripts/release.sh b/scripts/release.sh
index b74d1729..36ff68f5 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -63,6 +63,35 @@ file_has() {
grep -F -q -- "$2" "$1"
}
+# pack_tar <parent-dir> <tarball> <entry>
+# macOS tar stores each file's extended attributes (com.apple.provenance is on
+# anything git or cp wrote) as a `._` AppleDouble entry beside the file, plus
+# pax xattr headers. GNU tar unpacks those entries as real files, and on Linux
+# node-gyp-build then loads `._argon2.glibc.node` as argon2's native module, so
+# the binary tarball does not boot. COPYFILE_DISABLE drops the `._` entries,
+# --no-xattrs the headers; GNU tar accepts both.
+pack_tar() {
+ COPYFILE_DISABLE=1 tar --no-xattrs -C "$1" -czf "$2" "$3"
+}
+
+# Fails when a tarball carries a `._` entry. macOS tar folds those entries into
+# the file they describe when it LISTS an archive, so a plain `tar -t` on the
+# release machine shows none; `tar:!mac-ext` lists them as stored.
+assert_no_mac_metadata() {
+ local listing
+ if tar --version 2>/dev/null | grep -q bsdtar; then
+ listing=$(tar --options 'tar:!mac-ext' -tzf "$1")
+ else
+ listing=$(tar -tzf "$1")
+ fi
+ # A here-string, not a pipe: `grep -q` exits on the first match, and under
+ # pipefail the writer's SIGPIPE would turn that match into a failed test.
+ if grep -qE '(^|/)\._' <<< "${listing}"; then
+ err "$(basename "$1") carries macOS metadata (._ entries) — it would not boot on Linux."
+ exit 1
+ fi
+}
+
# ========================== Step 1: GPG signer ==========================
note "Step 1 — GPG signer check"
@@ -150,12 +179,13 @@ if [ "${CURRENT_VERSION}" = "${RELEASE_VERSION}" ]; then
err "main should carry the dev-suffixed version between releases — bump it before running this script."
exit 1
fi
-# Proposed next version: the next minor. Computed in a pipeline on purpose —
-# nothing derived from the version may survive as a variable across the prompt
-# below, where the operator can replace RELEASE_VERSION. Anything split out up
-# here (MAJOR / MINOR / …) would still describe the rejected version and be
-# read as current further down.
-NEXT_RELEASE_VERSION=$(echo "$RELEASE_VERSION" | awk -F. '{ printf "%d.%d.0", $1, $2 + 1 }')
+# Proposed next version: the next minor — or, for a patch release (X.Y.Z with
+# Z > 0, cut from its own X.Y.x branch), the next patch on that line. Computed
+# in a pipeline on purpose — nothing derived from the version may survive as a
+# variable across the prompt below, where the operator can replace
+# RELEASE_VERSION. Anything split out up here (MAJOR / MINOR / …) would still
+# describe the rejected version and be read as current further down.
+NEXT_RELEASE_VERSION=$(echo "$RELEASE_VERSION" | awk -F. '{ if ($3 > 0) printf "%d.%d.%d", $1, $2, $3 + 1; else printf "%d.%d.0", $1, $2 + 1 }')
echo "Current (in package.json): ${CURRENT_VERSION}"
echo "Release: ${RELEASE_VERSION}"
@@ -368,7 +398,7 @@ SRC_STAGE_NAME="${PRODUCT_NAME}-${RELEASE_VERSION}-src"
# files at the release tag — no .git, no node_modules, no dist, no editor
# leftovers (git archive emits only tracked files, which excludes all of
# those by .gitignore). We stage via `git archive` (portable — git does the
-# archiving) then repackage with plain `tar`, so this works the same on
+# archiving) then repackage with `pack_tar`, so this works the same on
# macOS (bsdtar) and Linux (GNU tar). GNU-only `--transform` is avoided;
# the tarball's top-level dir comes from `--prefix`.
rm -rf "${WORK_DIR}/${SRC_STAGE_NAME}"
@@ -382,7 +412,7 @@ rm -f "${WORK_DIR}/${SRC_STAGE_NAME}/.github/workflows/publish-image.yaml"
# artifact only; it is never committed to git.
cp "${WORK_DIR}/${SRC_STAGE_NAME}/docs/changelog/${RELEASE_VERSION}.md" \
"${WORK_DIR}/${SRC_STAGE_NAME}/CHANGELOG.md"
-tar -C "${WORK_DIR}" -czf "${SRC_TAR}" "${SRC_STAGE_NAME}"
+pack_tar "${WORK_DIR}" "${SRC_TAR}" "${SRC_STAGE_NAME}"
echo "Source tarball: ${SRC_TAR}"
@@ -417,12 +447,16 @@ cp "${CLONE_DIR}/README.md" "${BIN_STAGE}/README.md"
# Do NOT overwrite.
BIN_TAR="${WORK_DIR}/${PRODUCT_NAME}-${RELEASE_VERSION}-bin.tar.gz"
-tar -C "${WORK_DIR}" -czf "${BIN_TAR}" "${PRODUCT_NAME}-${RELEASE_VERSION}-bin"
+pack_tar "${WORK_DIR}" "${BIN_TAR}" "${PRODUCT_NAME}-${RELEASE_VERSION}-bin"
echo "Binary tarball: ${BIN_TAR}"
-# ========================== Step 11: Compare LICENSE/NOTICE in tarballs ==========================
-note "Step 11 — Verify LICENSE/NOTICE in src + bin tarballs"
+# ========================== Step 11: Verify src + bin tarballs ==========================
+note "Step 11 — Verify src + bin tarballs (macOS metadata, LICENSE/NOTICE)"
+
+assert_no_mac_metadata "${SRC_TAR}"
+assert_no_mac_metadata "${BIN_TAR}"
+echo "No macOS metadata in either tarball."
# Both tarballs must carry a LICENSE and NOTICE at their root, and the
# binary version must be the expanded one (contains the "Subcomponents"
(skywalking-horizon-ui) 02/02: docs(image): name the image tag as , and stop the release rewriting it
Posted by wu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch fix/release-tar-mac-metadata
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
commit a3853230334cc48e4f4c057f21f4b65de47514fa
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Thu Oct 1 00:16:16 2026 +0800
docs(image): name the image tag as <version>, and stop the release rewriting it
How to run the image rarely changes between releases, yet every release
rewrote docs/setup/container-image.md from the prior tag to the new one,
and Step 4 refused to start unless the page named the newest tag. Use the
<version> placeholder the rest of docs/ already uses, and drop both the
check and the rewrite. The release commit now touches version markers only.
---
CLAUDE.md | 4 +---
docs/setup/container-image.md | 14 ++++++++------
scripts/release.sh | 34 +++++-----------------------------
3 files changed, 14 insertions(+), 38 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index d725dc3d..cc4c8120 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -194,9 +194,7 @@ There is **no raw-JSON editor on these pages.** Never tell the reader to "edit t
### 3. Don't hardcode the Horizon version
-The website serves these docs **pinned per release**, so a version string in the body is redundant and silently goes stale on the next release. By default, write version-neutral: use a `<version>` placeholder in install commands, or phrase around it. State a concrete version only when the content is genuinely version-specific (a compatibility note, or a "new in X" call-out you deliberately want pinned).
-
-The **one maintained exception** is `docs/setup/container-image.md`: its image tags track the current release and are advanced automatically by the release tooling — leave them as concrete versions.
+The website serves these docs **pinned per release**, so a version string in the body is redundant and silently goes stale on the next release. By default, write version-neutral: use a `<version>` placeholder in install commands, or phrase around it. State a concrete version only when the content is genuinely version-specific (a compatibility note, or a "new in X" call-out you deliberately want pinned). Image tags are no exception — `ghcr.io/apache/skywalking-horizon-ui:<version>` — and [...]
### 4. Other house rules
diff --git a/docs/setup/container-image.md b/docs/setup/container-image.md
index 2c76edf7..aa43a436 100644
--- a/docs/setup/container-image.md
+++ b/docs/setup/container-image.md
@@ -14,8 +14,10 @@ Registry: **GitHub Container Registry (GHCR)** at `ghcr.io/apache/skywalking-hor
| `latest` | The newest released version. Moves. | Demos / dev only — do not pin production to `latest`. |
| `main` | Head of `main`. Moves on every merge. | Smoke-test the development branch. |
+In the examples on this page, replace `<version>` with the release you run.
+
```sh
-docker pull ghcr.io/apache/skywalking-horizon-ui:1.0.0
+docker pull ghcr.io/apache/skywalking-horizon-ui:<version>
docker pull ghcr.io/apache/skywalking-horizon-ui:<sha>
```
@@ -129,7 +131,7 @@ docker run -d --name horizon \
-p 8081:8081 \
-e NODE_OPTIONS=--max-old-space-size=1536 \
-v "$PWD/horizon.yaml:/app/horizon.yaml:ro" \
- ghcr.io/apache/skywalking-horizon-ui:1.0.0
+ ghcr.io/apache/skywalking-horizon-ui:<version>
```
## How to load `horizon.yaml` into the container
@@ -145,7 +147,7 @@ docker run -d \
--name horizon \
-p 8081:8081 \
-v "$PWD/horizon.yaml:/app/horizon.yaml:ro" \
- ghcr.io/apache/skywalking-horizon-ui:1.0.0
+ ghcr.io/apache/skywalking-horizon-ui:<version>
```
Notes:
@@ -158,7 +160,7 @@ Notes:
For immutable single-tenant deployments, build a child image that includes your config:
```dockerfile
-FROM ghcr.io/apache/skywalking-horizon-ui:1.0.0
+FROM ghcr.io/apache/skywalking-horizon-ui:<version>
COPY horizon.yaml /app/horizon.yaml
```
@@ -226,7 +228,7 @@ spec:
fsGroup: 101
containers:
- name: horizon
- image: ghcr.io/apache/skywalking-horizon-ui:1.0.0
+ image: ghcr.io/apache/skywalking-horizon-ui:<version>
ports:
- containerPort: 8081
envFrom:
@@ -272,7 +274,7 @@ docker run -d --name horizon \
-p 8081:8081 \
-v "$PWD/horizon.yaml:/app/horizon.yaml:ro" \
-v horizon-state:/data \
- ghcr.io/apache/skywalking-horizon-ui:1.0.0
+ ghcr.io/apache/skywalking-horizon-ui:<version>
```
Without a mounted volume the writes still land in the container's writable layer at `/data/` (ephemeral, but at least non-failing). Mounting a volume is what makes them durable.
diff --git a/scripts/release.sh b/scripts/release.sh
index 36ff68f5..e019bbcc 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -241,25 +241,11 @@ for pj in package.json packages/api-client/package.json packages/design-tokens/p
done
check_file_has_version "apps/bff/src/server.ts" "'${CURRENT_VERSION}'"
-# Docs normally reference the last released image tag on main, then the
-# release commit advances them to the new tag. If the docs were already
-# prepared for the release version, accept that too.
-PRIOR_RELEASE=$(cd "${PROJECT_DIR}" && git tag --list 'v*' --sort=-version:refname | head -1 | sed 's/^v//')
-if [ -z "${PRIOR_RELEASE}" ]; then
- err "No prior release tag (vX.Y.Z) found. Tag the first release manually before using this script."
- exit 1
-fi
-if ! file_has "${PROJECT_DIR}/docs/setup/container-image.md" "ghcr.io/apache/skywalking-horizon-ui:${PRIOR_RELEASE}" &&
- ! file_has "${PROJECT_DIR}/docs/setup/container-image.md" "ghcr.io/apache/skywalking-horizon-ui:${RELEASE_VERSION}"; then
- err "docs/setup/container-image.md must reference either prior image tag ${PRIOR_RELEASE} or release tag ${RELEASE_VERSION}."
- CONSISTENT=false
-fi
-
if ! $CONSISTENT; then
err "Version drift across files. Fix before continuing."
exit 1
fi
-echo "Code markers all at ${CURRENT_VERSION}; container docs are release-check compatible."
+echo "Code markers all at ${CURRENT_VERSION}."
# ========================== Step 5: Release-file check ==========================
note "Step 5 — Release-file check"
@@ -294,7 +280,7 @@ if [ "${CLONE_VERSION}" != "${CURRENT_VERSION}" ]; then
exit 1
fi
-# ========================== Step 8: Strip -dev, advance docs, commit, tag ==========================
+# ========================== Step 8: Strip -dev, commit, tag ==========================
note "Step 8 — Prepare release commit + tag ${TAG}"
cd "${CLONE_DIR}"
@@ -333,12 +319,7 @@ for (const f of files) {
sed -i.bak "s/'${CURRENT_VERSION}'/'${RELEASE_VERSION}'/g" apps/bff/src/server.ts
rm apps/bff/src/server.ts.bak
-# Advance docs from the prior release tag to the new one so the image
-# tag references in the release tarball match the release being cut.
-sed -i.bak "s|ghcr.io/apache/skywalking-horizon-ui:${PRIOR_RELEASE}|ghcr.io/apache/skywalking-horizon-ui:${RELEASE_VERSION}|g" docs/setup/container-image.md
-rm docs/setup/container-image.md.bak
-
-git add package.json packages/*/package.json apps/*/package.json apps/bff/src/server.ts docs/setup/container-image.md
+git add package.json packages/*/package.json apps/*/package.json apps/bff/src/server.ts
git commit -m "Prepare release ${RELEASE_VERSION}"
if git ls-remote --tags origin | grep -q "refs/tags/${TAG}$"; then
@@ -666,10 +647,6 @@ for (const f of files) {
sed -i.bak "s/'${RELEASE_VERSION}'/'${NEXT_DEV_VERSION}'/g" apps/bff/src/server.ts
rm apps/bff/src/server.ts.bak
-# Container-image docs already point at ${RELEASE_VERSION} (the release
-# commit just bumped them). They stay there — docs always reference the
-# last released tag, not the in-flight dev version.
-
# Open the next cycle: an empty docs/changelog/${NEXT_RELEASE_VERSION}.md plus
# its docs/menu.yml entry. The released version's file is not touched.
node "${CLONE_DIR}/scripts/changelog-version.mjs" seed "${NEXT_RELEASE_VERSION}" --repo-root "${CLONE_DIR}"
@@ -683,9 +660,8 @@ gh pr create --title "Release ${RELEASE_VERSION}, bump to ${NEXT_DEV_VERSION}" \
Release branch for ${RELEASE_VERSION}. Two commits:
1. \`Prepare release ${RELEASE_VERSION}\` — strips \`-dev\` from every package
- marker + \`apps/bff/src/server.ts\`; advances container-image docs to
- \`${RELEASE_VERSION}\`. Tagged \`${TAG}\` (the release-candidate commit the
- vote runs against).
+ marker + \`apps/bff/src/server.ts\`. Tagged \`${TAG}\` (the
+ release-candidate commit the vote runs against).
2. \`Prepare next release ${NEXT_DEV_VERSION}\` — bumps every marker to
\`${NEXT_DEV_VERSION}\` and seeds \`docs/changelog/${NEXT_RELEASE_VERSION}.md\`
(with its \`docs/menu.yml\` entry) for the next cycle.