From 7aaa07af47b5ed401e122a3bf1c2c7d95fb986e5 Mon Sep 17 00:00:00 2001 From: Artur Bobb Date: Wed, 15 Jul 2026 07:18:07 +0000 Subject: [PATCH] build: add scripts to publish Release folder deliverables Add Linux/macOS and Windows scripts under build/ that restore, build Release, pack NuGet packages, and collect library binaries plus packages into a top-level Release/ directory (gitignored). Co-authored-by: Artur B. --- .gitignore | 1 + README.md | 12 +++++- build/README.md | 40 ++++++++++++++++++ build/publish-release.cmd | 85 +++++++++++++++++++++++++++++++++++++++ build/publish-release.sh | 77 +++++++++++++++++++++++++++++++++++ 5 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 build/README.md create mode 100644 build/publish-release.cmd create mode 100755 build/publish-release.sh diff --git a/.gitignore b/.gitignore index bdf57d1..a2a79c3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ bin/ obj/ artifacts/ +Release/ *.user *.suo *.userosscache diff --git a/README.md b/README.md index ba0db8b..88e3e99 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,23 @@ dotnet test -c Release dotnet pack -c Release ``` +To produce a top-level `Release/` folder with library binaries and NuGet packages: + +```bash +# Linux / macOS +./build/publish-release.sh + +# Windows +build\publish-release.cmd +``` + Coverage (optional): ```bash dotnet test -c Release --collect:"XPlat Code Coverage" --results-directory ./artifacts/test-results ``` -Package artifacts are written to `artifacts/packages/`. Full coverage breakdown: [docs/coverage-summary.md](docs/coverage-summary.md). +Intermediate build outputs remain under `artifacts/`. Release deliverables are copied to `Release/` (gitignored). Coverage breakdown: [docs/coverage-summary.md](docs/coverage-summary.md). ## Design principles diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..901d10d --- /dev/null +++ b/build/README.md @@ -0,0 +1,40 @@ +# Release build scripts + +Scripts in this folder produce a top-level `Release/` folder with FunctionFoundry deliverables. + +## Linux / macOS + +```bash +./build/publish-release.sh +``` + +## Windows + +```bat +build\publish-release.cmd +``` + +## What the scripts do + +1. `dotnet restore` +2. `dotnet build -c Release` +3. `dotnet pack -c Release` (NuGet packages for distribution) +4. Copy production library outputs and packages into `Release/`: + +```text +Release/ + MANIFEST.txt + bin/ + FunctionFoundry.Security/ + FunctionFoundry.Security.dll + FunctionFoundry.Security.xml + ... + ... + packages/ + FunctionFoundry.*.nupkg + FunctionFoundry.*.snupkg +``` + +Test, sample, and benchmark binaries are not copied into `Release/bin`. + +`Release/` is gitignored. diff --git a/build/publish-release.cmd b/build/publish-release.cmd new file mode 100644 index 0000000..6ddbcc5 --- /dev/null +++ b/build/publish-release.cmd @@ -0,0 +1,85 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +rem Restore, build Release, pack packages, and collect deliverables into .\Release +cd /d "%~dp0\.." +set "ROOT=%CD%" +set "RELEASE_DIR=%ROOT%\Release" +set "STAGE_BIN=%RELEASE_DIR%\bin" +set "STAGE_PACKAGES=%RELEASE_DIR%\packages" + +set "DOTNET_NOLOGO=1" +set "DOTNET_CLI_TELEMETRY_OPTOUT=1" + +echo ==> Repository root: %ROOT% +echo ==> Cleaning %RELEASE_DIR% +if exist "%RELEASE_DIR%" rmdir /s /q "%RELEASE_DIR%" +mkdir "%STAGE_BIN%" +mkdir "%STAGE_PACKAGES%" + +echo ==> Restoring +dotnet restore FunctionFoundry.slnx +if errorlevel 1 exit /b 1 + +echo ==> Building Release +dotnet build FunctionFoundry.slnx -c Release --no-restore +if errorlevel 1 exit /b 1 + +echo ==> Packing NuGet packages +if exist "%ROOT%\artifacts\packages" rmdir /s /q "%ROOT%\artifacts\packages" +mkdir "%ROOT%\artifacts\packages" +dotnet pack FunctionFoundry.slnx -c Release --no-build -o "%ROOT%\artifacts\packages" +if errorlevel 1 exit /b 1 + +echo ==> Collecting library binaries +for /d %%D in ("%ROOT%\src\FunctionFoundry.*") do ( + set "NAME=%%~nxD" + set "SRC_OUT=%ROOT%\artifacts\bin\!NAME!\release" + if exist "!SRC_OUT!" ( + mkdir "%STAGE_BIN%\!NAME!" >nul 2>&1 + if exist "!SRC_OUT!\!NAME!.dll" copy /y "!SRC_OUT!\!NAME!.dll" "%STAGE_BIN%\!NAME!\" >nul + if exist "!SRC_OUT!\!NAME!.xml" copy /y "!SRC_OUT!\!NAME!.xml" "%STAGE_BIN%\!NAME!\" >nul + if exist "!SRC_OUT!\!NAME!.pdb" copy /y "!SRC_OUT!\!NAME!.pdb" "%STAGE_BIN%\!NAME!\" >nul + if exist "!SRC_OUT!\!NAME!.deps.json" copy /y "!SRC_OUT!\!NAME!.deps.json" "%STAGE_BIN%\!NAME!\" >nul + echo !NAME! + ) else ( + echo skip !NAME! ^(no release output^) + ) +) + +echo ==> Collecting NuGet packages +set "PACKAGE_COUNT=0" +for %%F in ("%ROOT%\artifacts\packages\FunctionFoundry.*.nupkg" "%ROOT%\artifacts\packages\FunctionFoundry.*.snupkg") do ( + if exist "%%~fF" ( + copy /y "%%~fF" "%STAGE_PACKAGES%\" >nul + set /a PACKAGE_COUNT+=1 + ) +) +echo %PACKAGE_COUNT% package file^(s^) + +echo ==> Writing Release manifest +> "%RELEASE_DIR%\MANIFEST.txt" ( + echo FunctionFoundry Release bundle + echo GeneratedUTC=%DATE% %TIME% + echo Host=%OS% + for /f "delims=" %%V in ('dotnet --version') do echo DotnetSdk=%%V + echo. + echo Libraries: +) +for /r "%STAGE_BIN%" %%F in (*) do ( + set "REL=%%F" + set "REL=!REL:%RELEASE_DIR%\=!" + >> "%RELEASE_DIR%\MANIFEST.txt" echo !REL! +) +>> "%RELEASE_DIR%\MANIFEST.txt" echo. +>> "%RELEASE_DIR%\MANIFEST.txt" echo Packages: +for /r "%STAGE_PACKAGES%" %%F in (*) do ( + set "REL=%%F" + set "REL=!REL:%RELEASE_DIR%\=!" + >> "%RELEASE_DIR%\MANIFEST.txt" echo !REL! +) + +echo. +echo Release folder ready: %RELEASE_DIR% +dir /s /b "%RELEASE_DIR%" +exit /b 0 diff --git a/build/publish-release.sh b/build/publish-release.sh new file mode 100755 index 0000000..860c990 --- /dev/null +++ b/build/publish-release.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Restore, build Release, pack packages, and collect deliverables into ./Release +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +export DOTNET_NOLOGO="${DOTNET_NOLOGO:-1}" +export DOTNET_CLI_TELEMETRY_OPTOUT="${DOTNET_CLI_TELEMETRY_OPTOUT:-1}" + +RELEASE_DIR="$ROOT/Release" +STAGE_BIN="$RELEASE_DIR/bin" +STAGE_PACKAGES="$RELEASE_DIR/packages" + +echo "==> Repository root: $ROOT" +echo "==> Cleaning $RELEASE_DIR" +rm -rf "$RELEASE_DIR" +mkdir -p "$STAGE_BIN" "$STAGE_PACKAGES" + +echo "==> Restoring" +dotnet restore FunctionFoundry.slnx + +echo "==> Building Release" +dotnet build FunctionFoundry.slnx -c Release --no-restore + +echo "==> Packing NuGet packages" +rm -rf "$ROOT/artifacts/packages" +mkdir -p "$ROOT/artifacts/packages" +dotnet pack FunctionFoundry.slnx -c Release --no-build -o "$ROOT/artifacts/packages" + +echo "==> Collecting library binaries" +shopt -s nullglob +for project_dir in "$ROOT"/src/FunctionFoundry.*; do + name="$(basename "$project_dir")" + src_out="$ROOT/artifacts/bin/$name/release" + if [[ ! -d "$src_out" ]]; then + echo " skip $name (no release output at $src_out)" + continue + fi + + dest="$STAGE_BIN/$name" + mkdir -p "$dest" + # Copy assembly, docs, symbols; skip deps.json/runtimeconfig from class libraries when absent. + for pattern in "$name.dll" "$name.xml" "$name.pdb" "$name.deps.json"; do + if [[ -f "$src_out/$pattern" ]]; then + cp -f "$src_out/$pattern" "$dest/" + fi + done + echo " $name" +done + +echo "==> Collecting NuGet packages" +package_count=0 +for pkg in "$ROOT"/artifacts/packages/FunctionFoundry.*.nupkg "$ROOT"/artifacts/packages/FunctionFoundry.*.snupkg; do + [[ -e "$pkg" ]] || continue + cp -f "$pkg" "$STAGE_PACKAGES/" + package_count=$((package_count + 1)) +done +echo " $package_count package file(s)" + +echo "==> Writing Release manifest" +{ + echo "FunctionFoundry Release bundle" + echo "GeneratedUTC=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" + echo "Host=$(uname -s) $(uname -m)" + echo "DotnetSdk=$(dotnet --version)" + echo + echo "Libraries:" + find "$STAGE_BIN" -type f | sort | sed "s|^$RELEASE_DIR/||" + echo + echo "Packages:" + find "$STAGE_PACKAGES" -type f | sort | sed "s|^$RELEASE_DIR/||" +} > "$RELEASE_DIR/MANIFEST.txt" + +echo +echo "Release folder ready: $RELEASE_DIR" +find "$RELEASE_DIR" -maxdepth 2 -type f | sort | sed "s|^$ROOT/||"