Add TechnicalDataBuilder with ECLASS/IEC-61360 validation and Templat… #16
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 }} |