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
50 changes: 50 additions & 0 deletions .github/scripts/calculate-package-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash

set -euo pipefail

current_version="${1:-}"
published_versions_file="${2:-}"

if [[ ! "${current_version}" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "Expected a stable major.minor.patch source version, found '${current_version}'." >&2
exit 1
fi

if [[ ! -f "${published_versions_file}" ]]; then
echo "Published-version index '${published_versions_file}' does not exist." >&2
exit 1
fi

major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
source_patch="$((10#${BASH_REMATCH[3]}))"

published_patch="$(
jq --exit-status --raw-output \
--arg major "${major}" \
--arg minor "${minor}" \
'
if (.versions | type) != "array" then
error("Expected a versions array in the NuGet version index.")
else
[
.versions[]
| select(type == "string")
| select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))
| split(".")
| select(.[0] == $major and .[1] == $minor)
| .[2]
| tonumber
]
| max // -1
end
' \
"${published_versions_file}"
)"

base_patch="${source_patch}"
if (( published_patch > base_patch )); then
base_patch="${published_patch}"
fi

printf '%s.%s.%s\n' "${major}" "${minor}" "$((base_patch + 1))"
30 changes: 30 additions & 0 deletions .github/scripts/pack-nuget.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash

set -euo pipefail

output_directory="${1:-}"
package_version="${2:-}"
project="Magic.IndexedDb/Magic.IndexedDb.csproj"

if [[ -z "${output_directory}" ]]; then
echo "Usage: pack-nuget.sh OUTPUT_DIRECTORY [PACKAGE_VERSION]" >&2
exit 1
fi

if [[ -z "${package_version}" ]]; then
package_version="$(sed -nE 's:.*<Version>([^<]+)</Version>.*:\1:p' "${project}")"
fi

if [[ ! "${package_version}" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "Expected a stable major.minor.patch package version, found '${package_version}'." >&2
exit 1
fi

dotnet pack "${project}" \
--configuration Release \
--no-restore \
--output "${output_directory}" \
-p:Version="${package_version}" \
-p:PackageVersion="${package_version}" \
-p:ContinuousIntegrationBuild=true \
-p:GeneratePackageOnBuild=false
53 changes: 53 additions & 0 deletions .github/scripts/test-calculate-package-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash

set -euo pipefail

script_directory="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
test_directory="$(mktemp -d)"
trap 'rm -rf "${test_directory}"' EXIT
test_number=0

assert_version() {
local current_version="${1}"
local published_versions="${2}"
local expected_version="${3}"
local versions_file="${test_directory}/versions-$((++test_number)).json"
local actual_version

printf '%s\n' "${published_versions}" > "${versions_file}"
actual_version="$(
bash "${script_directory}/calculate-package-version.sh" \
"${current_version}" \
"${versions_file}"
)"

if [[ "${actual_version}" != "${expected_version}" ]]; then
echo "Expected ${expected_version}, got ${actual_version}." >&2
exit 1
fi
}

assert_failure() {
local current_version="${1}"
local published_versions="${2}"
local versions_file="${test_directory}/versions-$((++test_number)).json"

printf '%s\n' "${published_versions}" > "${versions_file}"
if bash "${script_directory}/calculate-package-version.sh" \
"${current_version}" \
"${versions_file}" > /dev/null 2>&1; then
echo "Expected version calculation to fail for '${current_version}'." >&2
exit 1
fi
}

assert_version "2.0.2" '{"versions":["1.0.12","2.0.1","2.0.2"]}' "2.0.3"
assert_version "2.0.2" '{"versions":["2.0.2","2.0.3"]}' "2.0.4"
assert_version "2.0.7" '{"versions":["2.0.3"]}' "2.0.8"
assert_version "2.1.0" '{"versions":["2.0.99","2.1.0-alpha1"]}' "2.1.1"
assert_version "2.0.2" '{"versions":["2.0.999-alpha1","3.0.0"]}' "2.0.3"
assert_failure "2.0" '{"versions":["2.0.2"]}'
assert_failure "02.0.2" '{"versions":["2.0.2"]}'
assert_failure "2.0.2" '{"unexpected":[]}'

echo "Package-version tests passed."
37 changes: 19 additions & 18 deletions .github/workflows/publish-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,22 @@ jobs:
shell: bash
run: |
current_version="$(sed -nE 's:.*<Version>([^<]+)</Version>.*:\1:p' Magic.IndexedDb/Magic.IndexedDb.csproj)"

if [[ ! "${current_version}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
echo "Expected a stable major.minor.patch Version in Magic.IndexedDb.csproj, found '${current_version}'." >&2
exit 1
fi

major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
next_patch="$((10#${patch} + GITHUB_RUN_NUMBER))"
package_version="${major}.${minor}.${next_patch}"
published_versions="${RUNNER_TEMP}/magic-indexeddb-versions.json"
curl \
--fail \
--silent \
--show-error \
--retry 3 \
--retry-all-errors \
--connect-timeout 10 \
--max-time 30 \
--output "${published_versions}" \
https://api.nuget.org/v3-flatcontainer/magic.indexeddb/index.json
package_version="$(
bash .github/scripts/calculate-package-version.sh \
"${current_version}" \
"${published_versions}"
)"

echo "package_version=${package_version}" >> "${GITHUB_OUTPUT}"
echo "Publishing Magic.IndexedDb ${package_version} from ${GITHUB_SHA}."
Expand All @@ -74,13 +79,9 @@ jobs:

- name: Pack
run: >-
dotnet pack Magic.IndexedDb/Magic.IndexedDb.csproj
--configuration Release
--no-restore
--output artifacts
-p:Version=${{ steps.version.outputs.package_version }}
-p:PackageVersion=${{ steps.version.outputs.package_version }}
-p:ContinuousIntegrationBuild=true
bash .github/scripts/pack-nuget.sh
artifacts
${{ steps.version.outputs.package_version }}

- name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
Expand Down
27 changes: 12 additions & 15 deletions .github/workflows/validate-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,11 @@ jobs:
- name: Restore unit tests
run: dotnet restore Magic.IndexedDb.UnitTests/Magic.IndexedDb.UnitTests.csproj

- name: Run unit and contract tests
run: >-
dotnet test Magic.IndexedDb.UnitTests/Magic.IndexedDb.UnitTests.csproj
--configuration Release
--no-restore
--logger "trx;LogFileName=core-validation.trx"
--results-directory artifacts/test-results
- name: Test package version calculation
run: bash .github/scripts/test-calculate-package-version.sh

- name: Pack the NuGet artifact
run: >-
dotnet pack Magic.IndexedDb/Magic.IndexedDb.csproj
--configuration Release
--no-restore
--output artifacts/package
-p:ContinuousIntegrationBuild=true
-p:GeneratePackageOnBuild=false
- name: Pack the NuGet artifact from a clean build state
run: bash .github/scripts/pack-nuget.sh artifacts/package

- name: Verify package contents
shell: bash
Expand All @@ -66,6 +55,14 @@ jobs:
unzip -Z1 "${package}" | grep -Fx wizardHatIcon.png
unzip -Z1 "${package}" | grep -F 'staticwebassets/'

- name: Run unit and contract tests
run: >-
dotnet test Magic.IndexedDb.UnitTests/Magic.IndexedDb.UnitTests.csproj
--configuration Release
--no-restore
--logger "trx;LogFileName=core-validation.trx"
--results-directory artifacts/test-results

- name: Upload test results and package
if: ${{ always() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
Expand Down
10 changes: 10 additions & 0 deletions docs/contributing/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ Every pull request runs:

Pushes to `master` run the same workflows again. A push to `release` starts `publish-nuget.yml`, which calls both validation workflows and does not build or publish the NuGet package until every validation job succeeds. This makes the release run a final independent gate even when the same commit passed on `master`.

Core validation packages the library before the unit-test build so the package check starts without cached build manifests. Validation and release publishing use the same `.github/scripts/pack-nuget.sh` entry point.

Release versions are based on the checked-in stable version line and the versions already present on NuGet. The workflow publishes one patch above whichever matching version is newer. Failed or retried workflow runs therefore do not consume or skip package versions. Version calculation fails safely if NuGet's version index cannot be read or validated.

The version-selection regression tests can be run locally:

```bash
bash .github/scripts/test-calculate-package-version.sh
```

The macOS WebKit job is valuable coverage for Apple's browser engine, but Playwright's WebKit build is not the branded Safari application and is not an iPhone or iPad device. Real Safari and iOS device coverage requires a separate device service or owned Apple test hardware; it should be added when credentials and a stable device-testing provider are available.

## Test design rules
Expand Down
Loading