Skip to content

Commit 3b5e1c4

Browse files
committed
Add CI/CD workflows for build, test, and release
Introduces GitHub Actions workflows for building, testing, and releasing the FFmpeg Installer. Includes 'build-release.yml' for tagged releases, 'build-test.yml' for CI on main and PRs, and a README with usage and customization instructions.
1 parent 89ab959 commit 3b5e1c4

File tree

3 files changed

+346
-0
lines changed

3 files changed

+346
-0
lines changed

.github/workflows/README.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# GitHub Actions Workflows
2+
3+
This directory contains CI/CD workflows for the FFmpeg Installer project.
4+
5+
## Workflows
6+
7+
### 1. Build and Release (`build-release.yml`)
8+
9+
**Trigger**: Push a version tag (e.g., `v2.5.0`)
10+
11+
**Purpose**: Automatically builds the installer and creates a draft GitHub release.
12+
13+
**What it does**:
14+
- ✅ Builds the FFmpeg Installer as a single-file executable
15+
- ✅ Generates release notes from commit history
16+
- ✅ Calculates SHA256 checksums for security verification
17+
- ✅ Creates a draft release with the executable and zip archive
18+
- ✅ Uploads build artifacts for 30 days
19+
20+
**How to use**:
21+
22+
```bash
23+
# Create and push a version tag
24+
git tag v2.5.0
25+
git push origin v2.5.0
26+
27+
# Or create an annotated tag with message
28+
git tag -a v2.5.0 -m "Release version 2.5.0 - Added build selection feature"
29+
git push origin v2.5.0
30+
```
31+
32+
After the workflow completes:
33+
1. Go to [Releases](../../releases)
34+
2. Find the draft release
35+
3. Review the release notes and artifacts
36+
4. Edit if needed
37+
5. Click "Publish release" when ready
38+
39+
### 2. Build and Test (`build-test.yml`)
40+
41+
**Trigger**:
42+
- Push to `main` branch
43+
- Pull requests to `main` branch
44+
45+
**Purpose**: Continuous integration testing to ensure builds work correctly.
46+
47+
**What it does**:
48+
- ✅ Builds the project in Debug and Release configurations
49+
- ✅ Verifies the executable is created successfully
50+
- ✅ Uploads build artifacts for commits to main branch
51+
- ✅ Runs on every PR to catch issues early
52+
53+
## Version Tag Format
54+
55+
Use semantic versioning with a `v` prefix:
56+
- `v2.5.0` - Major.Minor.Patch
57+
- `v3.0.0` - Major version bump
58+
- `v2.5.1` - Patch release
59+
60+
The workflow extracts the version (removes the `v`) for file naming.
61+
62+
## Requirements
63+
64+
These workflows require:
65+
- **Windows runner**: Builds .NET Windows Forms application
66+
- **.NET 6.0 SDK**: Automatically installed by the workflow
67+
- **GitHub token**: Automatically provided (`GITHUB_TOKEN`)
68+
69+
## Artifacts
70+
71+
The workflows produce:
72+
- `FFmpegInstaller.exe` - Standalone executable
73+
- `FFmpegInstaller-{version}.zip` - Compressed archive
74+
- `checksums.txt` - SHA256 hashes for verification
75+
- `release_notes.md` - Generated release notes
76+
77+
## Customization
78+
79+
### Change retention period:
80+
Edit the `retention-days` value in the workflow files.
81+
82+
### Add more build configurations:
83+
Add additional `dotnet publish` commands with different runtime identifiers:
84+
```yaml
85+
- dotnet publish -r win-x86 # 32-bit Windows
86+
- dotnet publish -r win-arm64 # ARM64 Windows
87+
```
88+
89+
### Auto-publish releases:
90+
Change `draft: true` to `draft: false` in `build-release.yml` to auto-publish.
91+
92+
## Troubleshooting
93+
94+
### Build fails with "FFmpegInstaller.exe not found"
95+
- Check that the project file is named `FFmpegInstaller.csproj`
96+
- Verify the output path in the publish command
97+
98+
### Release not created
99+
- Ensure you have `contents: write` permission
100+
- Check that the tag follows the `v*.*.*` format
101+
- Verify the `GITHUB_TOKEN` has sufficient permissions
102+
103+
### Wrong version in release
104+
- Check that your tag follows semantic versioning
105+
- The version is extracted from the tag name (removes `v` prefix)
106+
107+
## Example Workflow Run
108+
109+
```bash
110+
# 1. Make your changes and commit
111+
git add .
112+
git commit -m "Add new feature X"
113+
git push origin main
114+
115+
# 2. Create and push version tag
116+
git tag v2.5.0
117+
git push origin v2.5.0
118+
119+
# 3. Workflow automatically:
120+
# - Builds the installer
121+
# - Creates draft release
122+
# - Uploads FFmpegInstaller.exe
123+
# - Generates checksums
124+
125+
# 4. Review and publish the draft release on GitHub
126+
```
127+
128+
## Notes
129+
130+
- The installer always downloads the **latest FFmpeg version** from gyan.dev, regardless of when it was built
131+
- Workflows run on GitHub-hosted Windows runners (free for public repositories)
132+
- Build artifacts are stored for 7-30 days depending on the workflow
133+
- Draft releases allow you to test before publishing to users
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
name: Build and Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*.*.*' # Triggers on version tags like v2.5.0, v3.0.1, etc.
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build-and-release:
13+
runs-on: windows-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Extract version from tag
22+
id: get_version
23+
shell: pwsh
24+
run: |
25+
$tag = "${{ github.ref_name }}"
26+
$version = $tag -replace '^v', ''
27+
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
28+
echo "TAG=$tag" >> $env:GITHUB_OUTPUT
29+
echo "Version: $version"
30+
31+
- name: Setup .NET
32+
uses: actions/setup-dotnet@v4
33+
with:
34+
dotnet-version: '6.0.x'
35+
36+
- name: Restore dependencies
37+
run: dotnet restore FFmpegInstaller.csproj
38+
39+
- name: Build application
40+
run: |
41+
dotnet publish FFmpegInstaller.csproj `
42+
-c Release `
43+
-r win-x64 `
44+
--self-contained false `
45+
-p:PublishSingleFile=true `
46+
-p:PublishReadyToRun=false `
47+
-p:PublishTrimmed=false `
48+
-o ./publish
49+
50+
- name: Verify build output
51+
shell: pwsh
52+
run: |
53+
if (Test-Path "./publish/FFmpegInstaller.exe") {
54+
Write-Host "✓ FFmpegInstaller.exe found"
55+
$fileSize = (Get-Item "./publish/FFmpegInstaller.exe").Length / 1MB
56+
Write-Host "File size: $($fileSize.ToString('F2')) MB"
57+
} else {
58+
Write-Error "FFmpegInstaller.exe not found!"
59+
exit 1
60+
}
61+
62+
- name: Create release archive
63+
shell: pwsh
64+
run: |
65+
Compress-Archive -Path "./publish/FFmpegInstaller.exe" `
66+
-DestinationPath "./FFmpegInstaller-${{ steps.get_version.outputs.VERSION }}.zip"
67+
68+
# Also keep the standalone exe
69+
Copy-Item "./publish/FFmpegInstaller.exe" `
70+
"./FFmpegInstaller.exe"
71+
72+
- name: Generate release notes
73+
id: release_notes
74+
shell: pwsh
75+
run: |
76+
$version = "${{ steps.get_version.outputs.VERSION }}"
77+
78+
# Get commit messages since last tag
79+
$lastTag = git describe --tags --abbrev=0 HEAD^ 2>$null
80+
81+
if ($lastTag) {
82+
$commits = git log "$lastTag..HEAD" --pretty=format:"- %s" --no-merges
83+
} else {
84+
$commits = git log --pretty=format:"- %s" --no-merges -10
85+
}
86+
87+
$notes = @"
88+
## FFmpeg Installer v$version
89+
90+
**Full Changelog**: https://github.com/${{ github.repository }}/compare/$lastTag...${{ steps.get_version.outputs.TAG }}
91+
"@
92+
93+
# Save to file for GitHub release
94+
$notes | Out-File -FilePath release_notes.md -Encoding utf8
95+
96+
Write-Host "Release notes generated successfully"
97+
98+
- name: Calculate checksums
99+
shell: pwsh
100+
run: |
101+
# Calculate SHA256 for the exe
102+
$exeHash = (Get-FileHash -Path "./FFmpegInstaller.exe" -Algorithm SHA256).Hash
103+
Write-Host "FFmpegInstaller.exe SHA256: $exeHash"
104+
105+
# Calculate SHA256 for the zip
106+
$zipHash = (Get-FileHash -Path "./FFmpegInstaller-${{ steps.get_version.outputs.VERSION }}.zip" -Algorithm SHA256).Hash
107+
Write-Host "FFmpegInstaller.zip SHA256: $zipHash"
108+
109+
# Save checksums to file
110+
@"
111+
# SHA256 Checksums
112+
113+
``````
114+
$exeHash FFmpegInstaller.exe
115+
$zipHash FFmpegInstaller-${{ steps.get_version.outputs.VERSION }}.zip
116+
``````
117+
"@ | Out-File -FilePath checksums.txt -Encoding utf8
118+
119+
# Append to release notes
120+
Get-Content checksums.txt | Out-File -FilePath release_notes.md -Append -Encoding utf8
121+
122+
- name: Create Draft Release
123+
uses: softprops/action-gh-release@v2
124+
with:
125+
draft: true
126+
prerelease: false
127+
name: "FFmpeg Installer v${{ steps.get_version.outputs.VERSION }}"
128+
tag_name: ${{ steps.get_version.outputs.TAG }}
129+
body_path: release_notes.md
130+
files: |
131+
FFmpegInstaller.exe
132+
FFmpegInstaller-${{ steps.get_version.outputs.VERSION }}.zip
133+
checksums.txt
134+
env:
135+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
136+
137+
- name: Upload build artifacts
138+
uses: actions/upload-artifact@v4
139+
with:
140+
name: ffmpeg-installer-v${{ steps.get_version.outputs.VERSION }}
141+
path: |
142+
FFmpegInstaller.exe
143+
FFmpegInstaller-${{ steps.get_version.outputs.VERSION }}.zip
144+
checksums.txt
145+
release_notes.md
146+
retention-days: 30

.github/workflows/build-test.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Build and Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths-ignore:
8+
- '**.md'
9+
- 'LICENSE'
10+
- '.gitignore'
11+
pull_request:
12+
branches:
13+
- main
14+
paths-ignore:
15+
- '**.md'
16+
- 'LICENSE'
17+
- '.gitignore'
18+
19+
jobs:
20+
build:
21+
runs-on: windows-latest
22+
23+
steps:
24+
- name: Checkout code
25+
uses: actions/checkout@v4
26+
27+
- name: Setup .NET
28+
uses: actions/setup-dotnet@v4
29+
with:
30+
dotnet-version: '6.0.x'
31+
32+
- name: Restore dependencies
33+
run: dotnet restore FFmpegInstaller.csproj
34+
35+
- name: Build application (Debug)
36+
run: dotnet build FFmpegInstaller.csproj -c Debug --no-restore
37+
38+
- name: Build application (Release)
39+
run: |
40+
dotnet publish FFmpegInstaller.csproj `
41+
-c Release `
42+
-r win-x64 `
43+
--self-contained false `
44+
-p:PublishSingleFile=true `
45+
-p:PublishReadyToRun=false `
46+
-p:PublishTrimmed=false `
47+
-o ./publish
48+
49+
- name: Verify build output
50+
shell: pwsh
51+
run: |
52+
if (Test-Path "./publish/FFmpegInstaller.exe") {
53+
Write-Host "✓ Build successful - FFmpegInstaller.exe created"
54+
$fileSize = (Get-Item "./publish/FFmpegInstaller.exe").Length / 1MB
55+
Write-Host "File size: $($fileSize.ToString('F2')) MB"
56+
} else {
57+
Write-Error "Build failed - FFmpegInstaller.exe not found!"
58+
exit 1
59+
}
60+
61+
- name: Upload build artifact
62+
uses: actions/upload-artifact@v4
63+
if: github.event_name == 'push'
64+
with:
65+
name: ffmpeg-installer-build-${{ github.sha }}
66+
path: ./publish/FFmpegInstaller.exe
67+
retention-days: 7

0 commit comments

Comments
 (0)