Skip to content

Add TechnicalDataBuilder with ECLASS/IEC-61360 validation and Templat… #16

Add TechnicalDataBuilder with ECLASS/IEC-61360 validation and Templat…

Add TechnicalDataBuilder with ECLASS/IEC-61360 validation and Templat… #16

Workflow file for this run

name: Build & Publish NuGet (Tag Release)
permissions:
contents: write
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Release version (e.g. v0.2.0.12)"
required: true
type: string
ref:
description: "Git reference (commit SHA, branch, or tag) to create the release from"
required: true
type: string
default: "main"
jobs:
# Blocking gate: all tests must pass before any packing/publishing can run.
test-gate:
runs-on: ubuntu-latest
outputs:
resolved_sha: ${{ steps.resolve_sha.outputs.RESOLVED_SHA }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.ref || github.ref }}
- name: Resolve checked out commit SHA
id: resolve_sha
shell: bash
run: |
RESOLVED_SHA=$(git rev-parse HEAD)
echo "RESOLVED_SHA=$RESOLVED_SHA" >> "$GITHUB_OUTPUT"
echo "✅ Resolved commit SHA: $RESOLVED_SHA"
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
cache: true
cache-dependency-path: |
FluentAAS/**/*.csproj
FluentAAS/global.json
- name: Locate solution file
id: solution
shell: bash
run: |
SOLUTION=$(find . -maxdepth 5 -name "*.sln" | head -n 1)
if [ -z "$SOLUTION" ]; then
echo "❌ No solution file (*.sln) found in the repo."
exit 1
fi
echo "SOLUTION_PATH=$SOLUTION" >> $GITHUB_OUTPUT
echo "✅ Found solution: $SOLUTION"
- name: Restore dependencies
run: dotnet restore "${{ steps.solution.outputs.SOLUTION_PATH }}"
- name: Build solution
run: dotnet build "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-restore
- name: Test solution (blocking gate)
run: dotnet test "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-build --verbosity normal
build-pack-push:
runs-on: ubuntu-latest
needs: test-gate
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ needs.test-gate.outputs.resolved_sha }}
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
cache: true
cache-dependency-path: |
FluentAAS/**/*.csproj
FluentAAS/global.json
- name: Determine version (from tag or input)
id: version
shell: bash
env:
INPUT_VERSION: ${{ inputs.version }}
GITHUB_REF_NAME: ${{ github.ref_name }}
EVENT_NAME: ${{ github.event_name }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
TAG="$INPUT_VERSION"
else
TAG="$GITHUB_REF_NAME"
fi
echo "Tag: $TAG"
# Guardrail: must start with v and look like vX.Y.Z(.W)
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
echo "❌ Invalid tag format: $TAG"
echo "Expected format: v<major>.<minor>.<patch>[.<revision>] (e.g., v0.2.0.12 or v1.2.3)"
exit 1
fi
VERSION="${TAG#v}"
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "TAG=$TAG" >> $GITHUB_OUTPUT
echo "✅ Valid version format: $VERSION"
- name: Locate solution file
id: solution
shell: bash
run: |
SOLUTION=$(find . -maxdepth 5 -name "*.sln" | head -n 1)
if [ -z "$SOLUTION" ]; then
echo "❌ No solution file (*.sln) found in the repo."
exit 1
fi
echo "SOLUTION_PATH=$SOLUTION" >> $GITHUB_OUTPUT
echo "✅ Found solution: $SOLUTION"
- name: Restore dependencies
run: dotnet restore "${{ steps.solution.outputs.SOLUTION_PATH }}"
- name: Build solution
run: dotnet build "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-restore
- name: Pack NuGet packages
run: dotnet pack "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release -o ./artifacts --no-build /p:PackageVersion=${{ steps.version.outputs.VERSION }}
- name: Verify package versions
shell: bash
run: |
shopt -s nullglob
packages=(./artifacts/*.nupkg)
if [ ${#packages[@]} -eq 0 ]; then
echo "❌ No NuGet packages found in ./artifacts/"
exit 1
fi
echo "📦 Generated NuGet packages:"
VERSION="${{ steps.version.outputs.VERSION }}"
ESCAPED_VERSION="${VERSION//./\\.}"
for pkg in "${packages[@]}"; do
filename=$(basename "$pkg")
echo " - $filename"
# Verify the package name contains the expected version using escaped dots
if [[ "$filename" =~ \.$ESCAPED_VERSION\.nupkg$ ]]; then
echo "✅ Version matches tag: $VERSION"
else
echo "❌ Version mismatch in package name"
exit 1
fi
done
- name: Publish to NuGet
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: dotnet nuget push "artifacts/*.nupkg" --api-key "$NUGET_API_KEY" --source "https://api.nuget.org/v3/index.json" --skip-duplicate
- name: Build Changelog
id: build_changelog
uses: mikepenz/release-changelog-builder-action@v6
with:
fetchReleaseInformation: true
failOnError: false
mode: "HYBRID"
configurationJson: |
{
"template": "## What's Changed\n\n#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}",
"empty_template": "## What's Changed\n\nNo user-facing changes in this release.",
"pr_template": "- #{{TITLE}} by @#{{AUTHOR}} in ##{{NUMBER}}",
"commit_template": "- #{{TITLE}} by @#{{AUTHOR}} (`#{{MERGE_SHA}}`)",
"categories": [
{
"title": "## 🚀 Features",
"labels": ["enhancement", "feature", "feat"],
"mode": "PR"
},
{
"title": "## 🐛 Bug Fixes",
"labels": ["bug", "fix", "bugfix"],
"mode": "PR"
},
{
"title": "## 📝 Documentation",
"labels": ["docs", "documentation"],
"mode": "PR"
},
{
"title": "## 🧪 Tests",
"labels": ["test", "tests", "qa"],
"mode": "PR"
},
{
"title": "## 🧰 Maintenance",
"labels": ["chore", "ci", "build", "dependencies", "refactor"],
"mode": "PR"
},
{
"title": "## 🔒 Security",
"labels": ["security"],
"mode": "PR"
},
{
"title": "## 🚀 Features (Direct Commits)",
"mode": "COMMIT",
"rules": [
{
"pattern": "^(feat|feature)(\\(.+\\))?:\\s+.+$",
"flags": "giu",
"on_property": "title"
}
]
},
{
"title": "## 🐛 Bug Fixes (Direct Commits)",
"mode": "COMMIT",
"rules": [
{
"pattern": "^(fix|bugfix|bug)(\\(.+\\))?:\\s+.+$",
"flags": "giu",
"on_property": "title"
}
]
},
{
"title": "## 🧰 Maintenance (Direct Commits)",
"mode": "COMMIT",
"rules": [
{
"pattern": "^(build|chore|ci|refactor|perf|style|test|docs)(\\(.+\\))?:\\s+.+$",
"flags": "giu",
"on_property": "title"
}
]
},
{
"title": "## 📦 Other Direct Commits",
"mode": "COMMIT",
"rules": [
{
"pattern": "^.+$",
"flags": "gu",
"on_property": "title"
}
]
}
],
"sort": {
"order": "ASC",
"on_property": "mergedAt"
},
"label_extractor": [
{
"pattern": "^(enhancement|feature|feat)$",
"target": "$1",
"flags": "i"
},
{
"pattern": "^(bug|fix|bugfix)$",
"target": "$1",
"flags": "i"
},
{
"pattern": "^(docs|documentation)$",
"target": "$1",
"flags": "i"
},
{
"pattern": "^(test|tests|qa)$",
"target": "$1",
"flags": "i"
},
{
"pattern": "^(chore|ci|build|dependencies|refactor)$",
"target": "$1",
"flags": "i"
},
{
"pattern": "^security$",
"target": "$0",
"flags": "i"
}
],
"autolabeler": [
{
"label": "docs",
"files": ["**/*.md", "docs/**"]
},
{
"label": "test",
"files": ["**/*test*/**", "**/*tests*/**", "**/*.tests/**", "**/*.Tests/**"]
},
{
"label": "ci",
"files": [".github/workflows/**"]
}
]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload NuGet Artifacts
uses: actions/upload-artifact@v7
with:
name: nuget-packages-${{ steps.version.outputs.VERSION }}
path: ./artifacts/*.nupkg
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.TAG }}
name: FluentAAS ${{ steps.version.outputs.VERSION }}
body: ${{ steps.build_changelog.outputs.changelog || 'Release notes will be added here.' }}
files: ./artifacts/*.nupkg
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}