Skip to content
Merged
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
74 changes: 74 additions & 0 deletions .config/mise/tasks/github-actions/archive-storage-contract
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/sh
#MISE description="Run an archive storage CI lifecycle phase"

set -eu

root=$(CDPATH='' cd -- "$(dirname -- "$0")/../../../.." && pwd)
xunit_project="$root/src/EventStore.Core.XUnit.Tests/EventStore.Core.XUnit.Tests.csproj"
core_project="$root/src/EventStore.Core.Tests/EventStore.Core.Tests.csproj"
phase=${1:?archive storage phase is required}
platform=${TARGET_ARCH:-x64}

run_recovery_test() {
dotnet test \
--configuration Release \
--no-build \
-p:Platform="$platform" \
-p:RunS3Tests=true \
--filter "FullyQualifiedName~S3RestartRecoveryTests" \
--logger:GitHubActions \
"$xunit_project"
}

cd "$root"

case "$phase" in
contract)
dotnet test \
--configuration Release \
-p:Platform="$platform" \
-p:ContinuousIntegrationBuild=true \
-p:RunS3Tests=true \
--filter "FullyQualifiedName~S3ReaderTests|FullyQualifiedName~S3WriterTests|FullyQualifiedName~S3MetricsTests|FullyQualifiedName~S3FixtureLifecycleTests" \
--logger:GitHubActions \
"$xunit_project"
;;
recovery)
if [ "${EVENTSTORE_S3_RECOVERY_PHASE:-}" = unavailable ]; then
timeout 20 dotnet test \
--configuration Release \
--no-build \
-p:Platform="$platform" \
-p:RunS3Tests=true \
--filter "FullyQualifiedName~S3RestartRecoveryTests" \
--logger:GitHubActions \
"$xunit_project"
else
run_recovery_test
fi
;;
stop-storage)
: "${RUSTFS_CONTAINER_ID:?RUSTFS_CONTAINER_ID is required}"
timeout 20 docker stop --timeout 10 "$RUSTFS_CONTAINER_ID"
test "$(docker inspect --format '{{.State.Status}}' "$RUSTFS_CONTAINER_ID")" = exited
;;
restart-and-verify)
: "${RUSTFS_CONTAINER_ID:?RUSTFS_CONTAINER_ID is required}"
docker start "$RUSTFS_CONTAINER_ID"
timeout 30 sh -c 'until curl --output /dev/null --silent --fail http://localhost:9000/health; do sleep 1; done'
run_recovery_test
;;
cluster-restore)
dotnet test \
--configuration Release \
-p:Platform="$platform" \
-p:ContinuousIntegrationBuild=true \
--filter "TestCategory=ArchiveIntegration" \
--logger:GitHubActions \
"$core_project"
;;
*)
echo "Unsupported archive storage phase: $phase" >&2
exit 2
;;
esac
45 changes: 45 additions & 0 deletions .config/mise/tasks/github-actions/container
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/sh
#MISE description="Run a reusable container workflow phase"

set -eu

root=$(CDPATH='' cd -- "$(dirname -- "$0")/../../../.." && pwd)
phase=${1:?container phase is required}

cd "$root"

case "$phase" in
verify)
docker run --rm eventstore --insecure --what-if
;;
export-test)
docker save eventstore-test -o eventstore-test.tar
;;
export-runtime)
docker save eventstore -o eventstore.tar
;;
load-test)
docker load -i eventstore-test.tar
;;
load-runtime)
docker load --input eventstore.tar
;;
test)
: "${TEST_GROUP:?TEST_GROUP is required}"
docker run \
--env TEST_GROUP="$TEST_GROUP" \
--volume "$root/test-results:/build/test-results" \
--rm \
eventstore-test
;;
normalize-results)
if [ -d test-results ]; then
sudo chown -R "$(id -u):$(id -g)" test-results
sudo chmod -R u+rwX,go+rX test-results
fi
;;
*)
echo "Unsupported container phase: $phase" >&2
exit 2
;;
esac
45 changes: 45 additions & 0 deletions .config/mise/tasks/github-actions/docker-compose-smoke
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/sh
#MISE description="Build and validate the local TLS Docker Compose cluster"

set -eu

root=$(CDPATH='' cd -- "$(dirname -- "$0")/../../../.." && pwd)
fingerprints_before=$(mktemp)
fingerprints_after=$(mktemp)
compose_started=0
cleanup() {
rm -f "$fingerprints_before" "$fingerprints_after"
if [ "$compose_started" -eq 1 ]; then
docker compose down
fi
}
trap cleanup EXIT HUP INT TERM

cd "$root"
docker compose build
docker compose run --rm cert-gen
docker compose run --rm --entrypoint sh cert-gen -c '
test -z "$(find /certs/ca -mindepth 1 -maxdepth 1 ! -name ca.crt -print -quit)"
test "$(stat -c %a /certs/ca/ca.crt)" = 644
for certificate in /certs/node*/node.crt; do
test "$(stat -c %a "$certificate")" = 644
done
for private_key in /certs/node*/node.key; do
test "$(stat -c %a "$private_key")" = 600
done
'
docker compose run --rm --entrypoint sh cert-gen -c \
'sha256sum /certs/ca/ca.crt /certs/node*/node.crt /certs/node*/node.key' >"$fingerprints_before"
docker compose run --rm cert-gen
docker compose run --rm --entrypoint sh cert-gen -c \
'sha256sum /certs/ca/ca.crt /certs/node*/node.crt /certs/node*/node.key' >"$fingerprints_after"
diff --unified "$fingerprints_before" "$fingerprints_after"
compose_started=1
docker compose up --detach
printf 'Waiting for cluster'
for port in 2111 2112 2113; do
timeout 60 sh -c \
"until curl --output /dev/null --silent --fail --cacert certs/ca/ca.crt https://localhost:$port/-/readiness; do printf '.'; sleep 2; done"
done
docker compose down
compose_started=0
69 changes: 69 additions & 0 deletions .config/mise/tasks/github-actions/dotnet-build
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
#MISE description="Run a reusable dotnet build workflow phase"

set -euo pipefail

root=$(cd -- "$(dirname -- "$0")/../../../.." && pwd)
phase=${1:?dotnet build phase is required}

case "$phase" in
collect-results)
if [[ -d "$root/test-results" ]]; then
find "$root/test-results" -name "*.html" -exec cat {} + >"$root/test-results.html"
else
: >"$root/test-results.html"
fi
exit 0
;;
compile | verify | test) ;;
*)
echo "Unsupported dotnet build phase: $phase" >&2
exit 2
;;
esac

: "${TARGET_ARCH:?TARGET_ARCH is required}"
: "${BUILD_CONFIGURATION:?BUILD_CONFIGURATION is required}"

protobuf_tools_args=()
if [[ "$TARGET_ARCH" == arm64 ]]; then
protobuf_tools_args=(-p:Protobuf_ProtocFullPath="$(command -v protoc)")
fi

cd "$root"

case "$phase" in
compile)
dotnet build \
--configuration "$BUILD_CONFIGURATION" \
-p:Platform="$TARGET_ARCH" \
"${protobuf_tools_args[@]}" \
src/EventStore.sln
;;
verify)
dotnet run \
--project src/EventStore.ClusterNode \
--configuration "$BUILD_CONFIGURATION" \
-p:Platform="$TARGET_ARCH" \
"${protobuf_tools_args[@]}" \
-- --insecure --what-if
;;
test)
while IFS= read -r -d '' test_project; do
timeout --signal=TERM --kill-after=30s 30m \
dotnet test \
--configuration "$BUILD_CONFIGURATION" \
-p:Platform="$TARGET_ARCH" \
"${protobuf_tools_args[@]}" \
-p:ContinuousIntegrationBuild=true \
--blame \
--settings ./ci/ci.runsettings \
--logger:GitHubActions \
--logger:html \
--logger:trx \
--logger:"console;verbosity=normal" \
--results-directory="$(pwd)/test-results/$test_project" \
"$test_project"
done < <(find ./src -maxdepth 1 -type d -name "*.Tests" -print0)
;;
esac
13 changes: 13 additions & 0 deletions .config/mise/tasks/github-actions/nuget-authenticate
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
#MISE description="Authenticate dotnet against GitHub Packages"

set -eu

: "${NUGET_GITHUB_ACTOR:?NUGET_GITHUB_ACTOR is required}"
: "${NUGET_GITHUB_TOKEN:?NUGET_GITHUB_TOKEN is required}"

dotnet nuget add source "https://nuget.pkg.github.com/TrogonStack/index.json" \
--name github \
--username "$NUGET_GITHUB_ACTOR" \
--password "$NUGET_GITHUB_TOKEN" \
--store-password-in-clear-text
33 changes: 33 additions & 0 deletions .config/mise/tasks/github-actions/publish-container
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
#MISE description="Publish the container tags implied by the GitHub ref"

set -euo pipefail

: "${GITHUB_REF:?GITHUB_REF is required}"
: "${GITHUB_REF_NAME:?GITHUB_REF_NAME is required}"
: "${IMAGE:?IMAGE is required}"

tags=()

if [[ "$GITHUB_REF" == refs/heads/master ]]; then
tags+=(ci)
elif [[ "$GITHUB_REF" =~ ^refs/tags/v([0-9]+)\.([0-9]+)\.([0-9]+)(-[0-9A-Za-z.-]+)?$ ]]; then
major=${BASH_REMATCH[1]}
minor=${BASH_REMATCH[2]}
version=${GITHUB_REF_NAME#v}
tags+=("$version")

if [[ "$version" == *-* ]]; then
tags+=(preview)
else
tags+=("$major.$minor" "$major" stable)
fi
else
echo "Unsupported image publication ref: $GITHUB_REF" >&2
exit 1
fi

for tag in "${tags[@]}"; do
docker tag eventstore "$IMAGE:$tag"
docker push "$IMAGE:$tag"
done
21 changes: 21 additions & 0 deletions .config/mise/tasks/github-actions/resolve-comparison-refs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/sh
#MISE description="Write the C# quality comparison refs to GITHUB_OUTPUT"

set -eu

: "${GITHUB_OUTPUT:?GITHUB_OUTPUT is required}"
: "${EVENT_NAME:?EVENT_NAME is required}"

if [ "$EVENT_NAME" = pull_request ]; then
: "${BASE_SHA:?BASE_SHA is required for pull requests}"
: "${HEAD_SHA:?HEAD_SHA is required for pull requests}"
base=$BASE_SHA
head=$HEAD_SHA
else
: "${BEFORE_SHA:?BEFORE_SHA is required for push events}"
: "${CURRENT_SHA:?CURRENT_SHA is required for push events}"
base=$BEFORE_SHA
head=$CURRENT_SHA
fi

printf 'base=%s\nhead=%s\n' "$base" "$head" >>"$GITHUB_OUTPUT"
19 changes: 19 additions & 0 deletions .config/mise/tasks/github-actions/vulnerability-scan
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh
#MISE description="Restore packages and fail when vulnerable dependencies are reported"

set -eu

root=$(CDPATH='' cd -- "$(dirname -- "$0")/../../../.." && pwd)
results=$(mktemp)
trap 'rm -f "$results"' EXIT HUP INT TERM

cd "$root/src"
dotnet restore
if ! dotnet list package --vulnerable --include-transitive >"$results"; then
cat "$results"
exit 1
fi
cat "$results"
if grep -q "has the following vulnerable packages" "$results"; then
exit 1
fi
37 changes: 16 additions & 21 deletions .github/workflows/build-container-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ jobs:
uses: actions/checkout@v7
with:
fetch-depth: 0
if: ${{ inputs.mode != 'test-only' }}
- name: Install task runner
id: mise
uses: jdx/mise-action@v4.2.3
with:
version: 2026.8.2
install: false
cache: false
- name: Install net10.0
uses: actions/setup-dotnet@v6
with:
Expand Down Expand Up @@ -75,8 +81,7 @@ jobs:
nuget_auth_token=${{ secrets.GITHUB_TOKEN }}
- name: Verify Build
if: ${{ inputs.mode != 'test-only' }}
run: |
docker run --rm eventstore --insecure --what-if
run: mise run --skip-tools github-actions:container -- verify
- name: Build Test Container
uses: docker/build-push-action@v7
if: ${{ inputs.mode != 'test-only' }}
Expand All @@ -94,12 +99,10 @@ jobs:
nuget_auth_token=${{ secrets.GITHUB_TOKEN }}
- name: Export Test Container
if: ${{ inputs.mode == 'build-only' }}
run: |
docker save eventstore-test -o eventstore-test.tar
run: mise run --skip-tools github-actions:container -- export-test
- name: Export Container
if: ${{ inputs.mode == 'build-only' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) }}
run: |
docker save eventstore -o eventstore.tar
run: mise run --skip-tools github-actions:container -- export-runtime
- name: Publish Test Container
uses: actions/upload-artifact@v7
if: ${{ inputs.mode == 'build-only' }}
Expand All @@ -123,23 +126,15 @@ jobs:
name: ${{ inputs.test-image-artifact-name }}
- name: Load Test Container
if: ${{ inputs.mode == 'test-only' }}
run: |
docker load -i eventstore-test.tar
run: mise run --skip-tools github-actions:container -- load-test
- name: Run Tests
if: ${{ inputs.mode != 'build-only' }}
run: |
docker run \
--env TEST_GROUP="${{ inputs.test-group-name }}" \
--volume "$(pwd)/test-results:/build/test-results" \
--rm \
eventstore-test
env:
TEST_GROUP: ${{ inputs.test-group-name }}
run: mise run --skip-tools github-actions:container -- test
- name: Normalize Test Result Permissions
if: failure()
run: |
if [ -d test-results ]; then
sudo chown -R "$(id -u):$(id -g)" test-results
sudo chmod -R u+rwX,go+rX test-results
fi
if: ${{ failure() && steps.mise.outcome == 'success' }}
run: mise run --skip-tools github-actions:container -- normalize-results
- name: Publish Test Results
uses: actions/upload-artifact@v7
if: failure()
Expand Down
Loading
Loading