Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/release-rules/reviews.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"require_code_owner_review": false,
"allowed_merge_methods": [
"merge",
"squash"
"squash",
"rebase"
]
}
}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-validate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ jobs:
- name: Regenerate release content
env:
RELEASE_BASE: ${{ github.event.pull_request.base.sha }}
run: bundle exec bake gem:release:validate "base=$RELEASE_BASE" optional=true
run: bundle exec bake gem:github:release:validate "base=$RELEASE_BASE"
- name: Build unsigned package
run: bundle exec bake gem:build signing_key=false
3 changes: 2 additions & 1 deletion bake-modernize.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ Gem::Specification.new do |spec|
"source_code_uri" => "https://github.com/ioquatix/bake-modernize.git",
}

spec.files = Dir.glob(["{bake,lib,template}/**/*", "*.md", "release.cert"], File::FNM_DOTMATCH, base: __dir__)
spec.files = Dir.glob(["{bake,context,lib,template}/**/*", "*.md", "release.cert"], File::FNM_DOTMATCH, base: __dir__)

spec.required_ruby_version = ">= 3.3"

spec.add_dependency "async-http"
spec.add_dependency "async-ollama", "~> 0.10"
spec.add_dependency "bake"
spec.add_dependency "build-files", "~> 1.6"
spec.add_dependency "erb"
spec.add_dependency "markly", "~> 0.13"
spec.add_dependency "rugged"
end
8 changes: 7 additions & 1 deletion bake/modernize/contributing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ def contributing
def update_contributing(readme_path)
root = Markly.parse(File.read(readme_path))

replacement = Markly.parse(DEFAULT_CONTRIBUTING)
contributing = DEFAULT_CONTRIBUTING
if Bake::Modernize.gem_dependencies(File.dirname(readme_path)).include?("bake-gem-github")
contributing = contributing.sub("gem:release:patch", "gem:github:release:patch")
contributing = contributing.sub("### Developer Certificate of Origin", "See [bake-gem-github](https://github.com/socketry/bake-gem-github) for setup and release instructions.\n\n### Developer Certificate of Origin")
end

replacement = Markly.parse(contributing)

return unless node = root.find_header("Contributing")

Expand Down
35 changes: 33 additions & 2 deletions bake/modernize/releases.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

require "bake/modernize"
require "markly"
require "erb"

# Update the project to use bake-releases for release notes.
#
Expand All @@ -17,6 +18,28 @@ def releases(root: Dir.pwd)
update_bake(root)
end

# Migrate release dependencies and hooks to bake-gem-github. Configure its workflows with gem:github:setup afterwards.
#
# @parameter root [String] The root directory of the project.
def github(root: Dir.pwd)
require "bundler"

dependencies = Bake::Modernize.gem_dependencies(root)
environment = Bundler.unbundled_env

unless dependencies.include?("bake-gem-github")
system(environment, "bundle", "add", "bake-gem-github", "--group", "maintenance", chdir: root, unsetenv_others: true, exception: true)
end

if dependencies.include?("bake-gem")
system(environment, "bundle", "remove", "bake-gem", chdir: root, unsetenv_others: true, exception: true)
end

update_releases(File.join(root, "readme.md"))
update_releases_md(File.join(root, "releases.md"))
update_bake(root)
end

private

DEFAULT_CONTRIBUTING = <<~MARKDOWN
Expand Down Expand Up @@ -58,13 +81,21 @@ def update_bake(root)
require "async/ollama"

bake_path = File.join(root, "bake.rb")
template = File.read(RELEASES_TEMPLATE_ROOT + "bake.rb")
github_releases = Bake::Modernize.gem_dependencies(root).include?("bake-gem-github")
template = ERB.new(File.read(RELEASES_TEMPLATE_ROOT + "bake.rb.erb"), trim_mode: "-").result(binding)
instruction = "Merge the template into the existing file. Add any missing methods and update existing method bodies to include any missing calls shown in the template."

if github_releases
instruction += " Remove the releases:github:release call from after_gem_release, because bake-gem-github publishes the GitHub release. Remove that method and its documentation if it becomes empty. Do not add an after_gem_release hook. Preserve all other methods and calls."
else
instruction += " Do not remove any existing calls."
end

if File.exist?(bake_path)
existing = File.read(bake_path)
updated = Async::Ollama::Transform.call(existing,
model: "qwen3-coder:latest",
instruction: "Merge the template into the existing file. Add any missing methods and update existing method bodies to include any missing calls shown in the template. Do not remove any existing calls.",
instruction: instruction,
template: template,
)
File.write(bake_path, updated)
Expand Down
85 changes: 85 additions & 0 deletions context/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Getting Started

This guide explains how to update a Ruby gem with `bake-modernize`, review the generated changes, and optionally migrate to releases through GitHub.

## Installation

Add the tools to the project's maintenance dependencies, preserving the existing groups and version requirements:

``` ruby
group :maintenance, optional: true do
gem "agent-context"
gem "bake-modernize"
end
```

Install the maintenance group and its agent guidance:

``` bash
bundle config set --local with maintenance
bundle install
bundle exec bake agent:context:install
```

If `bake-modernize` is already installed, use `bundle update bake-modernize --conservative` to update it, then reinstall the agent context. Read the project's instructions and relevant dependency guides before making changes. Generated `agents.md` and installed context are local working files; do not commit them.

## Update a gem

Start from an up-to-date checkout with a clean working tree and create a branch for the modernization. Check the gem's supported Ruby versions, CI jobs, release process, signing configuration, and custom Bake tasks before updating them.

List the available tasks, then run the default modernization from the gem's root directory:

``` bash
bundle exec bake list modernize
bundle exec bake modernize
git diff
```

The default task updates standard files including CI workflows, dependency manifests, the gemspec, copyright attributions, contributing instructions, and release hooks. It modifies the working tree directly. Review the diff and selectively keep appropriate changes; generated changes are suggestions, and repository customizations can be intentional. Some tasks install gems, inspect GitHub URLs, or use Ollama with `qwen3-coder:latest` to merge existing files. Those merges need a running Ollama service with that model available.

You can run individual tasks when only part of the project needs updating:

``` bash
bundle exec bake modernize:actions
bundle exec bake modernize:license
bundle exec bake modernize:releases
```

Check the resulting Ruby compatibility requirements, gem dependencies, workflow names and required status checks, gemspec file list, signing paths, and release hooks. Preserve custom tasks and project-specific CI. Copyright generation ignores author names ending in `[bot]`; `.mailmap`, `.contributors.yaml`, and human authorship through file renames remain supported.

Run the project's checks before opening a PR. For gems using the standard Sus, RuboCop, and Decode tasks:

``` bash
bundle exec bake test
bundle exec rubocop
bundle exec bake decode:index:coverage lib
```

Add user-visible changes under `## Unreleased` in `releases.md`. If guides or project documentation changed, run `bundle exec bake utopia:project:update` and review its output. Commit the selected changes and describe any remaining manual setup in the PR.

## Opt in to GitHub releases

The default `modernize` task does not migrate the publishing process. To adopt reviewed release PRs explicitly:

``` bash
bundle exec bake modernize:releases:github
```

This task adds `bake-gem-github` to maintenance dependencies, removes the direct `bake-gem` dependency when present, and updates release notes and Bake hooks. `bake-gem-github` supplies `bake-gem` and `bake-releases` as dependencies. Existing `bake-gem-github` version requirements are preserved.

Keep `after_gem_release_version_increment`, which updates release notes and project documentation. GitHub publishing replaces the `after_gem_release` call to `releases:github:release`. When merging an existing `bake.rb`, review the generated edit to ensure it removes that call while preserving unrelated custom behavior. Subsequent `modernize:releases` runs select the same template based on the target project's dependencies and do not add the publishing hook back. Contributing instructions also use `gem:github:release:patch` for projects that have adopted it.

Configure the release workflows separately using the installed gem's setup task. Pass the actual required CI job names; for example, a repository using the standard Ruby matrix and coverage workflows might use:

``` bash
bundle exec bake gem:github:setup checks="3.3 on ubuntu,3.3 on macos,3.4 on ubuntu,3.4 on macos,4.0 on ubuntu,4.0 on macos,check,ruby on ubuntu,ruby on macos,validate"
bundle exec bake gem:github:setup:plan
```

For an existing `config/release.yaml`, use `bundle exec bake gem:github:setup:update` to regenerate managed files instead. Review and commit the generated workflows, rulesets, configuration, and readme changes. Keep the readme's `Making Releases` section short: a release command and a link to [bake-gem-github](https://github.com/socketry/bake-gem-github).

Complete the setup described by [bake-gem-github](https://github.com/socketry/bake-gem-github): configure the RubyGems Trusted Publisher for `release-publish.yaml` and the `rubygems` environment, restrict that environment to the default branch, and install a matching signing key if signing is enabled. Select environment reviewers per repository when a separate publishing approval is wanted, for example `reviewers: [socketry/managers]`. Omitting reviewers leaves the environment's existing reviewer configuration unchanged.

After the setup PR is merged and the required CI jobs are available, an administrator reviews the plan and runs `bundle exec bake gem:github:setup:apply`. Generating files or upgrading gems does not apply remote settings. Workflow execution approvals, PR reviews, and publishing environment approvals are separate controls.

Once setup is complete, prepare a release with `bundle exec bake gem:github:release:patch` (or `minor` or `major`), or dispatch `release-prepare.yaml` remotely. Merge the reviewed release PR to start publishing.
15 changes: 15 additions & 0 deletions context/index.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Automatically generated context index for Utopia::Project guides.
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
---
description: Automatically modernize parts of your project/gem.
metadata:
bug_tracker_uri: https://github.com/ioquatix/bake-modernize/issues
changelog_uri: https://github.com/ioquatix/bake-modernize/blob/main/releases.md
documentation_uri: https://ioquatix.github.io/bake-modernize/
funding_uri: https://github.com/sponsors/ioquatix/
source_code_uri: https://github.com/ioquatix/bake-modernize.git
files:
- path: getting-started.md
title: Getting Started
description: This guide explains how to update a Ruby gem with `bake-modernize`,
review the generated changes, and optionally migrate to releases through GitHub.
3 changes: 2 additions & 1 deletion gems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
gemspec

group :maintenance, optional: true do
gem "bake-gem-github", "~> 0.4.0"
gem "agent-context"
gem "bake-gem-github", "~> 0.5.0"
gem "bake-releases"

gem "decode"
Expand Down
85 changes: 85 additions & 0 deletions guides/getting-started/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Getting Started

This guide explains how to update a Ruby gem with `bake-modernize`, review the generated changes, and optionally migrate to releases through GitHub.

## Installation

Add the tools to the project's maintenance dependencies, preserving the existing groups and version requirements:

``` ruby
group :maintenance, optional: true do
gem "agent-context"
gem "bake-modernize"
end
```

Install the maintenance group and its agent guidance:

``` bash
bundle config set --local with maintenance
bundle install
bundle exec bake agent:context:install
```

If `bake-modernize` is already installed, use `bundle update bake-modernize --conservative` to update it, then reinstall the agent context. Read the project's instructions and relevant dependency guides before making changes. Generated `agents.md` and installed context are local working files; do not commit them.

## Update a gem

Start from an up-to-date checkout with a clean working tree and create a branch for the modernization. Check the gem's supported Ruby versions, CI jobs, release process, signing configuration, and custom Bake tasks before updating them.

List the available tasks, then run the default modernization from the gem's root directory:

``` bash
bundle exec bake list modernize
bundle exec bake modernize
git diff
```

The default task updates standard files including CI workflows, dependency manifests, the gemspec, copyright attributions, contributing instructions, and release hooks. It modifies the working tree directly. Review the diff and selectively keep appropriate changes; generated changes are suggestions, and repository customizations can be intentional. Some tasks install gems, inspect GitHub URLs, or use Ollama with `qwen3-coder:latest` to merge existing files. Those merges need a running Ollama service with that model available.

You can run individual tasks when only part of the project needs updating:

``` bash
bundle exec bake modernize:actions
bundle exec bake modernize:license
bundle exec bake modernize:releases
```

Check the resulting Ruby compatibility requirements, gem dependencies, workflow names and required status checks, gemspec file list, signing paths, and release hooks. Preserve custom tasks and project-specific CI. Copyright generation ignores author names ending in `[bot]`; `.mailmap`, `.contributors.yaml`, and human authorship through file renames remain supported.

Run the project's checks before opening a PR. For gems using the standard Sus, RuboCop, and Decode tasks:

``` bash
bundle exec bake test
bundle exec rubocop
bundle exec bake decode:index:coverage lib
```

Add user-visible changes under `## Unreleased` in `releases.md`. If guides or project documentation changed, run `bundle exec bake utopia:project:update` and review its output. Commit the selected changes and describe any remaining manual setup in the PR.

## Opt in to GitHub releases

The default `modernize` task does not migrate the publishing process. To adopt reviewed release PRs explicitly:

``` bash
bundle exec bake modernize:releases:github
```

This task adds `bake-gem-github` to maintenance dependencies, removes the direct `bake-gem` dependency when present, and updates release notes and Bake hooks. `bake-gem-github` supplies `bake-gem` and `bake-releases` as dependencies. Existing `bake-gem-github` version requirements are preserved.

Keep `after_gem_release_version_increment`, which updates release notes and project documentation. GitHub publishing replaces the `after_gem_release` call to `releases:github:release`. When merging an existing `bake.rb`, review the generated edit to ensure it removes that call while preserving unrelated custom behavior. Subsequent `modernize:releases` runs select the same template based on the target project's dependencies and do not add the publishing hook back. Contributing instructions also use `gem:github:release:patch` for projects that have adopted it.

Configure the release workflows separately using the installed gem's setup task. Pass the actual required CI job names; for example, a repository using the standard Ruby matrix and coverage workflows might use:

``` bash
bundle exec bake gem:github:setup checks="3.3 on ubuntu,3.3 on macos,3.4 on ubuntu,3.4 on macos,4.0 on ubuntu,4.0 on macos,check,ruby on ubuntu,ruby on macos,validate"
bundle exec bake gem:github:setup:plan
```

For an existing `config/release.yaml`, use `bundle exec bake gem:github:setup:update` to regenerate managed files instead. Review and commit the generated workflows, rulesets, configuration, and readme changes. Keep the readme's `Making Releases` section short: a release command and a link to [bake-gem-github](https://github.com/socketry/bake-gem-github).

Complete the setup described by [bake-gem-github](https://github.com/socketry/bake-gem-github): configure the RubyGems Trusted Publisher for `release-publish.yaml` and the `rubygems` environment, restrict that environment to the default branch, and install a matching signing key if signing is enabled. Select environment reviewers per repository when a separate publishing approval is wanted, for example `reviewers: [socketry/managers]`. Omitting reviewers leaves the environment's existing reviewer configuration unchanged.

After the setup PR is merged and the required CI jobs are available, an administrator reviews the plan and runs `bundle exec bake gem:github:setup:apply`. Generating files or upgrading gems does not apply remote settings. Workflow execution approvals, PR reviews, and publishing environment approvals are separate controls.

Once setup is complete, prepare a release with `bundle exec bake gem:github:release:patch` (or `minor` or `major`), or dispatch `release-prepare.yaml` remotely. Merge the reviewed release PR to start publishing.
2 changes: 2 additions & 0 deletions guides/links.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
getting-started:
order: 1
15 changes: 15 additions & 0 deletions lib/bake/modernize.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ module Modernize

TEMPLATE_ROOT = Build::Files::Path.new(ROOT) + "template"

# Read the gem dependencies declared by the target project, including optional groups.
# @parameter root [String] The root directory of the project.
# @returns [Array(String)] The declared dependency names.
def self.gem_dependencies(root)
require "bundler"

if path = ["gems.rb", "Gemfile"].map{|name| File.expand_path(name, root)}.find{|path| File.file?(path)}
dsl = Bundler::Dsl.new
dsl.eval_gemfile(path)
return dsl.dependencies.map(&:name)
end

return []
end

# Compute the template root path relative to the gem root.
def self.template_path_for(path)
TEMPLATE_ROOT + path
Expand Down
2 changes: 2 additions & 0 deletions lib/bake/modernize/license.rb
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ def initialize

# Add a modification to the authorship.
def add(path, author, time, id = nil)
return if author[:name].end_with?("[bot]")

modification = Modification.new(author, time, path, id)

@commits[modification.key] << modification
Expand Down
8 changes: 8 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ A gem for modernizing files in your Ruby project.

Please see the [project documentation](https://ioquatix.github.io/bake-modernize/) for more details.

- [Getting Started](https://ioquatix.github.io/bake-modernize/guides/getting-started/index) - This guide explains how to update a Ruby gem with `bake-modernize`, review the generated changes, and optionally migrate to releases through GitHub.

## Releases

Please see the [project releases](https://ioquatix.github.io/bake-modernize/releases/index) for all releases.

### Unreleased

- Provide agent context for updating gems and configuring GitHub releases.
- Ignore `[bot]` authors in copyright attributions and gem authors.
- Add opt-in `modernize:releases:github` migration and omit redundant publishing hooks for gems using `bake-gem-github`.

### v0.60.0

- Ignore `/vendor/bundle` by default for dependencies installed by GitHub Actions' Bundler cache.
Expand Down
6 changes: 6 additions & 0 deletions releases.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Releases

## Unreleased

- Provide agent context for updating gems and configuring GitHub releases.
- Ignore `[bot]` authors in copyright attributions and gem authors.
- Add opt-in `modernize:releases:github` migration and omit redundant publishing hooks for gems using `bake-gem-github`.

## v0.60.0

- Ignore `/vendor/bundle` by default for dependencies installed by GitHub Actions' Bundler cache.
Expand Down
2 changes: 2 additions & 0 deletions template/releases/bake.rb → template/releases/bake.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ def after_gem_release_version_increment(version)
context["releases:update"].call(version)
context["utopia:project:update"].call
end
<% unless github_releases -%>

# Create a GitHub release for the given tag.
#
# @parameter tag [String] The tag to create a release for.
def after_gem_release(tag:, **options)
context["releases:github:release"].call(tag)
end
<% end -%>
Loading
Loading