-
Notifications
You must be signed in to change notification settings - Fork 55
Add dependency version validation pipeline #702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,338 @@ | ||||||
| # ================================================================================================ | ||||||
| # Dependency Version Validation Pipeline | ||||||
| # ================================================================================================ | ||||||
| # Validates that changes to dependency versions (Directory.Packages.props) do not break | ||||||
| # the DurableTask SDK NuGet packages at build or runtime when consumed by Azure Functions. | ||||||
| # | ||||||
| # This pipeline: | ||||||
| # 1. Packs all DurableTask SDK NuGet packages from source into a local feed | ||||||
| # 2. Builds an Azure Functions v4 (.NET isolated) app using those local packages | ||||||
| # 3. Starts Azurite (Azure Storage emulator) | ||||||
| # 4. Runs the Function App and triggers a HelloCities orchestration | ||||||
| # 5. Validates orchestration output and loaded SDK assembly versions | ||||||
| # ================================================================================================ | ||||||
|
|
||||||
| name: Dependency Version Validation | ||||||
|
|
||||||
| on: | ||||||
| push: | ||||||
| branches: | ||||||
| - main | ||||||
| - 'feature/**' | ||||||
| paths: | ||||||
| - 'Directory.Packages.props' | ||||||
| - 'Directory.Build.props' | ||||||
| - 'Directory.Build.targets' | ||||||
| - 'eng/targets/Release.props' | ||||||
| - 'test/SmokeTests/DepValidation/**' | ||||||
| pull_request: | ||||||
| paths: | ||||||
| - 'Directory.Packages.props' | ||||||
| - 'Directory.Build.props' | ||||||
| - 'Directory.Build.targets' | ||||||
| - 'eng/targets/Release.props' | ||||||
| - 'test/SmokeTests/DepValidation/**' | ||||||
| workflow_dispatch: | ||||||
|
|
||||||
| permissions: | ||||||
| contents: read | ||||||
|
|
||||||
| jobs: | ||||||
| dep-validation-smoke-test: | ||||||
| name: '.NET Isolated Smoke Test (NuGet Packages)' | ||||||
| runs-on: ubuntu-latest | ||||||
| timeout-minutes: 15 | ||||||
|
|
||||||
| steps: | ||||||
| # ---- Checkout & SDK Setup ---- | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v4 | ||||||
|
|
||||||
| - name: Setup .NET from global.json | ||||||
| uses: actions/setup-dotnet@v4 | ||||||
| with: | ||||||
| global-json-file: global.json | ||||||
|
|
||||||
| - name: Setup .NET 8.0 SDK | ||||||
| uses: actions/setup-dotnet@v4 | ||||||
| with: | ||||||
| dotnet-version: '8.0.x' | ||||||
|
|
||||||
| # ---- Parse SDK Version ---- | ||||||
| - name: Parse SDK version | ||||||
| id: version | ||||||
| run: | | ||||||
| set -e | ||||||
| PROPS_FILE="eng/targets/Release.props" | ||||||
| VERSION_PREFIX=$(grep -oP '<VersionPrefix>\K[^<]+' "$PROPS_FILE") | ||||||
| VERSION_SUFFIX=$(grep -oP '<VersionSuffix>\K[^<]+' "$PROPS_FILE" || true) | ||||||
|
|
||||||
| # Bump patch version to distinguish local build from published | ||||||
| IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION_PREFIX" | ||||||
| LOCAL_PATCH=$((PATCH + 1)) | ||||||
| LOCAL_VERSION="${MAJOR}.${MINOR}.${LOCAL_PATCH}" | ||||||
| if [ -n "$VERSION_SUFFIX" ]; then | ||||||
| LOCAL_VERSION="${LOCAL_VERSION}-${VERSION_SUFFIX}" | ||||||
| fi | ||||||
|
|
||||||
| # Update the version in source so assembly versions are consistent | ||||||
| sed -i "s|<VersionPrefix>${VERSION_PREFIX}</VersionPrefix>|<VersionPrefix>${MAJOR}.${MINOR}.${LOCAL_PATCH}</VersionPrefix>|" "$PROPS_FILE" | ||||||
|
|
||||||
| echo "Published version: ${VERSION_PREFIX}" | ||||||
| echo "Local version: ${LOCAL_VERSION}" | ||||||
| echo "sdk_version=${LOCAL_VERSION}" >> "$GITHUB_OUTPUT" | ||||||
|
|
||||||
| # ---- Pack SDK Packages from Source ---- | ||||||
| - name: Pack SDK packages from source | ||||||
| run: | | ||||||
| set -e | ||||||
| LOCAL_PACKAGES="test/SmokeTests/DepValidation/local-packages" | ||||||
| mkdir -p "$LOCAL_PACKAGES" | ||||||
|
|
||||||
| # Projects to pack (order matters for dependency resolution) | ||||||
| PROJECTS=( | ||||||
| "src/Abstractions/Abstractions.csproj" | ||||||
| "src/Client/Core/Client.csproj" | ||||||
| "src/Worker/Core/Worker.csproj" | ||||||
| "src/Grpc/Grpc.csproj" | ||||||
| "src/Client/Grpc/Client.Grpc.csproj" | ||||||
| "src/Worker/Grpc/Worker.Grpc.csproj" | ||||||
| ) | ||||||
|
|
||||||
| # Build all projects first | ||||||
| for project in "${PROJECTS[@]}"; do | ||||||
| echo "Building $project..." | ||||||
| dotnet build "$project" -c Release | ||||||
| done | ||||||
|
|
||||||
| # Pack from build output | ||||||
| for project in "${PROJECTS[@]}"; do | ||||||
| echo "Packing $project..." | ||||||
| dotnet pack "$project" -c Release --no-build --output "$LOCAL_PACKAGES" | ||||||
| done | ||||||
|
|
||||||
| echo "Local packages:" | ||||||
| ls -la "$LOCAL_PACKAGES" | ||||||
|
|
||||||
| # ---- Verify Packed Packages ---- | ||||||
| - name: Verify packed packages | ||||||
| env: | ||||||
| SDK_VERSION: ${{ steps.version.outputs.sdk_version }} | ||||||
| run: | | ||||||
| set -e | ||||||
| LOCAL_PACKAGES="test/SmokeTests/DepValidation/local-packages" | ||||||
| EXPECTED_PACKAGES=( | ||||||
| "Microsoft.DurableTask.Abstractions" | ||||||
| "Microsoft.DurableTask.Client" | ||||||
| "Microsoft.DurableTask.Client.Grpc" | ||||||
| "Microsoft.DurableTask.Worker" | ||||||
| "Microsoft.DurableTask.Worker.Grpc" | ||||||
| "Microsoft.DurableTask.Grpc" | ||||||
| ) | ||||||
| MISSING=0 | ||||||
| for pkg in "${EXPECTED_PACKAGES[@]}"; do | ||||||
| NUPKG="${pkg}.${SDK_VERSION}.nupkg" | ||||||
| if [ ! -f "$LOCAL_PACKAGES/$NUPKG" ]; then | ||||||
| echo "FAIL: Missing expected package: $NUPKG" | ||||||
| MISSING=$((MISSING + 1)) | ||||||
| else | ||||||
| echo " OK: $NUPKG" | ||||||
| fi | ||||||
| done | ||||||
| if [ $MISSING -gt 0 ]; then | ||||||
| echo "FAIL: $MISSING expected SDK package(s) missing for version $SDK_VERSION" | ||||||
| echo "Available packages:" | ||||||
| ls -1 "$LOCAL_PACKAGES" | ||||||
| exit 1 | ||||||
| fi | ||||||
| echo "PASS: All ${#EXPECTED_PACKAGES[@]} SDK packages verified for version $SDK_VERSION" | ||||||
|
|
||||||
| # ---- Build Smoke Test App ---- | ||||||
| - name: Build smoke test app | ||||||
| env: | ||||||
| SDK_VERSION: ${{ steps.version.outputs.sdk_version }} | ||||||
| run: | | ||||||
| set -e | ||||||
| cd test/SmokeTests/DepValidation | ||||||
| dotnet build DepValidationApp.csproj -c Release -p:SmokeTestSdkVersion=$SDK_VERSION -v normal | ||||||
|
|
||||||
| # ---- Verify SDK packages resolved from local-packages ---- | ||||||
| - name: Verify SDK packages from local source | ||||||
| run: | | ||||||
| set -e | ||||||
| echo "Verifying SDK packages were restored from local-packages..." | ||||||
| ASSETS_FILE="test/SmokeTests/DepValidation/obj/project.assets.json" | ||||||
| for pkg in "Microsoft.DurableTask.Abstractions" "Microsoft.DurableTask.Client.Grpc" "Microsoft.DurableTask.Worker.Grpc"; do | ||||||
| if grep -qi "$pkg" "$ASSETS_FILE"; then | ||||||
| echo " OK: $pkg found in project.assets.json" | ||||||
| else | ||||||
| echo " FAIL: $pkg NOT found" | ||||||
| exit 1 | ||||||
| fi | ||||||
| done | ||||||
| echo "PASS: SDK packages verified in build output." | ||||||
|
Comment on lines
+159
to
+173
|
||||||
|
|
||||||
| # ---- Publish Smoke Test App ---- | ||||||
| - name: Publish smoke test app | ||||||
| env: | ||||||
| SDK_VERSION: ${{ steps.version.outputs.sdk_version }} | ||||||
| run: | | ||||||
| set -e | ||||||
| cd test/SmokeTests/DepValidation | ||||||
| dotnet publish DepValidationApp.csproj -c Release -o ./publish -p:SmokeTestSdkVersion=$SDK_VERSION | ||||||
|
|
||||||
| # ---- Build Docker Image ---- | ||||||
| - name: Build Docker image | ||||||
| run: | | ||||||
| docker build -t dep-validation-smoketest test/SmokeTests/DepValidation | ||||||
|
|
||||||
| # ---- Start Azurite ---- | ||||||
| - name: Start Azurite | ||||||
| run: | | ||||||
| npm install -g azurite | ||||||
| docker network create smoketest-network 2>/dev/null || true | ||||||
| docker run -d \ | ||||||
| --name azurite-smoketest \ | ||||||
| --network smoketest-network \ | ||||||
| -p 10000:10000 -p 10001:10001 -p 10002:10002 \ | ||||||
| mcr.microsoft.com/azure-storage/azurite | ||||||
|
Comment on lines
+190
to
+198
|
||||||
| mcr.microsoft.com/azure-storage/azurite | |
| mcr.microsoft.com/azure-storage/azurite:3.33.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| local-packages/ |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|
|
||||||
| <PropertyGroup> | ||||||
| <TargetFramework>net8.0</TargetFramework> | ||||||
| <AzureFunctionsVersion>v4</AzureFunctionsVersion> | ||||||
| <OutputType>exe</OutputType> | ||||||
| <IsPackable>false</IsPackable> | ||||||
| <IsTestProject>false</IsTestProject> | ||||||
| <Nullable>enable</Nullable> | ||||||
| <ImplicitUsings>enable</ImplicitUsings> | ||||||
| <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally> | ||||||
| <!-- Disable SDK's source generation to allow reflection-based discovery of source-generated functions --> | ||||||
| <FunctionsEnableExecutorSourceGen>false</FunctionsEnableExecutorSourceGen> | ||||||
| <FunctionsEnableWorkerIndexing>false</FunctionsEnableWorkerIndexing> | ||||||
| </PropertyGroup> | ||||||
|
|
||||||
| <ItemGroup> | ||||||
| <!-- Azure Functions host packages (from nuget.org) --> | ||||||
| <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.51.0" /> | ||||||
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.3.0" /> | ||||||
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" OutputItemType="Analyzer" /> | ||||||
|
||||||
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" OutputItemType="Analyzer" /> | |
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" OutputItemType="Analyzer" PrivateAssets="all" /> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Use the Azure Functions base image for .NET 8.0 isolated | ||
| FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0 | ||
|
|
||
| ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ | ||
| AzureFunctionsJobHost__Logging__Console__IsEnabled=true \ | ||
| FUNCTIONS_WORKER_RUNTIME=dotnet-isolated | ||
|
|
||
| COPY ./publish /home/site/wwwroot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version parsing/mutation is brittle:
grep -Pand the exact-stringsedreplacement will break ifRelease.propsformatting changes (whitespace, attributes, multi-line XML), and mutating tracked files in-place makes failures harder to diagnose. Prefer deriving the version via MSBuild and passing it as properties (e.g., setVersionPrefix/VersionSuffix/Versionviadotnet build/pack -p:...) rather than editingeng/targets/Release.props.