Skip to content
Closed
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
4 changes: 3 additions & 1 deletion .github/scripts/clean-dev-files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ if [ -f ".nextcloudignore" ]; then
clean="${pattern#/}"
skip=false
for keep in "${KEEP_FILES[@]}"; do
# shellcheck disable=SC2254
# $clean is an intentional glob pattern (e.g. composer.*) matched against
# the preserved file name, so the RHS must stay unquoted.
# shellcheck disable=SC2053,SC2254
if [[ "$keep" == $clean ]]; then
skip=true
break
Expand Down
4 changes: 2 additions & 2 deletions .github/scripts/fetch-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ jq -r '.[] | "\(.id) \(.repo) \(.composer_args // "")"' "$CONFIG" | while read -
| length > 0
' "$OUTPUT/apps/$id/composer.json" > /dev/null 2>&1; then
echo " Running composer install for $id"
ARGS="${composer_args:---no-dev -a --quiet}"
(cd "$OUTPUT/apps/$id" && COMPOSER_ALLOW_SUPERUSER=1 composer install $ARGS)
read -r -a ARGS <<< "${composer_args:---no-dev -a --quiet}"
(cd "$OUTPUT/apps/$id" && COMPOSER_ALLOW_SUPERUSER=1 composer install "${ARGS[@]}")
fi
done

Expand Down
38 changes: 24 additions & 14 deletions .github/scripts/generate-metadata.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@

set -e

# Wrap the raw migration metadata JSON with build timestamps and write the
# final .metadata file. Reads env: METADATA_FILE, OUTPUT_FILE, BUILD_START,
# BUILD_DURATION. Kept as a function so it can be tested without occ/a database.
wrap_metadata() {
php << 'EOPHP'
<?php
$raw = file_get_contents(getenv('METADATA_FILE'));
$meta = json_decode($raw, true) ?: [];
$meta['build'] = [
'initiated' => (int)getenv('BUILD_START'),
'duration' => (int)getenv('BUILD_DURATION'),
];
file_put_contents(
getenv('OUTPUT_FILE'),
json_encode($meta, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);
echo "Metadata file created\n";
EOPHP
}

# When sourced (tests), stop here after defining functions.
[[ "${BASH_SOURCE[0]}" != "${0}" ]] && return 0

NC="${1:?Usage: generate-metadata.sh <nextcloud-dir> <version> <output-dir>}"
VERSION="${2:?Missing version}"
OUTPUT_DIR="${3:?Missing output directory}"
Expand Down Expand Up @@ -41,19 +64,6 @@ export OUTPUT_FILE="$OUTPUT_DIR/nextcloud-${VERSION}.metadata"
export BUILD_START="$START_TS"
export BUILD_DURATION="$DURATION"

php << 'EOPHP'
<?php
$raw = file_get_contents(getenv('METADATA_FILE'));
$meta = json_decode($raw, true) ?: [];
$meta['build'] = [
'initiated' => (int)getenv('BUILD_START'),
'duration' => (int)getenv('BUILD_DURATION'),
];
file_put_contents(
getenv('OUTPUT_FILE'),
json_encode($meta, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);
echo "Metadata file created\n";
EOPHP
wrap_metadata

rm -rf "$INSTALL_DIR" /tmp/metadata-raw.json
24 changes: 17 additions & 7 deletions .github/scripts/package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@

set -e

# Generate sha256/sha512/md5 sidecars for the release archives
# (nextcloud-<version>.{tar.bz2,zip}) in <output-dir>.
generate_checksums() {
local output="$1" version="$2" file
for file in "nextcloud-${version}.tar.bz2" "nextcloud-${version}.zip"; do
[ -f "$output/$file" ] || continue
( cd "$output" \
&& sha256sum "$file" > "${file}.sha256" \
&& sha512sum "$file" > "${file}.sha512" \
&& md5sum "$file" > "${file}.md5" )
done
}

# When sourced (tests), stop here after defining functions.
[[ "${BASH_SOURCE[0]}" != "${0}" ]] && return 0

NC="${1:?Usage: package.sh <nextcloud-dir> <version> <output-dir>}"
VERSION="${2:?Missing version}"
OUTPUT="${3:?Missing output directory}"
Expand All @@ -33,13 +49,7 @@ echo "Creating zip..."

# Generate checksums
echo "Generating checksums..."
cd "$OUTPUT"
for file in "nextcloud-${VERSION}.tar.bz2" "nextcloud-${VERSION}.zip"; do
[ -f "$file" ] || continue
sha256sum "$file" > "${file}.sha256"
sha512sum "$file" > "${file}.sha512"
md5sum "$file" > "${file}.md5"
done
generate_checksums "$OUTPUT" "$VERSION"

echo "Packages created:"
ls -lh "$OUTPUT/nextcloud-${VERSION}"*
11 changes: 10 additions & 1 deletion .github/scripts/sign-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@

set -e

# Resolve the signing certificate path: the given one, or the release default.
# Args: <nextcloud-dir> [certificate]
default_cert() {
echo "${2:-$1/resources/codesigning/core.crt}"
}

# When sourced (tests), stop here after defining functions.
[[ "${BASH_SOURCE[0]}" != "${0}" ]] && return 0

NC="${1:?Usage: sign-release.sh <nextcloud-dir> <private-key> [certificate]}"
KEY="${2:?Missing private key path}"
CERT="${3:-$NC/resources/codesigning/core.crt}"
CERT="$(default_cert "$NC" "${3:-}")"

chmod 755 "$NC/occ"
chmod 777 "$NC/config"
Expand Down
6 changes: 4 additions & 2 deletions .github/scripts/update-version-php.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@

set -e

NC="${1:?Usage: update-version-php.sh <nextcloud-dir> <channel> <branch>}"
# NC is exported because the inline PHP below reads it via getenv('NC').
export NC="${1:?Usage: update-version-php.sh <nextcloud-dir> <channel> <branch>}"
export CHANNEL="${2:?Missing channel (stable/beta)}"
export BRANCH="${3:?Missing branch (stable34/master)}"

COMMIT_HASH=$(cat "$NC/release-commit-hash")
rm -f "$NC/release-commit-hash"
export BUILD_STRING="$(date -u +%Y-%m-%dT%H:%M:%S+00:00) ${COMMIT_HASH}"
BUILD_STRING="$(date -u +%Y-%m-%dT%H:%M:%S+00:00) ${COMMIT_HASH}"
export BUILD_STRING

# Preserves OC_Version and OC_VersionString from the repo.
# Sets channel, build timestamp, edition, and vendor.
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/test-build-scripts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: MIT

name: Test build scripts

on:
push:
branches:
- main
paths:
- '.github/scripts/**'
- 'tests/build-scripts/**'
pull_request:
paths:
- '.github/scripts/**'
- 'tests/build-scripts/**'

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

# Global lint of every release script and every test harness.
- name: Shellcheck
run: shellcheck $(find .github/scripts tests -type f -name '*.sh' | sort)

test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

- name: Set up PHP
uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2.37.1
with:
php-version: '8.2'
tools: none

- name: Run snapshot tests
run: bash tests/build-scripts/run.sh

- name: Run unit tests
run: bash tests/build-scripts/unit.sh
114 changes: 114 additions & 0 deletions tests/build-scripts/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: MIT
#
# Snapshot test runner for the release build scripts (assemble.sh,
# clean-dev-files.sh, update-version-php.sh).
#
# These scripts only rearrange/clean a directory tree, so each scenario copies a
# fixture tree, runs the script, and snapshots the result:
# - assemble / clean-dev-files -> a manifest (sorted relative file paths)
# - update-version-php -> the rewritten version.php, build date normalized
#
# Usage:
# run.sh [--update] # --update regenerates expected/ from actual output
#
# Each scenario is a directory under scenarios/ containing:
# args.env - SCRIPT (assemble|clean-dev-files|update-version-php) + extras
# fixture/ - the input tree
# expected/snapshot - the expected manifest or normalized version.php

set -euo pipefail

TEST_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="$(cd "$TEST_DIR/../.." && pwd)"
SCENARIOS_DIR="$TEST_DIR/scenarios"
SCRIPTS="$REPO_DIR/.github/scripts"

UPDATE_MODE=false
[[ "${1:-}" == "--update" ]] && UPDATE_MODE=true

PASS=0
FAIL=0
ERRORS=""

# Sorted list of files + symlinks relative to a directory.
manifest() {
(cd "$1" && find . \( -type f -o -type l \) | LC_ALL=C sort)
}

run_scenario() {
local dir="$1"
local name
name=$(basename "$dir")
echo "--- ${name} ---"

local SCRIPT CHANNEL BRANCH
SCRIPT=""
CHANNEL="stable"
BRANCH="stable34"
# shellcheck source=/dev/null
source "$dir/args.env"

local work snapshot
work=$(mktemp -d)
snapshot=$(mktemp)
cp -a "$dir/fixture/." "$work/"

case "$SCRIPT" in
assemble)
# assemble.sh `cp -a server $OUTPUT` expects OUTPUT not to exist yet.
local outparent out
outparent=$(mktemp -d)
out="$outparent/nextcloud"
bash "$SCRIPTS/assemble.sh" "$work" "$out" > /dev/null
manifest "$out" > "$snapshot"
rm -rf "$outparent"
;;
clean-dev-files)
bash "$SCRIPTS/clean-dev-files.sh" "$work" > /dev/null
manifest "$work" > "$snapshot"
;;
clean-server-dev-files)
bash "$SCRIPTS/clean-server-dev-files.sh" "$work" > /dev/null
manifest "$work" > "$snapshot"
;;
update-version-php)
bash "$SCRIPTS/update-version-php.sh" "$work" "$CHANNEL" "$BRANCH" > /dev/null
# Normalize the non-deterministic build timestamp (commit hash stays).
sed -E "s/(\\\$OC_Build = ')[0-9T:+-]+ /\\1<DATE> /" "$work/version.php" > "$snapshot"
;;
*)
echo " FAIL: unknown SCRIPT '$SCRIPT'"
FAIL=$((FAIL + 1)); ERRORS="${ERRORS}\n ${name}: unknown SCRIPT"
rm -rf "$work" "$snapshot"; return
;;
esac

if [[ "$UPDATE_MODE" == "true" ]]; then
mkdir -p "$dir/expected"
cp "$snapshot" "$dir/expected/snapshot"
echo " UPDATED expected snapshot"
PASS=$((PASS + 1))
elif diff -u "$dir/expected/snapshot" "$snapshot"; then
echo " PASS"
PASS=$((PASS + 1))
else
echo " FAIL: snapshot differs"
FAIL=$((FAIL + 1)); ERRORS="${ERRORS}\n ${name}"
fi

rm -rf "$work" "$snapshot"
}

for scenario in "$SCENARIOS_DIR"/*/; do
[[ -f "$scenario/args.env" ]] || continue
run_scenario "$scenario"
done

echo ""
echo "=== Results: ${PASS} passed, ${FAIL} failed ==="
if [[ $FAIL -gt 0 ]]; then
echo -e "Failures:${ERRORS}"
exit 1
fi
1 change: 1 addition & 0 deletions tests/build-scripts/scenarios/assemble-basic/args.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SCRIPT=assemble
11 changes: 11 additions & 0 deletions tests/build-scripts/scenarios/assemble-basic/expected/snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
./3rdparty/autoload.php
./apps/files/appinfo.xml
./apps/news/main.php
./apps/notes/main.php
./core/doc/admin/index.html
./core/doc/user/index.html
./core/skeleton/Nextcloud Manual.pdf
./core/skeleton/Readme.md
./updater/index.php
./updater/updater.phar
./version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
u
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
readme
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
secret
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
old
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
junk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SCRIPT=clean-dev-files
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
./appinfo/info.xml
./composer.json
./composer.lock
./js/app.js.map
./lib/Foo.php
./package-lock.json
./package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# comment
/screenshots
*.log

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<xml/>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
log

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lic
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading