Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Reusable Release Workflows for AlchemyCMS Gems

This repository contains reusable GitHub Actions workflows for automating gem releases across all AlchemyCMS repositories.

Overview

The release process is fully automated with three workflows:

  1. prepare-release.yml - Creates a release PR with version bump and changelog
  2. release.yml - Publishes the gem to RubyGems and creates a GitHub release
  3. post-release.yml - Bumps to next development version, syncs changelog, and announces release

Features

  • Supports both main and *-stable branch releases
  • Automatic changelog generation from GitHub release notes
  • Post-release announcements to Slack, Mastodon, and Bluesky
  • Opt-in RubyFlow announcement issues for minor and major releases
  • Changelog sync to main branch after stable releases (for Dependabot visibility)

Adding Workflows to Your Gem

Create three workflow files in your gem's .github/workflows/ directory:

1. .github/workflows/prepare-release.yml

name: Prepare Releaseon:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type. Choose "release" for finalizing a pre-release (8.0.0.dev → 8.0.0), or patch/minor/major to simply bump version.'required: truetype: choicedefault: 'patch'options:
- release
- patch
- minor
- majorjobs:
prepare:
uses: AlchemyCMS/.github/.github/workflows/prepare-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISbump: ${{ inputs.bump }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

2. .github/workflows/release.yml

name: Publish Releaseon:
workflow_dispatch:
pull_request:
types: [closed]branches:
- main
- '*-stable'jobs:
publish:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v'))uses: AlchemyCMS/.github/.github/workflows/release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THISsecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}

3. .github/workflows/post-release.yml

name: Post Releaseon:
workflow_run:
workflows: ["Publish Release"]types:
- completedjobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy/YOUR_GEM/version.rb # UPDATE THIStarget_branch: ${{ github.event.workflow_run.head_branch }}secrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}mastodon_access_token: ${{ secrets.MASTODON_ACCESS_TOKEN }}mastodon_instance: ${{ secrets.MASTODON_INSTANCE }}bluesky_identifier: ${{ secrets.BLUESKY_IDENTIFIER }}bluesky_password: ${{ secrets.BLUESKY_PASSWORD }}

Configuration

Update version_file_path in all three workflows to match your gem's version file location. For example:

  • lib/alchemy/solidus/version.rb
  • lib/alchemy/devise/version.rb
  • lib/alchemy_cms/version.rb

The workflows will automatically use the organization's ALCHEMY_BOT_APP_ID variable and ALCHEMY_BOT_APP_PRIVATE_KEY secret.

How to Release

Releasing from main

  1. Go to Actions tab in your gem repository
  2. Select Prepare Release workflow
  3. Click Run workflow (ensure main branch is selected)
  4. Choose the version bump type:
    • release - Finalize a pre-release (e.g., 8.0.0.dev8.0.0)
    • patch - Increment patch version (e.g., 1.2.31.2.4)
    • minor - Increment minor version (e.g., 1.2.31.3.0)
    • major - Increment major version (e.g., 1.2.32.0.0)

This creates a PR targeting main with:

  • Updated version file
  • Generated changelog from GitHub release notes
  • Release branch release/vX.Y.Z

Review and merge the PR. This automatically triggers:

  1. Publish Release - Publishes gem to RubyGems and creates GitHub release
  2. Post Release - Bumps version to next minor dev version (e.g., 1.2.01.3.0.dev) and announces the release

Releasing from Stable Branches

For repositories with x.y-stable branches (e.g., 8.0-stable):

  1. Go to Actions tab
  2. Select Prepare Release workflow
  3. Click Run workflow and select the stable branch (e.g., 8.0-stable)
  4. Choose bump type (typically release for stable branches)

This creates a PR targeting the stable branch. After merge:

  1. Publish Release - Publishes gem and creates GitHub release
  2. Post Release - Syncs changelog to main (via PR) and announces the release

The changelog sync ensures tools like Dependabot see all releases when reading from main. Version bumps are not automated for stable branches.

Requirements

Your gem repository must have:

  1. Version file with VERSION = "x.y.z" constant (e.g., lib/alchemy/solidus/version.rb)
  2. CHANGELOG.md file in the repository root
  3. Trusted publishing configured on RubyGems for the gem
  4. Main branch named main

These are standard across all AlchemyCMS gems.

What Each Workflow Does

prepare-release.yml

  • Calculates next version based on bump type and current version
  • Strips pre-release suffixes (.dev, .alpha, etc.) when using "release" bump
  • Creates release branch release/vX.Y.Z
  • Generates changelog from GitHub release notes API
  • Updates version file and prepends to CHANGELOG.md
  • Creates PR (with skip-changelog label) targeting the branch it was triggered from (main or *-stable)

release.yml

  • Triggers when a release/v* PR is merged to main or *-stable branches
  • Sets up Ruby and installs dependencies
  • Publishes gem to RubyGems using trusted publishing
  • Creates GitHub release with auto-generated notes

post-release.yml

  • Triggers after successful release
  • Version bump (main only): Creates a PR to bump to next minor dev version (e.g., 1.2.01.3.0.dev)
  • Changelog sync (stable only): Creates a PR to copy the changelog entry to main branch (for Dependabot visibility)
  • Announcements: Posts release notifications to Slack, Mastodon, and Bluesky (if secrets are configured)
  • RubyFlow (opt-in): For minor and major releases, opens a tracking issue with a ready-to-paste draft for manual posting to RubyFlow (when announce_to_rubyflow: true)

All PRs created by these workflows are labeled with skip-changelog to exclude them from future release notes.

Release Announcements

The post-release workflow can announce releases to multiple platforms. Configure these org-level secrets:

SecretDescription
SLACK_WEBHOOK_URLSlack incoming webhook URL (via Slack App)
MASTODON_ACCESS_TOKENMastodon bot access token with write:statuses scope
MASTODON_INSTANCEMastodon instance URL (e.g., https://ruby.social)
BLUESKY_IDENTIFIERBluesky handle, DID, or custom domain
BLUESKY_PASSWORDBluesky app password (not main password)

All announcement secrets are optional. Announcements are skipped for platforms without configured secrets.

RubyFlow (opt-in)

RubyFlow has no posting API and requires a GitHub-authenticated session, so the workflow does not post there automatically. Instead, for minor and major releases only (versions ending in .0), it opens a GitHub issue in the releasing repo containing a ready-to-paste title and content plus the RubyFlow submit link. A maintainer pastes it into RubyFlow and closes the issue.

This is opt-in and disabled by default. Enable it by passing announce_to_rubyflow: true to the reusable post-release.yml workflow:

jobs:
post-release:
if: github.event.workflow_run.conclusion == 'success'uses: AlchemyCMS/.github/.github/workflows/post-release.yml@mainwith:
version_file_path: lib/alchemy_cms/version.rbtarget_branch: ${{ github.event.workflow_run.head_branch }}announce_to_rubyflow: truesecrets:
app_id: ${{ vars.ALCHEMY_BOT_APP_ID }}app_private_key: ${{ secrets.ALCHEMY_BOT_APP_PRIVATE_KEY }}# ...announcement secrets as above

Only alchemy_cms enables this; other gems leave it off so we don't flood RubyFlow with every gem's releases. No extra secret is needed — the issue is created with the existing bot app token.

Advanced: Version Pinning

The examples above use @main to always use the latest workflow version. You can also pin to specific commits:

# Pin to a specific commit (maximum control)uses: AlchemyCMS/.github/.github/workflows/release.yml@abc123

Using @main ensures you automatically get updates and fixes, which is recommended for most AlchemyCMS gems.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors