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
410 changes: 410 additions & 0 deletions .github/workflows/wangamail-csharp.yml

Large diffs are not rendered by default.

365 changes: 365 additions & 0 deletions .github/workflows/wangapayfast-csharp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,365 @@
name: wangapayfast-csharp

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'wangapayfast-csharp/**'
- '.github/workflows/wangapayfast-csharp.yml'
push:
branches: [main]
paths:
- 'wangapayfast-csharp/**'
- '.github/workflows/wangapayfast-csharp.yml'
workflow_dispatch:

jobs:
format:
name: Format
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore
run: |
dotnet restore wangapayfast-csharp/WangaPayFast.CSharp.csproj
dotnet restore wangapayfast-csharp/tests/WangaPayFast.CSharp.Tests/WangaPayFast.CSharp.Tests.csproj
- name: Check formatting
run: dotnet format wangapayfast-csharp/WangaPayFast.CSharp.csproj --verify-no-changes --verbosity minimal
- name: Job summary
if: always()
run: |
echo "## Format" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY

build:
name: Build
runs-on: ubuntu-latest
needs: format
if: github.event_name == 'pull_request' || github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore
run: |
dotnet restore wangapayfast-csharp/WangaPayFast.CSharp.csproj
dotnet restore wangapayfast-csharp/tests/WangaPayFast.CSharp.Tests/WangaPayFast.CSharp.Tests.csproj
- name: Build
run: dotnet build wangapayfast-csharp/WangaPayFast.CSharp.csproj -c Release --no-restore
- name: Job summary
if: always()
run: |
echo "## Build" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY

test:
name: Test
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'pull_request' || github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore
run: |
dotnet restore wangapayfast-csharp/WangaPayFast.CSharp.csproj
dotnet restore wangapayfast-csharp/tests/WangaPayFast.CSharp.Tests/WangaPayFast.CSharp.Tests.csproj
- name: Test
run: dotnet test wangapayfast-csharp/tests/WangaPayFast.CSharp.Tests/WangaPayFast.CSharp.Tests.csproj -c Release --no-restore
- name: Job summary
if: always()
run: |
echo "## Test" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY

version-bump:
name: Bump Version
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
outputs:
version: ${{ steps.bump.outputs.new_version }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Get current version
id: current
run: |
python3 - <<'PY'
import re
from pathlib import Path
import os
text = Path("wangapayfast-csharp/WangaPayFast.CSharp.csproj").read_text(encoding="utf-8")
m = re.search(r"<Version>(\d+\.\d+\.\d+)</Version>", text)
if not m:
raise SystemExit("Error: Failed to extract Version from WangaPayFast.CSharp.csproj")
version = m.group(1)
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
f.write(f"version={version}\n")
print(f"Current version: {version}")
PY

- name: Bump patch version
id: bump
run: |
V="${{ steps.current.outputs.version }}"
IFS='.' read -r MAJOR MINOR PATCH <<< "$V"
PATCH=$((PATCH + 1))
NEW="${MAJOR}.${MINOR}.${PATCH}"
echo "new_version=$NEW" >> $GITHUB_OUTPUT
python3 - <<PY
import re
from pathlib import Path
NEW = "$NEW"
path = Path("wangapayfast-csharp/WangaPayFast.CSharp.csproj")
text = path.read_text(encoding="utf-8")
out, n = re.subn(r"<Version>\d+\.\d+\.\d+</Version>", f"<Version>{NEW}</Version>", text, count=1)
if n != 1:
raise SystemExit("Error: Failed to update Version in WangaPayFast.CSharp.csproj")
path.write_text(out, encoding="utf-8")
print(f"New version: {NEW}")
PY

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Commit and push version
run: |
git add wangapayfast-csharp/WangaPayFast.CSharp.csproj
if git diff --staged --quiet; then
echo "No version change to commit"
else
git commit -m "chore(wangapayfast-csharp): bump version to ${{ steps.bump.outputs.new_version }} [skip ci]"
git fetch origin main || true
git pull origin main --rebase || git pull origin main --no-rebase || true
git push origin main || git push origin main --force-with-lease
fi

- name: Job summary
if: always()
run: |
echo "## Bump Version" >> $GITHUB_STEP_SUMMARY
echo "**New version:** ${{ steps.bump.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY

get-version:
name: Get Version
runs-on: ubuntu-latest
needs: [version-bump]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Pull latest
run: git pull origin main || true

- name: Get version
id: version
run: |
V=$(python3 - <<'PY'
import re
from pathlib import Path
text = Path("wangapayfast-csharp/WangaPayFast.CSharp.csproj").read_text(encoding="utf-8")
m = re.search(r"<Version>(\d+\.\d+\.\d+)</Version>", text)
print(m.group(1) if m else "")
PY
)
if [ -z "$V" ]; then
echo "Error: Failed to extract version from csproj"
exit 1
fi
echo "version=$V" >> $GITHUB_OUTPUT
echo "Version: $V"

- name: Job summary
if: always()
run: |
echo "## Get Version" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY

publish:
name: Publish to NuGet
runs-on: ubuntu-latest
needs: [get-version]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Pull latest
run: git pull origin main || true

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Validate NuGet key
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
if [ -z "$NUGET_API_KEY" ]; then
echo "Error: NUGET_API_KEY is empty or not configured in repository secrets."
exit 1
fi

- name: Pack
run: dotnet pack wangapayfast-csharp/WangaPayFast.CSharp.csproj -c Release -o ./artifacts

- name: Publish package
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: Job summary
if: always()
run: |
echo "## Publish" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ needs.get-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY

release:
name: Create Release
runs-on: ubuntu-latest
needs: [get-version, publish]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Create tag and release
uses: softprops/action-gh-release@v2
with:
tag_name: wangapayfast-csharp-v${{ needs.get-version.outputs.version }}
name: wangapayfast-csharp v${{ needs.get-version.outputs.version }}
body: |
## wangapayfast-csharp ${{ needs.get-version.outputs.version }}
PayFast helpers for .NET services.
- [NuGet](https://www.nuget.org/packages/wangapayfast-csharp)
draft: false
prerelease: false

- name: Job summary
if: always()
run: |
echo "## Release" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
echo "**Tag:** wangapayfast-csharp-v${{ needs.get-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY

monitor-failures:
name: Monitor Failed Jobs
runs-on: ubuntu-latest
if: always() && failure()
needs: [format, build, test, version-bump, get-version, publish, release]
permissions:
contents: read
issues: write
actions: read
steps:
- uses: actions/checkout@v4

- name: Create failure issue
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: run } = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId
});

const { data: jobsData } = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId
});

const failedJobs = jobsData.jobs.filter(job =>
job.conclusion === 'failure' ||
job.conclusion === 'cancelled' ||
job.conclusion === 'timed_out'
);

if (failedJobs.length === 0) {
console.log('No failed jobs found');
return;
}

const branch = context.ref.replace('refs/heads/', '');
const title = `🚨 CI/CD Failure: wangapayfast-csharp - ${branch} branch`;

let body = `## CI/CD Pipeline Failure\n\n`;
body += `**Workflow:** [wangapayfast-csharp](${run.html_url})\n`;
body += `**Branch:** \`${branch}\`\n`;
body += `**Commit:** [${context.sha.substring(0, 7)}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/commit/${context.sha})\n`;
body += `**Triggered by:** @${context.actor}\n\n`;
body += `### Failed Jobs\n\n`;
for (const job of failedJobs) {
body += `- ❌ [${job.name}](${job.html_url}) (${job.conclusion})\n`;
}
body += `\n---\n*Automatically created by workflow monitor.*\n`;

const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'ci-failure,wangapayfast-csharp'
});

const existingIssue = issues.find(issue =>
issue.title === title || issue.title.includes(`wangapayfast-csharp - ${branch}`)
);

if (existingIssue) {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body,
state: 'open'
});
} else {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: ['ci-failure', 'wangapayfast-csharp', 'bug', 'priority-high']
});
}

- name: Job summary
if: always()
run: |
echo "## Monitor Failed Jobs" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
Loading
Loading