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
105 changes: 105 additions & 0 deletions .github/workflows/pr-build-dll.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: "PR - Build SourceGenerator DLL"

on:
pull_request:
paths-ignore:
- '**/*.md'
- '**/*.gitignore'
- '**/*.gitattributes'

permissions:
contents: read
pull-requests: write

jobs:
build-sourcegenerator:
name: Build and Upload SourceGenerator DLL
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true

steps:
- uses: actions/checkout@v4

- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
7.0.x

- name: Restore
run: dotnet restore

- name: Build SourceGenerator (Release)
run: dotnet build Arch.SystemGroups.SourceGenerator/Arch.SystemGroups.SourceGenerator.csproj --configuration Release --no-restore

- name: Upload SourceGenerator DLL
uses: actions/upload-artifact@v4
with:
name: Arch.SystemGroups.SourceGenerator-PR${{ github.event.pull_request.number }}-run${{ github.run_number }}
path: Arch.SystemGroups.SourceGenerator/bin/Release/netstandard2.0/Arch.SystemGroups.SourceGenerator.dll
retention-days: 30

- name: Comment on PR with artifact link
uses: actions/github-script@v7
with:
script: |
const artifactName = `Arch.SystemGroups.SourceGenerator-PR${{ github.event.pull_request.number }}-run${{ github.run_number }}`;
const runId = context.runId;
const runNumber = '${{ github.run_number }}';
const repo = context.repo;

const comment = `## ✅ SourceGenerator DLL Built Successfully

The SourceGenerator DLL has been built in Release mode and is available for download.

**📦 Download:** [${artifactName}](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})

### How to Download:
1. Click the link above (requires GitHub login)
2. Scroll to the "Artifacts" section at the bottom
3. Click the artifact name to download
4. **Extract the zip file** to get the DLL (GitHub artifacts are automatically zipped)

> **Note:** PR artifacts are zipped by GitHub. For direct DLL downloads without extraction, use the [Release workflow](https://github.com/${repo.owner}/${repo.repo}/actions/workflows/release.yaml) which attaches DLLs directly to releases.

**Build Details:**
- Configuration: Release
- Target Framework: netstandard2.0
- DLL: \`Arch.SystemGroups.SourceGenerator.dll\`
- Workflow Run: [#${runId}](https://github.com/${repo.owner}/${repo.repo}/actions/runs/${runId})
- Run Number: ${runNumber}
`;

// Check if we already commented
const { data: comments } = await github.rest.issues.listComments({
owner: repo.owner,
repo: repo.repo,
issue_number: context.issue.number,
});

const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('SourceGenerator DLL Built Successfully')
);

if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: repo.owner,
repo: repo.repo,
comment_id: botComment.id,
body: comment
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: repo.owner,
repo: repo.repo,
issue_number: context.issue.number,
body: comment
});
}
189 changes: 189 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: "Create Release"

on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v1.0.0)'
required: true
type: string
custom_description:
description: 'Custom release description (optional - leave empty to auto-generate from PRs)'
required: false
type: string
prerelease:
description: 'Mark as pre-release'
required: false
type: boolean
default: false

permissions:
contents: write
pull-requests: read

jobs:
create-release:
name: Build and Create Release
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for changelog generation

- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
7.0.x

- name: Restore
run: dotnet restore

- name: Build SourceGenerator (Release)
run: dotnet build Arch.SystemGroups.SourceGenerator/Arch.SystemGroups.SourceGenerator.csproj --configuration Release --no-restore

- name: Run Tests
run: dotnet test --configuration Release --no-restore --logger trx --results-directory "TestResults"

- name: Generate Release Notes
id: release_notes
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const customDescription = `${{ github.event.inputs.custom_description }}`;

// If custom description provided, use it
if (customDescription && customDescription.trim() !== '') {
return customDescription;
}

// Otherwise, generate from merged PRs
const repo = context.repo;

// Get the latest release
let lastReleaseDate;
try {
const { data: latestRelease } = await github.rest.repos.getLatestRelease({
owner: repo.owner,
repo: repo.repo,
});
lastReleaseDate = latestRelease.created_at;
} catch (error) {
// No previous release, use repo creation date or a far back date
lastReleaseDate = '2020-01-01T00:00:00Z';
}

// Get merged PRs since last release
const { data: pullRequests } = await github.rest.pulls.list({
owner: repo.owner,
repo: repo.repo,
state: 'closed',
sort: 'updated',
direction: 'desc',
per_page: 100
});

const mergedPRs = pullRequests.filter(pr =>
pr.merged_at &&
new Date(pr.merged_at) > new Date(lastReleaseDate)
);

if (mergedPRs.length === 0) {
return '## Changes\n\nNo merged pull requests since last release.';
}

// Group PRs by type based on title/labels
const features = [];
const bugFixes = [];
const other = [];

for (const pr of mergedPRs) {
const title = pr.title.toLowerCase();
const labels = pr.labels.map(l => l.name.toLowerCase());

const prLink = `- ${pr.title} (#${pr.number}) @${pr.user.login}`;

if (title.startsWith('feat') || labels.includes('enhancement') || labels.includes('feature')) {
features.push(prLink);
} else if (title.startsWith('fix') || labels.includes('bug') || labels.includes('bugfix')) {
bugFixes.push(prLink);
} else {
other.push(prLink);
}
}

// Build release notes
let notes = '## What\'s Changed\n\n';

if (features.length > 0) {
notes += '### ✨ Features\n' + features.join('\n') + '\n\n';
}

if (bugFixes.length > 0) {
notes += '### 🐛 Bug Fixes\n' + bugFixes.join('\n') + '\n\n';
}

if (other.length > 0) {
notes += '### 🔧 Other Changes\n' + other.join('\n') + '\n\n';
}

notes += `\n**Full Changelog**: https://github.com/${repo.owner}/${repo.repo}/compare/${lastReleaseDate.split('T')[0]}...${{ github.event.inputs.version }}`;

return notes;

- name: Create Release
uses: actions/github-script@v7
env:
RELEASE_NOTES: ${{ steps.release_notes.outputs.result }}
with:
script: |
const fs = require('fs');
const repo = context.repo;

// Create the release
const { data: release } = await github.rest.repos.createRelease({
owner: repo.owner,
repo: repo.repo,
tag_name: '${{ github.event.inputs.version }}',
name: '${{ github.event.inputs.version }}',
body: process.env.RELEASE_NOTES,
draft: false,
prerelease: ${{ github.event.inputs.prerelease }},
target_commitish: context.sha
});

console.log(`Release created: ${release.html_url}`);

// Upload the SourceGenerator DLL as a release asset
const dllPath = 'Arch.SystemGroups.SourceGenerator/bin/Release/netstandard2.0/Arch.SystemGroups.SourceGenerator.dll';
const dllContent = fs.readFileSync(dllPath);

await github.rest.repos.uploadReleaseAsset({
owner: repo.owner,
repo: repo.repo,
release_id: release.id,
name: 'Arch.SystemGroups.SourceGenerator.dll',
data: dllContent,
});

console.log('SourceGenerator DLL uploaded successfully');

// Also create a summary
await core.summary
.addHeading('Release Created Successfully! 🎉')
.addLink('View Release', release.html_url)
.addRaw('\n\n')
.addHeading('Release Details', 3)
.addList([
`Version: ${{ github.event.inputs.version }}`,
`Pre-release: ${{ github.event.inputs.prerelease }}`,
`Assets: Arch.SystemGroups.SourceGenerator.dll`
])
.write();
36 changes: 24 additions & 12 deletions .github/workflows/workflows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ name: "Continuous Integration"

on:
push:
branches:
- main
paths-ignore:
- '**/*.md'
- '**/*.gitignore'
Expand All @@ -15,13 +17,12 @@ on:
- '**/*.gitignore'
- '**/*.gitattributes'
workflow_dispatch:
branches:
- main
paths-ignore:
- '**/*.md'
- '**/*.gitignore'
- '**/*.gitattributes'


permissions:
contents: read
checks: write
pull-requests: write

jobs:
build:
name: Build Arch.SystemGroups
Expand All @@ -40,10 +41,10 @@ jobs:
fail-fast: false

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
Expand All @@ -58,10 +59,21 @@ jobs:
- name: Test
run: dotnet test --logger trx --results-directory "TestResults"

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: |
TestResults/**/*.trx
check_name: '.NET Test Results'
comment_title: '🧪 Test Results'
report_individual_runs: true
deduplicate_classes_by_file_name: false

- name: Upload dotnet test results
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: dotnet-results
name: dotnet-results-${{ github.run_number }}
path: TestResults
# Use always() to always run this step to publish test results when there are test failures
if: ${{ always() }}
Loading
Loading