Improving CICD #4
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: CI | |
| permissions: | |
| contents: write | |
| packages: write | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| push: | |
| tags: | |
| - 'v*.*.*' | |
| jobs: | |
| build: | |
| name: Restore, Build and Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v3 | |
| with: | |
| dotnet-version: '10.x' | |
| - name: Restore | |
| run: dotnet restore | |
| - name: Build | |
| run: dotnet build TenJames.CompMap.sln -c Release --no-restore | |
| - name: Test (if present) | |
| run: | | |
| if [ -d "TenJames.CompMap/TenJames.CompMap.Tests" ]; then | |
| dotnet test TenJames.CompMap/TenJames.CompMap.Tests -c Release --no-build --verbosity normal | |
| else | |
| echo "No tests found" | |
| fi | |
| bump-version: | |
| name: Bump package version (patch) on PR | |
| if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }} | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout (full) | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Bump package version (patch) in TenJames.CompMap.csproj | |
| id: bump | |
| run: | | |
| set -e | |
| csproj="TenJames.CompMap/TenJames.CompMap/TenJames.CompMap.csproj" | |
| if [ ! -f "$csproj" ]; then | |
| echo "CSProj not found: $csproj" | |
| exit 0 | |
| fi | |
| # extract version like 1.2.3 | |
| version=$(grep -oPm1 "(?<=<Version>)[^<]+" "$csproj" || true) | |
| if [ -z "$version" ]; then | |
| echo "No <Version> found in $csproj" | |
| exit 0 | |
| fi | |
| echo "Current version: $version" | |
| IFS='.' read -r major minor patch <<< "$version" | |
| if [ -z "$patch" ]; then | |
| echo "Version format unexpected: $version" | |
| exit 1 | |
| fi | |
| new_patch=$((patch + 1)) | |
| new_version="${major}.${minor}.${new_patch}" | |
| # update the csproj | |
| sed -i "s|<Version>${version}</Version>|<Version>${new_version}</Version>|" "$csproj" | |
| git add "$csproj" | |
| git commit -m "ci: bump version to ${new_version} [skip ci]" || echo "No changes to commit" | |
| # push back to the PR branch | |
| git push origin HEAD:refs/heads/${{ github.event.pull_request.head.ref }} || echo "Push failed (maybe from a fork)" | |
| echo "new_version=${new_version}" >> $GITHUB_OUTPUT | |
| publish: | |
| name: Pack, update csproj and publish on tag | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v3 | |
| with: | |
| dotnet-version: '10.x' | |
| - name: Determine package version from tag | |
| id: vars | |
| run: | | |
| TAG=${GITHUB_REF#refs/tags/} | |
| VERSION=${TAG#v} | |
| echo "tag=${TAG}" >> $GITHUB_OUTPUT | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| - name: Configure Git for pushing | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Update csproj version and push to default branch | |
| env: | |
| VERSION: ${{ steps.vars.outputs.version }} | |
| TAG: ${{ steps.vars.outputs.tag }} | |
| run: | | |
| set -e | |
| csproj="TenJames.CompMap/TenJames.CompMap/TenJames.CompMap.csproj" | |
| if [ ! -f "$csproj" ]; then | |
| echo "CSProj not found: $csproj" | |
| exit 0 | |
| fi | |
| default_branch="${{ github.event.repository.default_branch }}" | |
| echo "Default branch is: $default_branch" | |
| # create a new branch from default branch to avoid push-to-protected-branch issues | |
| git fetch origin $default_branch | |
| branch_name="ci/bump-version-${{ steps.vars.outputs.version }}" | |
| git checkout -b "$branch_name" origin/$default_branch || git checkout -b "$branch_name" | |
| current=$(grep -oPm1 "(?<=<Version>)[^<]+" "$csproj" || true) | |
| echo "Current csproj version: ${current}" | |
| echo "Desired version: ${VERSION}" | |
| if [ "${current}" != "${VERSION}" ]; then | |
| if grep -q "<Version>" "$csproj"; then | |
| sed -i "s|<Version>.*</Version>|<Version>${VERSION}</Version>|" "$csproj" | |
| else | |
| # insert Version element after the first PropertyGroup using perl to avoid quoting issues | |
| perl -0777 -pe "s/(<PropertyGroup>\s*)/$1 <Version>${VERSION}<\/Version>\n/s if !/<Version>/s" -i "$csproj" | |
| fi | |
| git add "$csproj" | |
| git commit -m "chore: set package version to ${VERSION} (tag ${TAG}) [skip ci]" || echo "No changes to commit" | |
| git push --set-upstream origin "$branch_name" || echo "Push failed" | |
| echo "branch_name=${branch_name}" >> $GITHUB_OUTPUT | |
| else | |
| echo "CSProj already matches tag version" | |
| fi | |
| - name: Create Pull Request for version update | |
| uses: actions/github-script@v7 | |
| env: | |
| VERSION: ${{ steps.vars.outputs.version }} | |
| TAG: ${{ steps.vars.outputs.tag }} | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const headBranch = `ci/bump-version-${process.env.VERSION}`; | |
| const base = `${{ github.event.repository.default_branch }}`; | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const title = `chore: set package version to ${process.env.VERSION} (tag ${process.env.TAG})`; | |
| const body = `This PR updates TenJames.CompMap.csproj version to ${process.env.VERSION} (created by release workflow for tag ${process.env.TAG}).`; | |
| // Check for existing open PR from the same head | |
| const existing = await github.pulls.list({ owner, repo, head: `${owner}:${headBranch}`, state: 'open' }); | |
| if (existing.data && existing.data.length > 0) { | |
| console.log(`Found existing PR: ${existing.data[0].html_url}`); | |
| } else { | |
| const pr = await github.pulls.create({ owner, repo, title, head: headBranch, base, body }); | |
| console.log(`Created PR: ${pr.data.html_url}`); | |
| } | |
| - name: Pack | |
| run: | | |
| dotnet pack TenJames.CompMap/TenJames.CompMap/TenJames.CompMap.csproj -c Release -o ./nupkgs /p:PackageVersion=${{ steps.vars.outputs.version }} | |
| - name: Find generated nupkg | |
| id: find_pkg | |
| run: | | |
| set -e | |
| pkg=$(ls ./nupkgs/*.nupkg | head -n1 || true) | |
| if [ -z "$pkg" ]; then | |
| echo "No nupkg found in ./nupkgs" | |
| exit 1 | |
| fi | |
| echo "package_path=$pkg" >> $GITHUB_OUTPUT | |
| echo "package_name=$(basename $pkg)" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release for tag | |
| id: create_release | |
| uses: actions/create-release@v1 | |
| with: | |
| tag_name: ${{ steps.vars.outputs.tag }} | |
| release_name: ${{ steps.vars.outputs.tag }} | |
| body: Release for tag ${{ steps.vars.outputs.tag }} | |
| draft: false | |
| prerelease: false | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload nupkg to Release | |
| uses: actions/upload-release-asset@v1 | |
| with: | |
| upload_url: ${{ steps.create_release.outputs.upload_url }} | |
| asset_path: ${{ steps.find_pkg.outputs.package_path }} | |
| asset_name: ${{ steps.find_pkg.outputs.package_name }} | |
| asset_content_type: application/octet-stream | |
| - name: Publish to NuGet | |
| env: | |
| NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} | |
| run: | | |
| if [ -z "$NUGET_API_KEY" ]; then | |
| echo "NUGET_API_KEY not set - skipping publish" | |
| exit 0 | |
| fi | |
| dotnet nuget push ./nupkgs/*.nupkg -k "$NUGET_API_KEY" -s https://api.nuget.org/v3/index.json --skip-duplicate |