From 361f647a71ba81faf83b367090000c4a897a6bbf Mon Sep 17 00:00:00 2001 From: Denis Talakevich Date: Wed, 6 May 2026 16:04:31 +0300 Subject: [PATCH] add support of active admin v4 --- .github/workflows/ci.yml | 17 ++++------- .gitignore | 5 ++++ Gemfile | 26 ++++++----------- activeadmin-oidc.gemspec | 9 ++++-- .../active_admin/devise/sessions/new.html.erb | 29 +++++++++++++++---- gemfiles/activeadmin_3.5.gemfile | 16 ++++++++++ gemfiles/activeadmin_4.0.gemfile | 19 ++++++++++++ lib/activeadmin-oidc.rb | 10 +++++++ .../oidc/install/install_generator.rb | 19 ++++++++++-- .../templates/sessions_new_v4.html.erb | 12 ++++++++ 10 files changed, 122 insertions(+), 40 deletions(-) create mode 100644 gemfiles/activeadmin_3.5.gemfile create mode 100644 gemfiles/activeadmin_4.0.gemfile create mode 100644 lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed6c919..61a81a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,24 +9,17 @@ permissions: jobs: test: - name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }} / AA ${{ matrix.activeadmin }} / OOIDC ${{ matrix.omniauth_openid_connect }} + name: Ruby ${{ matrix.ruby }} / ${{ matrix.gemfile }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: ruby: ['3.2', '3.3', '3.4'] - rails: ['7.2.0', '8.0.0'] - activeadmin: ['3.5.0'] - # 0.6.x → openid_connect 1.x (httpclient, no faraday dep). - # 0.7.x / 0.8.x → openid_connect 2.x (faraday 2.x). - omniauth_openid_connect: ['0.6.0', '0.7.0', '0.8.0'] - # AA 3.4.0 is excluded: it pins devise < 5, which is - # incompatible with the devise >= 4.9 floor this gem needs. - # Support starts at ActiveAdmin 3.5, which lifted that cap. + gemfile: + - gemfiles/activeadmin_3.5.gemfile + - gemfiles/activeadmin_4.0.gemfile env: - RAILS: ${{ matrix.rails }} - AA: ${{ matrix.activeadmin }} - OOIDC: ${{ matrix.omniauth_openid_connect }} + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 diff --git a/.gitignore b/.gitignore index 970778d..34bd2a2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,11 +11,16 @@ .DS_Store .rspec_status /Gemfile.lock +/gemfiles/*.lock /spec/dummy/log/ /spec/dummy/tmp/ /spec/dummy/db/*.sqlite3 /spec/dummy/db/*.sqlite3-journal /spec/dummy/storage/ +/spec/dummy_engine/log/ +/spec/dummy_engine/tmp/ +/spec/dummy_isolated/log/ +/spec/dummy_isolated/tmp/ # The dummy app's database.yml is checked in — override a global # ignore rule that excludes "database.yml" everywhere by default. diff --git a/Gemfile b/Gemfile index 34184fc..b839084 100644 --- a/Gemfile +++ b/Gemfile @@ -1,19 +1,11 @@ # frozen_string_literal: true -source "https://rubygems.org" - -gemspec - -default_rails_version = "7.2.0" -default_activeadmin_version = "3.5.0" - -rails_version = ENV.fetch("RAILS", default_rails_version) -activeadmin_version = ENV.fetch("AA", default_activeadmin_version) -# 0.6.x uses openid_connect 1.x (httpclient, no faraday) — required for -# host apps still on faraday 1.x. 0.7.x uses openid_connect 2.x (faraday 2.x). -ooidc_version = ENV["OOIDC"] - -gem "rails", "~> #{rails_version}" -gem "activerecord", "~> #{rails_version}" -gem "activeadmin", "~> #{activeadmin_version}" -gem "omniauth_openid_connect", "~> #{ooidc_version}" if ooidc_version +# Local development and `rake spec:all` (run without BUNDLE_GEMFILE) +# default to the ActiveAdmin 3.5 stack. CI selects a specific stack via +# BUNDLE_GEMFILE — see gemfiles/activeadmin_3.5.gemfile (Sprockets/Sassc) +# and gemfiles/activeadmin_4.0.gemfile (Propshaft/importmap/Tailwind). +# +# eval_gemfile keeps a single source of truth: the `gemspec path: ".."` +# inside the eval'd file resolves relative to gemfiles/, i.e. this repo +# root, exactly as it does when CI loads the gemfile directly. +eval_gemfile File.expand_path("gemfiles/activeadmin_3.5.gemfile", __dir__) diff --git a/activeadmin-oidc.gemspec b/activeadmin-oidc.gemspec index 5921b54..c443dc1 100644 --- a/activeadmin-oidc.gemspec +++ b/activeadmin-oidc.gemspec @@ -27,7 +27,7 @@ Gem::Specification.new do |spec| ] spec.require_paths = ["lib"] - spec.add_dependency "activeadmin", ">= 3.5", "< 4" + spec.add_dependency "activeadmin", ">= 3.5", "< 5" # Devise 5.0 wraps `Devise.mappings` with `reload_routes_unless_loaded` # (heartcombo/devise#5728) so OmniAuth's failure handler works under # Rails 8 lazy route loading without an engine-side workaround. @@ -46,8 +46,11 @@ Gem::Specification.new do |spec| spec.add_development_dependency "webmock", ">= 3.19" spec.add_development_dependency "jwt", ">= 2.7" spec.add_development_dependency "sqlite3", ">= 1.7" - spec.add_development_dependency "sprockets-rails", ">= 3.4" - spec.add_development_dependency "sassc-rails", ">= 2.1" + # The asset pipeline gems live in the per-version gemfiles under + # gemfiles/ rather than here: ActiveAdmin 3.5 needs Sprockets + Sassc, + # while ActiveAdmin 4.0 needs Propshaft + importmap + cssbundling + + # Tailwind. Keeping them out of the gemspec lets each gemfile install + # exactly one asset stack instead of both. spec.add_development_dependency "rake", ">= 13.0" spec.add_development_dependency "rubocop", ">= 1.60" spec.add_development_dependency "rubocop-rails", ">= 2.20" diff --git a/app/views/active_admin/devise/sessions/new.html.erb b/app/views/active_admin/devise/sessions/new.html.erb index f87e671..7c49318 100644 --- a/app/views/active_admin/devise/sessions/new.html.erb +++ b/app/views/active_admin/devise/sessions/new.html.erb @@ -1,7 +1,24 @@ -
-

<%= active_admin_application.site_title(self) %>

+<% if ActiveAdmin::Oidc.aa_v4? %> +
+

+ <%= site_title %> <%= set_page_title t('active_admin.devise.login.title') %> +

- <%= form_tag omniauth_authorize_path(resource_name, :oidc), method: :post, data: { turbo: false } do %> - <%= submit_tag ActiveAdmin::Oidc.config.login_button_label %> - <% end %> -
+ <%= button_to ActiveAdmin::Oidc.config.login_button_label, + "/admin/auth/oidc", + method: :post, + class: "activeadmin-oidc-login-button w-full", + form_class: 'formtastic', + data: { turbo: false } %> +
+<% else %> +
+

<%= active_admin_application.site_title(self) %>

+ + <%= button_to ActiveAdmin::Oidc.config.login_button_label, + "/admin/auth/oidc", + method: :post, + class: "activeadmin-oidc-login-button", + data: { turbo: false } %> +
+<% end %> diff --git a/gemfiles/activeadmin_3.5.gemfile b/gemfiles/activeadmin_3.5.gemfile new file mode 100644 index 0000000..a81b26f --- /dev/null +++ b/gemfiles/activeadmin_3.5.gemfile @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec path: ".." + +# ActiveAdmin 3.5 line: classic Sprockets + Sassc asset pipeline. +gem "activeadmin", "~> 3.5.0" +gem "rails", "~> 7.2.0" + +# openid_connect 1.x line (httpclient-based, no faraday dep). Pinning the +# 0.6.x series here keeps CI exercising the pre-faraday strategy path. +gem "omniauth_openid_connect", "~> 0.6.0" + +gem "sprockets-rails", ">= 3.4" +gem "sassc-rails", ">= 2.1" diff --git a/gemfiles/activeadmin_4.0.gemfile b/gemfiles/activeadmin_4.0.gemfile new file mode 100644 index 0000000..dc65df7 --- /dev/null +++ b/gemfiles/activeadmin_4.0.gemfile @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec path: ".." + +# ActiveAdmin 4.0 line (currently shipping as 4.0.0.beta*). AA 4 replaces +# the Sprockets/Sassc pipeline with Propshaft + importmap + cssbundling + +# Tailwind, so the asset gems differ entirely from the 3.5 gemfile. +gem "activeadmin", ">= 4.0.0.beta", "< 5" +gem "rails", "~> 8.0.0" + +# openid_connect 2.x line (faraday 2.x). +gem "omniauth_openid_connect", "~> 0.8.0" + +gem "propshaft" +gem "importmap-rails" +gem "cssbundling-rails" +gem "tailwindcss-rails", "~> 4.0" diff --git a/lib/activeadmin-oidc.rb b/lib/activeadmin-oidc.rb index 99f5cbd..dc6544b 100644 --- a/lib/activeadmin-oidc.rb +++ b/lib/activeadmin-oidc.rb @@ -3,6 +3,7 @@ require "logger" require "active_support/core_ext/object/blank" require "activeadmin/oidc/version" +require "active_admin/version" # `omniauth-rails_csrf_protection` registers a Railtie that replaces # OmniAuth 2.x's Rack-level authenticity check with Rails' own forgery @@ -53,6 +54,15 @@ def reset! @logger = nil end + # True when the installed ActiveAdmin is the 4.x line (including the + # 4.0.0 prereleases). AA 4 ships a Tailwind-based admin layout, so + # the login view override must emit Tailwind markup instead of the + # legacy `#login` structure AA 3.x expects. Mirrors the version probe + # ActiveAdmin plugins use (e.g. activeadmin_table_footer's styles.rb). + def aa_v4? + ::Gem::Version.new(::ActiveAdmin::VERSION) >= ::Gem::Version.new("4.0.0.beta1") + end + private def default_logger diff --git a/lib/generators/active_admin/oidc/install/install_generator.rb b/lib/generators/active_admin/oidc/install/install_generator.rb index 3fe5b04..e46cbb5 100644 --- a/lib/generators/active_admin/oidc/install/install_generator.rb +++ b/lib/generators/active_admin/oidc/install/install_generator.rb @@ -2,6 +2,7 @@ require "rails/generators/base" require "rails/generators/active_record" +require "active_admin/version" module ActiveAdmin module Oidc @@ -74,8 +75,13 @@ def create_migration_file end def create_view_override - copy_file "sessions_new.html.erb", - "app/views/active_admin/devise/sessions/new.html.erb" + if aa_v4? + copy_file "sessions_new_v4.html.erb", + "app/views/active_admin/devise/sessions/new.html.erb" + else + copy_file "sessions_new.html.erb", + "app/views/active_admin/devise/sessions/new.html.erb" + end end # Non-blocking: the generator completed successfully, but the @@ -142,6 +148,15 @@ def raw_info_column_type adapter = (ActiveRecord::Base.connection_db_config.adapter rescue "sqlite3").to_s adapter.start_with?("postgres") ? ":jsonb" : ":text" end + + # True when the installed ActiveAdmin is the 4.x line (including the + # 4.0.0 prereleases). AA 4 ships a Tailwind-based admin layout, so + # the login view override must emit Tailwind markup instead of the + # legacy `#login` structure AA 3.x expects. Mirrors the version probe + # ActiveAdmin plugins use (e.g. activeadmin_table_footer's styles.rb). + def aa_v4? + ::Gem::Version.new(::ActiveAdmin::VERSION) >= ::Gem::Version.new("4.0.0.beta1") + end end end end diff --git a/lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb b/lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb new file mode 100644 index 0000000..3140e29 --- /dev/null +++ b/lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb @@ -0,0 +1,12 @@ +
+

+ <%%= site_title %> <%%= set_page_title t('active_admin.devise.login.title') %> +

+ + <%%= button_to ActiveAdmin::Oidc.config.login_button_label, + "/admin/auth/oidc", + method: :post, + class: "activeadmin-oidc-login-button w-full", + form_class: 'formtastic', + data: { turbo: false } %> +