Skip to content

Instantly share code, notes, and snippets.

@adamruzicka
Last active May 15, 2026 09:06
Show Gist options
  • Select an option

  • Save adamruzicka/2ff406bf4e9414271cb65afd8df0ffc9 to your computer and use it in GitHub Desktop.

Select an option

Save adamruzicka/2ff406bf4e9414271cb65afd8df0ffc9 to your computer and use it in GitHub Desktop.
name foreman-plugin-release
description Use when releasing a Foreman plugin gem - bumping version, tagging, pushing to rubygems, and updating upstream/downstream packaging

Foreman Plugin Release

Overview

Release process for Foreman plugins: bump version in-repo, tag, push (triggers rubygems publish via GitHub Actions), then trigger packaging updates.

Steps

1a. Prepare and Determine Version

git fetch upstream

# Create a worktree based on upstream/master to keep the main working directory clean
git worktree add /tmp/<plugin_name>-release upstream/master
cd /tmp/<plugin_name>-release

Read the current version from lib/<plugin_name>/version.rb and recent commits/changelog to determine what changed since the last release. Apply versioning rules (see below) to propose the next version.

STOP: Present the suggested version to the user and wait for explicit approval before proceeding.

1b. Bump, Tag, Push, and Clean Up

# Working inside /tmp/<plugin_name>-release

# Bump version file (lib/<plugin_name>/version.rb)
# Edit VERSION = "x.y.z"

git add lib/<plugin_name>/version.rb
git commit -m "Bump version to x.y.z"
git tag vx.y.z
# Push HEAD explicitly since this worktree is in detached-like state (not on local master)
git push upstream HEAD:master
git push upstream vx.y.z

# Remove the worktree
cd -
git worktree remove /tmp/<plugin_name>-release

2. RubyGems (automatic + verify)

Tag push triggers GitHub Actions release workflow → gem built and pushed to rubygems.org.

Verify it worked — either check GitHub Actions:

gh run list --repo theforeman/<plugin_name> --workflow release.yml --limit 5
gh run watch <run-id> --repo theforeman/<plugin_name>

Or poll rubygems.org directly:

# Replace gem name and version as appropriate
curl -s https://rubygems.org/api/v1/versions/<gem_name>.json | \
  python3 -c "import sys,json; vs=[v['number'] for v in json.load(sys.stdin)]; print('Found' if 'x.y.z' in vs else 'NOT found')"

Don't proceed to upstream packaging until the gem is confirmed on rubygems.org.

3. Upstream Packaging

Automation runs twice weekly comparing packaging vs rubygems. To trigger manually:

gh workflow run bump_packages.yml \
  --repo theforeman/foreman-packaging \
  -f package=MyPackageHere

After triggering, wait for the automation to create PRs, then find and present them to the user:

# Poll until PRs appear (may take a few minutes)
gh pr list --repo theforeman/foreman-packaging --search "<gem_name>" --json number,title,url

Present the PR links to the user. Usually two PRs per package (rpm + deb). Merge permission matches source repo permissions.

Versioning Rules

Change Version bump
Foreman dependency version requirement changes Major
Required Ruby version changes Major
New features Minor
Bug fixes Patch

Common Mistakes

  • Forgetting to push the tag (git push upstream vx.y.z) — rubygems publish won't trigger
  • Pushing tag before the version bump commit — tag should point to the bump commit
  • Targeting all packages in packaging workflow — prefer targeting individual packages with package= filter
  • Using rubygem- prefix in the package= parameter — that's RPM-specific; use the bare gem name
  • The package= value is usually the gem name (with underscores), but foreman-tasks is an exception: use foreman-tasks (dashes), not foreman_tasks
name foreman-post-release-jira
description Use when a Foreman plugin has been released and Jira housekeeping is needed - setting "Fixed in Build" and moving issues to "Release pending - upstream"

Foreman Post-Release Jira Housekeeping

Overview

After releasing a Foreman plugin, update Jira issues: set "Fixed in Build[Short text]" and move to "Release pending - upstream". Issues are found via two routes: Redmine numbers in commit messages, and GitHub PR URLs looked up from commit SHAs.

Step 1: Derive Context from Repository

# List recent tags to identify release tag and previous tag
git tag --sort=-version:refname | head -5

# Get gem name from version file path
ls lib/*/version.rb

# GitHub repo
git remote get-url origin
  • Version: strip leading v from tag (e.g. v16.5.316.5.3)
  • Gem name: directory name under lib/ containing version.rb
  • "Fixed in Build" value: rubygem-<gem_name>-<version>
    • Exception: foreman_tasksrubygem-foreman-tasks-<version> (dashes, not underscores)

Step 2: Collect Commits

git log --oneline <previous-tag>..<release-tag>

Step 3: Find Jira Issues — Two Approaches (run both)

Approach A: Via Redmine numbers in commit messages

Extract Redmine issue numbers:

git log --oneline <previous-tag>..<release-tag> | grep -oE '#[0-9]+' | tr -d '#' | sort -u

For each number, search Jira:

mcp__atlassian__jira_search JQL:
  "External issue URL" = "https://projects.theforeman.org/issues/<N>"

Approach B: Via GitHub PR URLs from commit SHAs

For each commit SHA in the release range, find the PR that delivered it:

gh pr list --repo theforeman/<repo> --search "<sha>" --state merged --json number,url

For each PR URL found, search Jira:

mcp__atlassian__jira_search JQL:
  "GitHub Issue[URL Field]" = "https://github.com/theforeman/<repo>/pull/<N>"

Combine results from both approaches — deduplicate by Jira issue key.

Step 4: Present Planned Changes and Ask for Confirmation

Before touching Jira, show the user a table of all planned actions:

Jira Issue Summary Current Status Planned Actions
FOO-123 In Progress Set "Fixed in Build"=rubygem-…-x.y.z, move to "Release pending - upstream"
FOO-456 Release pending - upstream Set "Fixed in Build"=rubygem-…-x.y.z (already in correct status)

Also list commits with no linked Jira issue found.

STOP. Ask the user to confirm before proceeding.

Step 5: Update Each Jira Issue

Only after explicit user confirmation:

5a. Set "Fixed in Build[Short text]"

Field ID: customfield_10578 (type: short text string). No lookup needed.

mcp__atlassian__jira_update_issue:
  issue_key: <KEY>
  additional_fields: {"customfield_10578": "rubygem-<gem_name>-<version>"}

5b. Move to "Release pending - upstream" (if not already there or past it)

mcp__atlassian__jira_get_transitions  → find transition ID
mcp__atlassian__jira_transition_issue → apply it

Step 6: Report

  • Issues updated (Jira key, action taken)
  • Issues skipped (already in correct state)
  • Commits with no linked Jira issue found via either approach

Quick Reference

Item How to get it
Release tag git tag --sort=-version:refname | head -2
Gem name directory under lib/ with version.rb
"Fixed in Build" value rubygem-<gem_name>-<version>
foreman_tasks exception rubygem-foreman-tasks-<version>
GitHub repo git remote get-url origin
PR for commit gh pr list --repo … --search <sha> --state merged
"Fixed in Build" field ID customfield_10578 (short text)
JQL — Redmine "External issue URL" = "https://projects.theforeman.org/issues/<N>"
JQL — GitHub PR "GitHub Issue[URL Field]" = "https://github.com/…/pull/<N>"
Target status Release pending - upstream

Common Mistakes

  • Using HEAD tag as range start instead of the previous tag for git log
  • Wrong package name format: must be rubygem-<gem_name>-<version>
  • Skipping Approach B — some issues are linked only via PR URL in Jira, with no Redmine number in the commit
  • Moving issues already past "Release pending - upstream" — check current status first
  • Touching Jira before user confirms the planned changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment