From 43d56a7c2bf6e34e6632f72d2d9218e02be17191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=9Awi=C4=85tkowski?= Date: Mon, 8 Jun 2026 20:51:54 +0200 Subject: [PATCH 1/2] Source gems from gem.coop namespace --- lib/hanami/cli/generators/context.rb | 7 ++ lib/hanami/cli/generators/gem/app/gemfile.erb | 34 +++++++-- spec/unit/hanami/cli/commands/gem/new_spec.rb | 70 +++++++++++++++++++ 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/lib/hanami/cli/generators/context.rb b/lib/hanami/cli/generators/context.rb index 9bfc538e..f160da81 100644 --- a/lib/hanami/cli/generators/context.rb +++ b/lib/hanami/cli/generators/context.rb @@ -85,6 +85,13 @@ def gem_source "https://#{value}" end + # @since NEXT + # @api private + def gem_coop? + value = options.fetch(:gem_source) + value.match? %r{(\A\w+://)?gem.coop} + end + # @since 2.1.0 # @api private def generate_assets? diff --git a/lib/hanami/cli/generators/gem/app/gemfile.erb b/lib/hanami/cli/generators/gem/app/gemfile.erb index 20488f6b..cf2e2a3f 100644 --- a/lib/hanami/cli/generators/gem/app/gemfile.erb +++ b/lib/hanami/cli/generators/gem/app/gemfile.erb @@ -2,6 +2,22 @@ source "<%= gem_source %>" +<%- if gem_coop? and !hanami_head? -%> +source "https://gem.coop/@hanami" do + <%= hanami_gem("hanami") %> + <%- if generate_assets? -%> + <%= hanami_gem("assets") %> + <%- end -%> + <%= hanami_gem("action") %> + <%- if generate_db? -%> + <%= hanami_gem("db") %> + <%- end -%> + <%= hanami_gem("router") %> + <%- if generate_view? -%> + <%= hanami_gem("view") %> + <%- end -%> +end +<%- else -%> <%= hanami_gem("hanami") %> <%- if hanami_head? -%> <%= hanami_gem("cli") %> @@ -18,10 +34,20 @@ source "<%= gem_source %>" <%- if generate_view? -%> <%= hanami_gem("view") %> <%- end -%> +<%- end -%> + +<%- if gem_coop? -%> +source "https://gem.coop/@dry" do + gem "dry-types", "~> 1.7" + gem "dry-operation", ">= 1.0.1" + gem "dry-validation", "~> 1.11" +end +<%- else -%> gem "dry-types", "~> 1.7" gem "dry-operation", ">= 1.0.1" gem "dry-validation", "~> 1.11" +<%- end -%> gem "i18n", "~> 1.14" gem "puma", ">= 7.1" gem "rake" @@ -40,7 +66,7 @@ gem "slim" <%- end -%> group :development do - <%= hanami_gem("webconsole") %> + <%= hanami_gem("webconsole") %><%- if gem_coop? -%>, source: "https://gem.coop/@hanami"<% end %> end group :development, :test do @@ -52,13 +78,13 @@ group :development, :test do end group :cli, :development do - <%= hanami_gem("reloader") %> + <%= hanami_gem("reloader") %><%- if gem_coop? -%>, source: "https://gem.coop/@hanami"<% end %> end group :cli, :development, :test do <%- if generate_rspec? -%> - <%= hanami_gem("rspec") %> + <%= hanami_gem("rspec") %><%- if gem_coop? -%>, source: "https://gem.coop/@hanami"<% end %> <%- elsif generate_minitest? -%> - <%= hanami_gem("minitest") %> + <%= hanami_gem("minitest") %><%- if gem_coop? -%>, source: "https://gem.coop/@hanami"<% end %> <%- end -%> end diff --git a/spec/unit/hanami/cli/commands/gem/new_spec.rb b/spec/unit/hanami/cli/commands/gem/new_spec.rb index 05ab93e1..5a07a5e6 100644 --- a/spec/unit/hanami/cli/commands/gem/new_spec.rb +++ b/spec/unit/hanami/cli/commands/gem/new_spec.rb @@ -614,6 +614,76 @@ class Operation < Dry::Operation end context "with gem-source" do + context "with gem.coop" do + it "generates an app with gem.coop as gem source and scoped sources" do + expect(bundler).to receive(:install!) + .and_return(true) + + expect(bundler).to receive(:exec) + .with("hanami install") + .and_return(successful_system_call_result) + + expect(bundler).to receive(:exec) + .with("check") + .at_least(1) + .and_return(successful_system_call_result) + + expect(system_call).to receive(:call).with("npm", ["install"]) + + subject.call(app: app, **kwargs.merge(gem_source: "gem.coop")) + + expect(fs.directory?(app)).to be(true) + + fs.chdir(app) do + hanami_version = Hanami::CLI::Generators::Version.gem_requirement + gemfile = <<~EXPECTED + # frozen_string_literal: true + + source "https://gem.coop" + + source "https://gem.coop/@hanami" do + gem "hanami", "#{hanami_version}" + gem "hanami-assets", "#{hanami_version}" + gem "hanami-action", "#{hanami_version}" + gem "hanami-db", "#{hanami_version}" + gem "hanami-router", "#{hanami_version}" + gem "hanami-view", "#{hanami_version}" + end + + source "https://gem.coop/@dry" do + gem "dry-types", "~> 1.7" + gem "dry-operation", ">= 1.0.1" + gem "dry-validation", "~> 1.11" + end + + gem "i18n", "~> 1.14" + gem "puma", ">= 7.1" + gem "rake" + gem "sqlite3" + + group :development do + gem "hanami-webconsole", "#{hanami_version}", source: "https://gem.coop/@hanami" + end + + group :development, :test do + gem "dotenv" + # Syntax highlighting SQL logs + gem "rouge" + end + + group :cli, :development do + gem "hanami-reloader", "#{hanami_version}", source: "https://gem.coop/@hanami" + end + + group :cli, :development, :test do + gem "hanami-rspec", "#{hanami_version}", source: "https://gem.coop/@hanami" + end + EXPECTED + expect(fs.read("Gemfile")).to eq(gemfile) + end + end + end + context "without scheme" do it "generates an app with a custom gem source" do expect(bundler).to receive(:install!) From f9d97d835ab8a38e6aa741e0001d2dba51b39f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=9Awi=C4=85tkowski?= Date: Wed, 10 Jun 2026 12:00:25 +0200 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e97d136..b85a3647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Break Versioning](https://www.taoensso.com/break-ve - `hanami new` puts `dry-validation` in the app's `Gemfile` instead of `hanami-validations`. Hanami Validations will no longer be used; Hanami Action now checks for Dry Validation directly. (@timriley) - Update for `hanami-controller` gem rename to `hanami-action`. (@cllns in #402) +- When `--gem-source=gem.coop` is used, Hanami and Dry gems are installed from their respective namespaces on gem.coop (@katafrakt in #424) ### Deprecated