This commit is contained in:
Tickbase
2025-05-18 01:28:42 +02:00
parent f9a5a00446
commit 3c26dd5eb9
4 changed files with 366 additions and 67 deletions

View File

@@ -24,12 +24,16 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install Rust
uses: actions-rs/toolchain@v1
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
toolchain: stable
profile: minimal
workspaces: 'src-tauri -> target'
cache-on-failure: true
- name: Install system dependencies
run: |

View File

@@ -17,16 +17,22 @@ on:
description: 'Custom release notes (leave empty for auto-generated)'
required: false
type: string
dry_run:
description: 'Perform a dry run (no actual release)'
required: false
default: false
type: boolean
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUST_BACKTRACE: short
jobs:
create-release:
version-bump:
runs-on: ubuntu-latest
outputs:
new_version: ${{ steps.version.outputs.new_version }}
release_id: ${{ steps.create_release.outputs.id }}
steps:
- uses: actions/checkout@v4
@@ -37,9 +43,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
cache: 'npm'
- name: Calculate New Version
id: version
@@ -100,10 +104,11 @@ jobs:
CHANGELOG="## Changes\n\n$COMMITS"
# Save changelog to a file (multiline to output)
echo "$CHANGELOG" > changelog.md
echo -e "$CHANGELOG" > changelog.md
echo "Generated changelog from commit messages"
- name: Commit Version Changes
if: ${{ !github.event.inputs.dry_run }}
env:
NEW_VERSION: ${{ steps.version.outputs.new_version }}
run: |
@@ -115,36 +120,41 @@ jobs:
git push origin HEAD:${GITHUB_REF#refs/heads/}
git push origin "v$NEW_VERSION"
- name: Create GitHub Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NEW_VERSION: ${{ steps.version.outputs.new_version }}
# Upload changelog as an artifact for the publish-release job
- name: Upload Changelog
uses: actions/upload-artifact@v4
with:
tag_name: v${{ steps.version.outputs.new_version }}
release_name: CreamLinux v${{ steps.version.outputs.new_version }}
body_path: ${{ github.event.inputs.custom_release_notes == '' && 'changelog.md' || github.event.inputs.custom_release_notes }}
draft: false
prerelease: false
name: changelog
path: changelog.md
retention-days: 1
build-linux:
needs: create-release
needs: version-bump
runs-on: ubuntu-latest
outputs:
appimage_path: ${{ steps.find-assets.outputs.appimage_path }}
deb_path: ${{ steps.find-assets.outputs.deb_path }}
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.create-release.outputs.new_version }}
ref: v${{ needs.version-bump.outputs.new_version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install Rust
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: 'src-tauri -> target'
cache-on-failure: true
- name: Install system dependencies
run: |
sudo apt-get update
@@ -153,25 +163,143 @@ jobs:
- name: Install frontend dependencies
run: npm install
- name: Quick lint and type-check
run: |
npm run lint
npx tsc --noEmit
- name: Build the app (optimized)
run: npm run tauri build
- name: Find build assets
id: find-assets
run: |
echo "appimage_path=$(find src-tauri/target/release/bundle/appimage -name "*.AppImage" | head -n 1)" >> $GITHUB_OUTPUT
echo "deb_path=$(find src-tauri/target/release/bundle/deb -name "*.deb" | head -n 1)" >> $GITHUB_OUTPUT
- name: Upload Linux builds as artifacts
uses: actions/upload-artifact@v4
with:
name: linux-builds
path: |
${{ steps.find-assets.outputs.appimage_path }}
${{ steps.find-assets.outputs.deb_path }}
retention-days: 1
# Build for other platforms in parallel if needed - examples:
build-windows:
needs: version-bump
runs-on: windows-latest
if: false # Disabled until we add Windows build support
outputs:
msi_path: ${{ steps.find-assets.outputs.msi_path }}
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.version-bump.outputs.new_version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: 'src-tauri -> target'
cache-on-failure: true
- name: Install frontend dependencies
run: npm install
- name: Build the app
run: npm run tauri build
- name: Upload AppImage
- name: Find build assets
id: find-assets
shell: bash
run: |
echo "msi_path=$(find src-tauri/target/release/bundle/msi -name "*.msi" | head -n 1)" >> $GITHUB_OUTPUT
- name: Upload Windows builds as artifacts
uses: actions/upload-artifact@v4
with:
name: windows-builds
path: |
${{ steps.find-assets.outputs.msi_path }}
retention-days: 1
# Final job to create the release and upload assets
publish-release:
needs: [version-bump, build-linux]
if: ${{ !github.event.inputs.dry_run }}
runs-on: ubuntu-latest
steps:
- name: Download changelog
uses: actions/download-artifact@v4
with:
name: changelog
- name: Download Linux builds
uses: actions/download-artifact@v4
with:
name: linux-builds
path: dist
# Add this step if Windows builds are enabled
# - name: Download Windows builds
# if: needs.build-windows.result == 'success'
# uses: actions/download-artifact@v4
# with:
# name: windows-builds
# path: dist
- name: Check downloaded artifacts
run: |
echo "Contents of dist directory:"
find dist -type f | sort
- name: Create GitHub Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NEW_VERSION: ${{ needs.version-bump.outputs.new_version }}
with:
tag_name: v${{ needs.version-bump.outputs.new_version }}
release_name: CreamLinux v${{ needs.version-bump.outputs.new_version }}
body_path: ${{ github.event.inputs.custom_release_notes == '' && 'changelog.md' || github.event.inputs.custom_release_notes }}
draft: false
prerelease: false
- name: Get filenames
id: get_filenames
run: |
echo "appimage_filename=$(basename $(find dist -name '*.AppImage' | head -n 1))" >> $GITHUB_OUTPUT
echo "deb_filename=$(basename $(find dist -name '*.deb' | head -n 1))" >> $GITHUB_OUTPUT
- name: Upload AppImage to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.release_id }}
asset_path: ./src-tauri/target/release/bundle/appimage/*.AppImage
asset_name: CreamLinux-${{ needs.create-release.outputs.new_version }}.AppImage
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/${{ steps.get_filenames.outputs.appimage_filename }}
asset_name: CreamLinux-${{ needs.version-bump.outputs.new_version }}.AppImage
asset_content_type: application/octet-stream
- name: Upload Debian Package
- name: Upload Debian Package to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.release_id }}
asset_path: ./src-tauri/target/release/bundle/deb/*.deb
asset_name: creamlinux_${{ needs.create-release.outputs.new_version }}_amd64.deb
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/${{ steps.get_filenames.outputs.deb_filename }}
asset_name: creamlinux_${{ needs.version-bump.outputs.new_version }}_amd64.deb
asset_content_type: application/vnd.debian.binary-package

View File

@@ -18,6 +18,7 @@ To use the release automation, you need:
- Git installed locally
- GitHub CLI installed and authenticated
- Proper GitHub permissions on the repository
- Optional: `act` for local testing (https://github.com/nektos/act)
## Starting a Release
@@ -44,6 +45,36 @@ npm run release minor "Added DLC management feature and improved UI"
If you don't provide custom notes, they will be automatically generated from commit messages since the last release.
### Advanced Options
The release script supports several advanced options:
#### Dry Run
Run the release process without actually creating a release:
```bash
npm run release patch --dry-run
```
This will perform all the version incrementing and workflow steps but won't create the actual GitHub release.
#### Local Testing
Test the workflow locally before running it on GitHub:
```bash
npm run release minor --local
```
This requires the `act` tool to be installed (https://github.com/nektos/act) and runs the workflow locally to check for errors.
You can combine options:
```bash
npm run release patch --local --dry-run
```
### Method 2: Manually triggering the workflow in GitHub
You can also manually trigger the workflow from the GitHub Actions tab:
@@ -54,7 +85,8 @@ You can also manually trigger the workflow from the GitHub Actions tab:
4. Click "Run workflow"
5. Choose the version increment type (patch, minor, major)
6. Optionally enter custom release notes
7. Click "Run workflow"
7. Check the "dry run" option if you want to test without creating a release
8. Click "Run workflow"
## Release Process Details
@@ -70,10 +102,19 @@ The release process follows these steps:
- Commits the version changes
- Creates a version tag
- Pushes the changes and tag to the repository
5. **Release Creation**: Creates a GitHub Release with the changelog
6. **Build Process**: Builds the application for Linux
5. **Build Process**: Builds the application for Linux (and potentially other platforms)
6. **Release Creation**: Creates a GitHub Release with the changelog after all builds are complete
7. **Asset Upload**: Uploads the AppImage and Debian package to the release
## Optimizations
The release workflow includes several optimizations:
- **Caching**: Uses Rust and npm caches to speed up build times
- **Parallel Builds**: Builds for different platforms in parallel
- **Artifact Management**: Properly manages build artifacts between jobs
- **Error Handling**: Improves error detection and reporting
## Release Artifacts
The following artifacts are published to the GitHub release:
@@ -94,7 +135,15 @@ CreamLinux follows [Semantic Versioning](https://semver.org/):
If you encounter issues with the release process:
1. **Check GitHub Actions logs**: Review the workflow logs for detailed error information
2. **Verify permissions**: Ensure you have write permissions to the repository
3. **GitHub CLI authentication**: Run `gh auth status` to verify authentication
2. **Use local testing**: Run with `--local` flag to test locally before triggering on GitHub
3. **Try dry run mode**: Use `--dry-run` to test the process without creating an actual release
4. **Verify permissions**: Ensure you have write permissions to the repository
5. **GitHub CLI authentication**: Run `gh auth status` to verify authentication
Common errors:
- **"act not found"**: Install the `act` tool for local testing
- **Upload errors**: Check if the build produced the expected artifacts
- **Permission errors**: Check GitHub permissions and token access
For technical issues with the release workflow, contact the CreamLinux maintainers.

View File

@@ -5,12 +5,19 @@
* This script helps automate the release process by triggering the GitHub Actions workflow
*
* Usage:
* node scripts/release.js [patch|minor|major] [release notes]
* node scripts/release.js [patch|minor|major] [options] [release notes]
*
* Options:
* --dry-run Perform a dry run (no actual release)
* --local Test the workflow locally with act before running on GitHub
* --help Show help message
*
* Examples:
* node scripts/release.js patch
* node scripts/release.js minor "Added new feature X"
* node scripts/release.js major "Major redesign with new UI"
* node scripts/release.js patch --dry-run
* node scripts/release.js minor --local
*/
import { execSync } from 'child_process'
@@ -20,17 +27,36 @@ import path from 'path'
// Configuration
const GITHUB_WORKFLOW_NAME = 'release.yml'
// Check if act is installed for local testing
function isActInstalled() {
try {
execSync('act --version', { stdio: 'ignore' })
return true
} catch (error) {
return false
}
}
// Validate environment
function validateEnvironment() {
function validateEnvironment(isLocal) {
try {
// Check if git is installed
execSync('git --version', { stdio: 'ignore' })
// Check if GitHub CLI is installed
execSync('gh --version', { stdio: 'ignore' })
if (!isLocal) {
// Check if GitHub CLI is installed
execSync('gh --version', { stdio: 'ignore' })
// Check if the user is authenticated with GitHub CLI
execSync('gh auth status', { stdio: 'ignore' })
// Check if the user is authenticated with GitHub CLI
execSync('gh auth status', { stdio: 'ignore' })
} else {
// Check if act is installed for local testing
if (!isActInstalled()) {
console.error('Error: "act" is required for local testing but is not installed.')
console.error('You can install it from: https://github.com/nektos/act')
process.exit(1)
}
}
// Check if we're in a git repository
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' })
@@ -59,10 +85,9 @@ function validateEnvironment() {
function parseArguments() {
const args = process.argv.slice(2)
if (args.length === 0) {
console.error('Error: Missing version type argument')
if (args.length === 0 || args[0] === '--help') {
showUsage()
process.exit(1)
process.exit(args[0] === '--help' ? 0 : 1)
}
const versionType = args[0].toLowerCase()
@@ -72,38 +97,92 @@ function parseArguments() {
process.exit(1)
}
// Join remaining arguments as release notes
const releaseNotes = args.slice(1).join(' ')
// Extract options
const options = {
dryRun: args.includes('--dry-run'),
localTest: args.includes('--local'),
}
return { versionType, releaseNotes }
// Join remaining arguments as release notes (excluding options)
const releaseNotes = args
.slice(1)
.filter((arg) => !arg.startsWith('--'))
.join(' ')
return { versionType, releaseNotes, options }
}
// Show usage information
function showUsage() {
console.log('Usage: node scripts/release.js [patch|minor|major] [release notes]')
console.log('Usage: node scripts/release.js [patch|minor|major] [options] [release notes]')
console.log('')
console.log('Options:')
console.log(' --dry-run Perform a dry run (no actual release)')
console.log(' --local Test the workflow locally with act before running on GitHub')
console.log(' --help Show this help message')
console.log('')
console.log('Examples:')
console.log(' node scripts/release.js patch')
console.log(' node scripts/release.js minor "Added new feature X"')
console.log(' node scripts/release.js major "Major redesign with new UI"')
console.log(' node scripts/release.js patch --dry-run')
console.log(' node scripts/release.js minor --local')
}
// Run local test with act
function runLocalTest(versionType, releaseNotes) {
console.log('\n=== Running local workflow test with act ===')
try {
const actCommand = `act workflow_dispatch -j version-bump -e ./scripts/test-event.json`
// First create the test event JSON
const testEvent = {
inputs: {
version_type: versionType,
custom_release_notes: releaseNotes || '',
dry_run: true,
},
}
// Write the test event to a file
const fs = require('fs')
fs.writeFileSync('./scripts/test-event.json', JSON.stringify(testEvent, null, 2))
console.log('Running local test with act (this might take a while)...')
execSync(actCommand, { stdio: 'inherit' })
// Clean up
fs.unlinkSync('./scripts/test-event.json')
console.log('\n✅ Local test completed successfully!')
return true
} catch (error) {
console.error(`❌ Local test failed: ${error.message}`)
return false
}
}
// Trigger GitHub workflow
function triggerWorkflow(versionType, releaseNotes) {
function triggerWorkflow(versionType, releaseNotes, isDryRun) {
try {
console.log(`Triggering release workflow with version type: ${versionType}`)
console.log(
`Triggering release workflow with version type: ${versionType}${isDryRun ? ' (dry run)' : ''}`
)
const command = releaseNotes
? `gh workflow run ${GITHUB_WORKFLOW_NAME} -f version_type=${versionType} -f custom_release_notes="${releaseNotes}"`
: `gh workflow run ${GITHUB_WORKFLOW_NAME} -f version_type=${versionType}`
let command = `gh workflow run ${GITHUB_WORKFLOW_NAME} -f version_type=${versionType} -f dry_run=${isDryRun}`
if (releaseNotes) {
command += ` -f custom_release_notes="${releaseNotes}"`
}
execSync(command, { stdio: 'inherit' })
console.log('\nRelease workflow triggered successfully!')
console.log('\nRelease workflow triggered successfully!')
console.log('You can check the progress in the Actions tab of your GitHub repository.')
console.log('https://github.com/Novattz/rust-gui-dev/actions')
console.log('https://github.com/yourusername/creamlinux/actions')
} catch (error) {
console.error(`Failed to trigger workflow: ${error.message}`)
console.error(`Failed to trigger workflow: ${error.message}`)
process.exit(1)
}
}
@@ -112,23 +191,62 @@ function triggerWorkflow(versionType, releaseNotes) {
function main() {
console.log('=== CreamLinux Release Script ===\n')
validateEnvironment()
const { versionType, releaseNotes } = parseArguments()
const { versionType, releaseNotes, options } = parseArguments()
console.log(`Version type: ${versionType}`)
// Validate environment based on mode
validateEnvironment(options.localTest)
console.log(`Version type: ${versionType} (${options.dryRun ? 'dry run' : 'actual release'})`)
if (releaseNotes) {
console.log(`Release notes: "${releaseNotes}"`)
} else {
console.log('Release notes: Auto-generated from commit messages')
}
// Confirm with user
console.log('\nThis will trigger a GitHub Actions workflow to create a new release.')
console.log('Press Ctrl+C to cancel or wait 5 seconds to continue...')
if (options.localTest) {
// Run local test first
const success = runLocalTest(versionType, releaseNotes)
setTimeout(() => {
triggerWorkflow(versionType, releaseNotes)
}, 5000)
if (options.localTest) {
// Run local test first
const success = runLocalTest(versionType, releaseNotes)
if (!success) {
console.error('\nLocal test failed. Fix the issues before running on GitHub.')
process.exit(1)
}
// If it was just a local test, exit here
if (options.dryRun) {
console.log(
'\nLocal test completed successfully. Exiting without triggering GitHub workflow.'
)
process.exit(0)
}
// Ask if user wants to continue with actual GitHub workflow
console.log('\nLocal test passed! Do you want to trigger the actual GitHub workflow?')
console.log('Press Ctrl+C to cancel or wait 5 seconds to continue...')
return new Promise((resolve) => {
setTimeout(() => {
triggerWorkflow(versionType, releaseNotes, options.dryRun)
resolve()
}, 5000)
})
} else {
// No local test, just confirm and trigger workflow
console.log('\nThis will trigger a GitHub Actions workflow to create a new release.')
console.log('Press Ctrl+C to cancel or wait 5 seconds to continue...')
return new Promise((resolve) => {
setTimeout(() => {
triggerWorkflow(versionType, releaseNotes, options.dryRun)
resolve()
}, 5000)
})
}
}
}
main()