diff --git a/.github/scripts/generate-release-notes.js b/.github/scripts/generate-release-notes.js new file mode 100644 index 0000000..08550c6 --- /dev/null +++ b/.github/scripts/generate-release-notes.js @@ -0,0 +1,176 @@ +#!/usr/bin/env node + +import { execSync } from "child_process"; +import fs from "fs"; + +function getCommitsSinceLastTag() { + try { + // Get the last tag + const lastTag = execSync("git describe --tags --abbrev=0 2>/dev/null", { + encoding: "utf8", + }).trim(); + + // Get commits since last tag + const commits = execSync(`git log ${lastTag}..HEAD --pretty=format:"%s"`, { + encoding: "utf8", + }).trim(); + + return commits ? commits.split("\n") : []; + } catch (error) { + // If no tags exist, get all commits from the beginning + try { + const commits = execSync('git log --pretty=format:"%s"', { + encoding: "utf8", + }).trim(); + + return commits ? commits.split("\n") : []; + } catch (e) { + return []; + } + } +} + +function categorizeCommits(commits) { + const categories = { + features: [], + fixes: [], + improvements: [], + chores: [], + breaking: [], + other: [] + }; + + commits.forEach(commit => { + // Skip auto-increment commits + if (commit.includes("🤖 Auto-increment version")) { + return; + } + + const lowerCommit = commit.toLowerCase(); + + if (lowerCommit.includes("breaking") || lowerCommit.includes("breaking change")) { + categories.breaking.push(commit); + } else if (lowerCommit.startsWith("feat:") || lowerCommit.startsWith("feature:") || lowerCommit.includes("add ")) { + categories.features.push(commit); + } else if (lowerCommit.startsWith("fix:") || lowerCommit.startsWith("bug:") || lowerCommit.includes("fix ")) { + categories.fixes.push(commit); + } else if (lowerCommit.startsWith("improve:") || lowerCommit.startsWith("enhancement:") || lowerCommit.includes("improve ")) { + categories.improvements.push(commit); + } else if (lowerCommit.startsWith("chore:") || lowerCommit.startsWith("ci:") || lowerCommit.startsWith("docs:")) { + categories.chores.push(commit); + } else { + categories.other.push(commit); + } + }); + + return categories; +} + +function generateReleaseNotes(version, categories) { + let notes = `# Release ${version}\n\n`; + + // Add date + const date = new Date().toISOString().split('T')[0]; + notes += `**Release Date:** ${date}\n\n`; + + // Breaking changes (if any) + if (categories.breaking.length > 0) { + notes += "## ⚠️ Breaking Changes\n\n"; + categories.breaking.forEach(commit => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Features + if (categories.features.length > 0) { + notes += "## ✨ New Features\n\n"; + categories.features.forEach(commit => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Bug fixes + if (categories.fixes.length > 0) { + notes += "## 🐛 Bug Fixes\n\n"; + categories.fixes.forEach(commit => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Improvements + if (categories.improvements.length > 0) { + notes += "## 🚀 Improvements\n\n"; + categories.improvements.forEach(commit => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Other changes + if (categories.other.length > 0) { + notes += "## 📝 Other Changes\n\n"; + categories.other.forEach(commit => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Chores (optional, usually less important) + if (categories.chores.length > 0) { + notes += "## 🔧 Maintenance\n\n"; + categories.chores.forEach(commit => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Add footer + notes += "---\n\n"; + notes += `**Full Changelog:** https://github.com/${process.env.GITHUB_REPOSITORY}/compare/...${version}\n\n`; + + return notes.trim(); +} + +function main() { + const version = process.argv[2]; + + if (!version) { + console.error("Usage: node generate-release-notes.js "); + process.exit(1); + } + + console.log(`Generating release notes for version ${version}...`); + + const commits = getCommitsSinceLastTag(); + console.log(`Found ${commits.length} commits since last release`); + + const categories = categorizeCommits(commits); + const releaseNotes = generateReleaseNotes(version, categories); + + // Output for GitHub Actions + if (process.env.GITHUB_OUTPUT) { + // Escape newlines for GitHub Actions + const escapedNotes = releaseNotes.replace(/\n/g, '%0A').replace(/\r/g, '%0D'); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `release_notes=${escapedNotes}\n`); + + // Also write to a file for easier debugging + fs.writeFileSync('release-notes.md', releaseNotes); + console.log("Release notes written to release-notes.md"); + } else { + // For local testing + console.log("\n" + "=".repeat(50)); + console.log("RELEASE NOTES:"); + console.log("=".repeat(50)); + console.log(releaseNotes); + } +} + +// Run if this script is executed directly +if (import.meta.url === `file://${process.argv[1]}`) { + main(); +} + +export { generateReleaseNotes, categorizeCommits, getCommitsSinceLastTag }; diff --git a/.github/scripts/increment-version.js b/.github/scripts/increment-version.js index 2c8d28b..e8fe2d7 100644 --- a/.github/scripts/increment-version.js +++ b/.github/scripts/increment-version.js @@ -52,6 +52,14 @@ function incrementVersion(version) { return `${version}.1`; } +function isStableRelease(version) { + // Check if version is a stable release (not alpha, beta, canary, etc.) + // Include common typos and variations + const prereleasePattern = + /-(alpha|beta|canary|canery|rc|dev|pre|snapshot|nightly|test)/i; + return !prereleasePattern.test(version); +} + function updateProjectData() { try { // Read the current file @@ -68,6 +76,9 @@ function updateProjectData() { const currentVersion = match[1]; const newVersion = incrementVersion(currentVersion); + // Check if this is a stable release + const isStable = isStableRelease(newVersion); + // Replace the version in the content const newContent = content.replace( versionPattern, @@ -78,6 +89,7 @@ function updateProjectData() { fs.writeFileSync(PROJECT_DATA_PATH, newContent, "utf8"); console.log(`Version updated from ${currentVersion} to ${newVersion}`); + console.log(`Stable release: ${isStable}`); // Output for GitHub Actions (using modern format) if (process.env.GITHUB_OUTPUT) { @@ -86,10 +98,12 @@ function updateProjectData() { `current=${currentVersion}\n`, ); fs.appendFileSync(process.env.GITHUB_OUTPUT, `new=${newVersion}\n`); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `is_stable=${isStable}\n`); } else { // Fallback for local testing console.log(`current=${currentVersion}`); console.log(`new=${newVersion}`); + console.log(`is_stable=${isStable}`); } } catch (error) { console.error("Error updating version:", error.message); @@ -102,4 +116,4 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) { updateProjectData(); } -export { incrementVersion, updateProjectData }; +export { incrementVersion, updateProjectData, isStableRelease }; diff --git a/.github/scripts/manage-versions.js b/.github/scripts/manage-versions.js new file mode 100644 index 0000000..ba12584 --- /dev/null +++ b/.github/scripts/manage-versions.js @@ -0,0 +1,428 @@ +#!/usr/bin/env node + +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import { execSync } from "child_process"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const PROJECT_DATA_PATH = path.join(__dirname, "../../apps/web/projectData.ts"); +const VERSION_JSON_PATH = path.join(__dirname, "../../version.json"); +const VERSIONS_DIR = path.join(__dirname, "../../Versions"); + +function parseVersion(version) { + // Parse semantic version with optional pre-release suffix + const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/); + if (!match) { + throw new Error(`Invalid version format: ${version}`); + } + + return { + major: parseInt(match[1], 10), + minor: parseInt(match[2], 10), + patch: parseInt(match[3], 10), + prerelease: match[4] || null, + full: version, + }; +} + +function incrementVersion(version, isMaster = false) { + const parsed = parseVersion(version); + + if (parsed.prerelease) { + // Handle pre-release versions (e.g., "0.1.10-canary-1" -> "0.1.10-canary-2") + const prereleaseMatch = parsed.prerelease.match(/^(.+)-(\d+)$/); + if (prereleaseMatch) { + const prefix = prereleaseMatch[1]; + const number = parseInt(prereleaseMatch[2], 10); + + if (isMaster) { + // On master branch, remove pre-release suffix and increment patch + return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`; + } else { + // On other branches, increment pre-release number + return `${parsed.major}.${parsed.minor}.${parsed.patch}-${prefix}-${number + 1}`; + } + } else { + // Pre-release without number, add -1 + if (isMaster) { + return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`; + } else { + return `${parsed.major}.${parsed.minor}.${parsed.patch}-${parsed.prerelease}-1`; + } + } + } else { + // Stable version, increment patch + return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`; + } +} + +function isStableRelease(version) { + // Check if version is a stable release (not alpha, beta, canary, etc.) + const prereleasePattern = + /-(alpha|beta|canary|canery|rc|dev|pre|snapshot|nightly|test)/i; + return !prereleasePattern.test(version); +} + +function readVersionJson() { + if (!fs.existsSync(VERSION_JSON_PATH)) { + return { + prod_version: "0.1.0", + dev_version: "0.1.1-canary-1", + }; + } + + return JSON.parse(fs.readFileSync(VERSION_JSON_PATH, "utf8")); +} + +function writeVersionJson(versions) { + fs.writeFileSync(VERSION_JSON_PATH, JSON.stringify(versions, null, 2) + "\n"); +} + +function readProjectData() { + if (!fs.existsSync(PROJECT_DATA_PATH)) { + throw new Error(`ProjectData file not found: ${PROJECT_DATA_PATH}`); + } + + const content = fs.readFileSync(PROJECT_DATA_PATH, "utf8"); + const versionPattern = /version:\s*["']([^"']+)["']/; + const match = content.match(versionPattern); + + if (!match) { + throw new Error("Could not find version property in projectData.ts"); + } + + return { + content, + version: match[1], + }; +} + +function writeProjectData(content, newVersion) { + const versionPattern = /version:\s*["']([^"']+)["']/; + const newContent = content.replace( + versionPattern, + `version: "${newVersion}"`, + ); + fs.writeFileSync(PROJECT_DATA_PATH, newContent, "utf8"); +} + +function createVersionFile(version, releaseNotes) { + if (!fs.existsSync(VERSIONS_DIR)) { + fs.mkdirSync(VERSIONS_DIR, { recursive: true }); + } + + // Convert version to filename format (e.g., "0.1.10" -> "v0-1-10.md") + const filename = `v${version.replace(/\./g, "-")}.md`; + const filepath = path.join(VERSIONS_DIR, filename); + + // Don't overwrite existing version files + if (fs.existsSync(filepath)) { + console.log(`Version file already exists: ${filename}`); + return filepath; + } + + const repoName = process.env.GITHUB_REPOSITORY || "your-org/your-repo"; + const content = `# Updates v${version} + +${releaseNotes} + +**Release Date:** ${new Date().toISOString().split("T")[0]} + +**Docker Image:** +\`\`\`bash +docker pull ghcr.io/${repoName}:v${version} +\`\`\` + +**Full Changelog:** https://github.com/${repoName}/releases/tag/v${version} +`; + + fs.writeFileSync(filepath, content); + console.log(`Created version file: ${filename}`); + return filepath; +} + +function getCommitsSinceLastTag() { + try { + // Get the last tag + const lastTag = execSync("git describe --tags --abbrev=0 2>/dev/null", { + encoding: "utf8", + }).trim(); + + // Get commits since last tag + const commits = execSync( + `git log ${lastTag}..HEAD --pretty=format:"%s (%h)" --no-merges`, + { + encoding: "utf8", + }, + ).trim(); + + return commits ? commits.split("\n") : []; + } catch (error) { + // If no tags exist, get recent commits + try { + const commits = execSync( + 'git log --pretty=format:"%s (%h)" --no-merges -10', + { + encoding: "utf8", + }, + ).trim(); + + return commits ? commits.split("\n") : []; + } catch (e) { + return []; + } + } +} + +function categorizeCommits(commits) { + const categories = { + features: [], + fixes: [], + improvements: [], + chores: [], + other: [], + }; + + commits.forEach((commit) => { + // Skip auto-increment commits + if (commit.includes("🤖 Auto-increment version")) { + return; + } + + const lowerCommit = commit.toLowerCase(); + + if ( + lowerCommit.startsWith("feat:") || + lowerCommit.startsWith("feature:") || + lowerCommit.includes("add ") || + lowerCommit.includes("new ") + ) { + categories.features.push(commit); + } else if ( + lowerCommit.startsWith("fix:") || + lowerCommit.startsWith("bug:") || + lowerCommit.includes("fix ") || + lowerCommit.includes("resolve") + ) { + categories.fixes.push(commit); + } else if ( + lowerCommit.startsWith("improve:") || + lowerCommit.startsWith("enhancement:") || + lowerCommit.includes("improve ") || + lowerCommit.includes("optimize") + ) { + categories.improvements.push(commit); + } else if ( + lowerCommit.startsWith("chore:") || + lowerCommit.startsWith("ci:") || + lowerCommit.startsWith("docs:") || + lowerCommit.includes("update ") + ) { + categories.chores.push(commit); + } else { + categories.other.push(commit); + } + }); + + return categories; +} + +function generateReleaseNotes(version) { + const commits = getCommitsSinceLastTag(); + + if (commits.length === 0) { + return `Automatic release for version ${version}. + +This release includes the latest updates and improvements. For detailed changes, please refer to the commit history and pull requests.`; + } + + const categories = categorizeCommits(commits); + let notes = `## What's Changed in v${version}\n\n`; + + // Features + if (categories.features.length > 0) { + notes += "### ✨ New Features\n"; + categories.features.forEach((commit) => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Bug fixes + if (categories.fixes.length > 0) { + notes += "### 🐛 Bug Fixes\n"; + categories.fixes.forEach((commit) => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Improvements + if (categories.improvements.length > 0) { + notes += "### 🚀 Improvements\n"; + categories.improvements.forEach((commit) => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Other changes + if (categories.other.length > 0) { + notes += "### 📝 Other Changes\n"; + categories.other.forEach((commit) => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + // Maintenance (less prominent) + if (categories.chores.length > 0) { + notes += "### 🔧 Maintenance\n"; + categories.chores.forEach((commit) => { + notes += `- ${commit}\n`; + }); + notes += "\n"; + } + + return notes.trim(); +} + +function main() { + try { + const isMaster = + process.env.GITHUB_REF_NAME === "master" || + process.env.GITHUB_REF_NAME === "main" || + process.argv.includes("--master"); + + console.log(`Running on branch: ${process.env.GITHUB_REF_NAME || "local"}`); + console.log(`Master branch mode: ${isMaster}`); + + // Read current state + const versions = readVersionJson(); + const projectData = readProjectData(); + + console.log(`Current prod_version: ${versions.prod_version}`); + console.log(`Current dev_version: ${versions.dev_version}`); + console.log(`Current projectData version: ${projectData.version}`); + + let newVersion; + let newProdVersion = versions.prod_version; + let newDevVersion; + + // Check if prod and dev versions are the same + if (versions.prod_version === versions.dev_version) { + console.log( + "prod_version == dev_version, auto-incrementing and adding canary suffix", + ); + newDevVersion = incrementVersion(versions.dev_version) + "-canary-1"; + newVersion = newDevVersion; + } else { + // Normal increment logic + if (isMaster) { + // On master: increment and potentially remove canary + newVersion = incrementVersion(projectData.version, true); + + // If this creates a stable version, update prod_version + if (isStableRelease(newVersion)) { + newProdVersion = newVersion; + newDevVersion = newVersion; + } else { + newDevVersion = newVersion; + } + } else { + // On other branches: normal increment + newVersion = incrementVersion(projectData.version, false); + newDevVersion = newVersion; + } + } + + // Update projectData.ts + writeProjectData(projectData.content, newVersion); + console.log( + `Updated projectData.ts: ${projectData.version} → ${newVersion}`, + ); + + // Update version.json + const newVersions = { + prod_version: newProdVersion, + dev_version: newDevVersion, + }; + writeVersionJson(newVersions); + console.log(`Updated version.json:`, newVersions); + + // Create version file for stable releases + let versionFilePath = null; + if (isStableRelease(newVersion) && isMaster) { + const releaseNotes = generateReleaseNotes(newVersion); + versionFilePath = createVersionFile(newVersion, releaseNotes); + } + + // Output for GitHub Actions + if (process.env.GITHUB_OUTPUT) { + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + `previous_version=${projectData.version}\n`, + ); + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + `new_version=${newVersion}\n`, + ); + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + `is_stable=${isStableRelease(newVersion)}\n`, + ); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `is_master=${isMaster}\n`); + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + `prod_version=${newProdVersion}\n`, + ); + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + `dev_version=${newDevVersion}\n`, + ); + + if (versionFilePath) { + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + `version_file=${path.basename(versionFilePath)}\n`, + ); + } + } else { + // Local testing output + console.log("\n=== OUTPUTS ==="); + console.log(`previous_version=${projectData.version}`); + console.log(`new_version=${newVersion}`); + console.log(`is_stable=${isStableRelease(newVersion)}`); + console.log(`is_master=${isMaster}`); + console.log(`prod_version=${newProdVersion}`); + console.log(`dev_version=${newDevVersion}`); + if (versionFilePath) { + console.log(`version_file=${path.basename(versionFilePath)}`); + } + } + } catch (error) { + console.error("Error managing versions:", error.message); + process.exit(1); + } +} + +// Export functions for testing +export { + parseVersion, + incrementVersion, + isStableRelease, + readVersionJson, + writeVersionJson, + createVersionFile, + generateReleaseNotes, + getCommitsSinceLastTag, + categorizeCommits, +}; + +// Run if this script is executed directly +if (import.meta.url === `file://${process.argv[1]}`) { + main(); +} diff --git a/.github/workflows/version-and-build.yml b/.github/workflows/version-and-build.yml index e09064e..3030eb1 100644 --- a/.github/workflows/version-and-build.yml +++ b/.github/workflows/version-and-build.yml @@ -32,18 +32,21 @@ jobs: with: node-version: "20" - - name: Update version using Node.js script + - name: Update versions using comprehensive management script id: version_update run: | # Make script executable - chmod +x .github/scripts/increment-version.js + chmod +x .github/scripts/manage-versions.js - # Run the version increment script - node .github/scripts/increment-version.js + # Run the comprehensive version management script + node .github/scripts/manage-versions.js - # Display updated file + # Display updated files echo "Updated projectData.ts:" cat apps/web/projectData.ts + echo "" + echo "Updated version.json:" + cat version.json - name: Check for changes id: git_status @@ -59,8 +62,16 @@ jobs: run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - git add apps/web/projectData.ts - git commit -m "🤖 Auto-increment version to ${{ steps.version_update.outputs.new }}" + + # Add all changed files + git add apps/web/projectData.ts version.json + + # Add version file if it was created + if [ -n "${{ steps.version_update.outputs.version_file }}" ]; then + git add "Versions/${{ steps.version_update.outputs.version_file }}" + fi + + git commit -m "🤖 Auto-increment version to ${{ steps.version_update.outputs.new_version }} (prod: ${{ steps.version_update.outputs.prod_version }}, dev: ${{ steps.version_update.outputs.dev_version }})" git push - name: Log in to the Container registry @@ -77,7 +88,8 @@ jobs: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=raw,value=latest - type=raw,value=${{ steps.version_update.outputs.new }} + type=raw,value=${{ steps.version_update.outputs.new_version }} + type=raw,value=${{ steps.version_update.outputs.prod_version }},enable={{isBranch 'master'}} type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} @@ -96,11 +108,92 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max + - name: Create version branch (stable releases only) + if: steps.git_status.outputs.changes == 'true' && steps.version_update.outputs.is_stable == 'true' && steps.version_update.outputs.is_master == 'true' + run: | + # Create a new branch for this stable version + git checkout -b "release/v${{ steps.version_update.outputs.new_version }}" + git push origin "release/v${{ steps.version_update.outputs.new_version }}" + + # Switch back to main branch + git checkout ${{ github.ref_name }} + + - name: Generate release notes (stable releases only) + if: steps.git_status.outputs.changes == 'true' && steps.version_update.outputs.is_stable == 'true' && steps.version_update.outputs.is_master == 'true' + id: release_notes + run: | + # Make script executable + chmod +x .github/scripts/generate-release-notes.js + + # Generate release notes using the script + node .github/scripts/generate-release-notes.js "${{ steps.version_update.outputs.new_version }}" + + - name: Create Git Tag (stable releases only) + if: steps.git_status.outputs.changes == 'true' && steps.version_update.outputs.is_stable == 'true' && steps.version_update.outputs.is_master == 'true' + run: | + git tag v${{ steps.version_update.outputs.new_version }} + git push origin v${{ steps.version_update.outputs.new_version }} + + - name: Create GitHub Release (stable releases only) + if: steps.git_status.outputs.changes == 'true' && steps.version_update.outputs.is_stable == 'true' && steps.version_update.outputs.is_master == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Use version file if created, otherwise use generated release notes + if [ -f "Versions/${{ steps.version_update.outputs.version_file }}" ]; then + NOTES_FILE="Versions/${{ steps.version_update.outputs.version_file }}" + else + NOTES_FILE="release-notes.md" + fi + + # Create release using GitHub CLI + gh release create v${{ steps.version_update.outputs.new_version }} \ + --title "Release v${{ steps.version_update.outputs.new_version }}" \ + --notes-file "$NOTES_FILE" \ + --latest + - name: Output summary run: | - echo "## Version Update Summary" >> $GITHUB_STEP_SUMMARY - echo "- Previous version: ${{ steps.version_update.outputs.current }}" >> $GITHUB_STEP_SUMMARY - echo "- New version: ${{ steps.version_update.outputs.new }}" >> $GITHUB_STEP_SUMMARY - echo "- Docker image built with tags:" >> $GITHUB_STEP_SUMMARY - echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY - echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version_update.outputs.new }}" >> $GITHUB_STEP_SUMMARY + echo "## 🚀 Comprehensive Version Update & Build Summary" >> $GITHUB_STEP_SUMMARY + echo "- **Previous version:** ${{ steps.version_update.outputs.previous_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **New version:** ${{ steps.version_update.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Production version:** ${{ steps.version_update.outputs.prod_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Development version:** ${{ steps.version_update.outputs.dev_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY + echo "- **Stable release:** ${{ steps.version_update.outputs.is_stable }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### 🐳 Docker Images Built" >> $GITHUB_STEP_SUMMARY + echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY + echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version_update.outputs.new_version }}\`" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.version_update.outputs.is_master }}" == "true" ]; then + echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version_update.outputs.prod_version }}\`" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### 📁 Files Updated" >> $GITHUB_STEP_SUMMARY + echo "- \`apps/web/projectData.ts\` - Updated to ${{ steps.version_update.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "- \`version.json\` - prod: ${{ steps.version_update.outputs.prod_version }}, dev: ${{ steps.version_update.outputs.dev_version }}" >> $GITHUB_STEP_SUMMARY + + if [ -n "${{ steps.version_update.outputs.version_file }}" ]; then + echo "- \`Versions/${{ steps.version_update.outputs.version_file }}\` - New version file created" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.version_update.outputs.is_stable }}" == "true" ] && [ "${{ steps.version_update.outputs.is_master }}" == "true" ]; then + echo "### 🏷️ Release Created" >> $GITHUB_STEP_SUMMARY + echo "- **Tag:** \`v${{ steps.version_update.outputs.new_version }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Branch:** \`release/v${{ steps.version_update.outputs.new_version }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Release:** [v${{ steps.version_update.outputs.new_version }}](https://github.com/${{ github.repository }}/releases/tag/v${{ steps.version_update.outputs.new_version }})" >> $GITHUB_STEP_SUMMARY + if [ -n "${{ steps.version_update.outputs.version_file }}" ]; then + echo "- **Version File:** \`Versions/${{ steps.version_update.outputs.version_file }}\`" >> $GITHUB_STEP_SUMMARY + fi + else + echo "### ⚠️ Development Build" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.version_update.outputs.is_master }}" != "true" ]; then + echo "This is a development branch build. No GitHub release or version branch created." >> $GITHUB_STEP_SUMMARY + else + echo "This is a pre-release version (contains alpha, beta, canary, etc.). No GitHub release or version branch created." >> $GITHUB_STEP_SUMMARY + fi + fi diff --git a/Versions/v0-1-11.md b/Versions/v0-1-11.md new file mode 100644 index 0000000..ef8d044 --- /dev/null +++ b/Versions/v0-1-11.md @@ -0,0 +1,14 @@ +# Updates v0.1.11 + +Automatic release for version 0.1.11. + +This release includes the latest updates and improvements. For detailed changes, please refer to the commit history and pull requests. + +**Release Date:** 2025-12-09 + +**Docker Image:** +```bash +docker pull ghcr.io/undefined:v0.1.11 +``` + +**Full Changelog:** https://github.com/undefined/releases/tag/v0.1.11 diff --git a/apps/web/projectData.ts b/apps/web/projectData.ts index 52b83a7..797abe9 100644 --- a/apps/web/projectData.ts +++ b/apps/web/projectData.ts @@ -1,5 +1,5 @@ const data = { - version: "0.1.10", + version: "0.1.9-canery-4", }; export default data; diff --git a/version.json b/version.json new file mode 100644 index 0000000..9d77e48 --- /dev/null +++ b/version.json @@ -0,0 +1,4 @@ +{ + "prod_version": "0.1.9", + "dev_version": "0.1.10-canery-1" +}