Compare commits

...

2 Commits

Author SHA1 Message Date
Brent Perteet
e22ae29b3f ci: add macOS app validation pipeline 2026-08-24 17:05:43 -05:00
Brent Perteet
db2439c52e fix(sync): replay interrupted messages immediately 2026-08-24 17:05:36 -05:00
5 changed files with 153 additions and 2 deletions

48
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,48 @@
pipeline {
agent { label 'um-trace' }
options {
buildDiscarder(logRotator(numToKeepStr: '20'))
disableConcurrentBuilds()
timeout(time: 45, unit: 'MINUTES')
}
environment {
DEVELOPER_DIR = '/Applications/Xcode.app/Contents/Developer'
DOTNET_ROOT = '/Users/brent/.dotnet'
DOTNET_CLI_TELEMETRY_OPTOUT = '1'
DOTNET_NOLOGO = '1'
NUGET_XMLDOC_MODE = 'skip'
PATH = "/Users/brent/.dotnet:/opt/homebrew/bin:${env.PATH}"
}
stages {
stage('Toolchain') {
steps {
sh './scripts/ci/verify-macos-agent.sh'
}
}
stage('Tests') {
steps {
sh './scripts/ci/test.sh'
}
}
stage('iOS Build (Unsigned)') {
steps {
sh './scripts/ci/build-ios-unsigned.sh'
}
}
}
post {
always {
archiveArtifacts(
artifacts: 'artifacts/**/*',
allowEmptyArchive: true,
fingerprint: true
)
}
}
}

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
dotnet_bin="${DOTNET_BIN:-/Users/brent/.dotnet/dotnet}"
developer_dir="${DEVELOPER_DIR:-/Applications/Xcode.app/Contents/Developer}"
project="${repo_dir}/FieldLogger/FieldLogger.csproj"
runtime_identifier="${IOS_RUNTIME:-ios-arm64}"
nuget_cache="${UM_TRACE_NUGET_CACHE:-${TMPDIR:-/tmp}/um-trace-ci-nuget}"
export DEVELOPER_DIR="${developer_dir}"
export NUGET_HTTP_CACHE_PATH="${NUGET_HTTP_CACHE_PATH:-${nuget_cache}/http-cache}"
mkdir -p "${NUGET_HTTP_CACHE_PATH}"
"${dotnet_bin}" restore "${project}" \
-p:TargetFrameworks=net9.0-ios \
-p:RuntimeIdentifier="${runtime_identifier}" \
-p:NuGetAudit=false
# A narrowed restore of the MAUI head can rewrite the referenced library's
# assets file, so restore the headless sync library explicitly as well.
"${dotnet_bin}" restore "${repo_dir}/src/FieldLogger.Sync/FieldLogger.Sync.csproj" \
-p:NuGetAudit=false
"${dotnet_bin}" clean "${project}" \
--framework net9.0-ios \
--configuration Debug \
-p:TargetFrameworks=net9.0-ios \
-p:RuntimeIdentifier="${runtime_identifier}"
"${dotnet_bin}" build "${project}" \
--framework net9.0-ios \
--configuration Debug \
--runtime "${runtime_identifier}" \
-p:TargetFrameworks=net9.0-ios \
-p:EnableCodeSigning=false \
-p:CodesignKey= \
-p:CodesignProvision= \
--no-restore

28
scripts/ci/test.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
dotnet_bin="${DOTNET_TEST_BIN:-/usr/local/share/dotnet/dotnet}"
results_dir="${repo_dir}/artifacts/test-results"
nuget_cache="${UM_TRACE_NUGET_CACHE:-${TMPDIR:-/tmp}/um-trace-ci-nuget}"
mkdir -p "${results_dir}" "${nuget_cache}/http-cache"
export NUGET_HTTP_CACHE_PATH="${NUGET_HTTP_CACHE_PATH:-${nuget_cache}/http-cache}"
test_projects=(
"tests/FieldLogger.Sync.Tests/FieldLogger.Sync.Tests.csproj"
"tests/FieldLogger.Tests/FieldLogger.Tests.csproj"
"tests/IfLoc.Sim.Tests/IfLoc.Sim.Tests.csproj"
)
for project in "${test_projects[@]}"; do
project_name="$(basename "${project}" .csproj)"
DOTNET_ROOT=/usr/local/share/dotnet "${dotnet_bin}" restore "${repo_dir}/${project}" \
-p:NuGetAudit=false
DOTNET_ROOT=/usr/local/share/dotnet "${dotnet_bin}" test "${repo_dir}/${project}" \
--configuration Release \
--no-restore \
--logger "trx;LogFileName=${project_name}.trx" \
--results-directory "${results_dir}"
done

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
dotnet_bin="${DOTNET_BIN:-/Users/brent/.dotnet/dotnet}"
test_dotnet_bin="${DOTNET_TEST_BIN:-/usr/local/share/dotnet/dotnet}"
developer_dir="${DEVELOPER_DIR:-/Applications/Xcode.app/Contents/Developer}"
if [[ ! -x "${dotnet_bin}" ]]; then
echo "Missing Xcode 26 build SDK at ${dotnet_bin}." >&2
exit 2
fi
if [[ ! -x "${test_dotnet_bin}" ]]; then
echo "Missing .NET 9 test SDK at ${test_dotnet_bin}." >&2
exit 2
fi
if [[ ! -d "${developer_dir}" ]]; then
echo "Missing Xcode developer directory at ${developer_dir}." >&2
exit 2
fi
export DEVELOPER_DIR="${developer_dir}"
java -version
xcodebuild -version
"${dotnet_bin}" --info
"${dotnet_bin}" workload list
DOTNET_ROOT=/usr/local/share/dotnet "${test_dotnet_bin}" --info
# Signing is not required for the unsigned compile build, but report what will be
# available to later approval-gated device and TestFlight stages.
security find-identity -v -p codesigning || true

View File

@@ -98,10 +98,12 @@ public sealed class SqliteOutboundStore : IOutboundStore
{
await _db.CreateTableAsync<OutboundMessage>();
// A process crash can leave rows in-flight after the broker accepted them but before
// the application ack was applied. Requeue them; pointId makes the replay idempotent.
// the application ack was applied. Requeue them for immediate replay; pointId makes
// the replay idempotent. A zero due-time also keeps recovery independent of whichever
// clock implementation the sync engine uses.
await _db.ExecuteAsync(
"UPDATE outbound SET Status = ?, NextAttemptUnixMs = ? WHERE Status = ?",
(int)OutboundStatus.Pending, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
(int)OutboundStatus.Pending, 0,
(int)OutboundStatus.InFlight);
}