Skip to content

Add verify_license rake task with JSON output for CI#2385

Merged
justin808 merged 7 commits intomasterfrom
jg/pro-license-verify-rake
Feb 9, 2026
Merged

Add verify_license rake task with JSON output for CI#2385
justin808 merged 7 commits intomasterfrom
jg/pro-license-verify-rake

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Feb 9, 2026

Summary

  • Adds react_on_rails_pro:verify_license rake task that verifies the Pro license and displays status, organization, plan, expiration date, and days remaining
  • Supports FORMAT=json for machine-readable output suitable for GitHub Actions and other CI systems
  • Exits with code 0 for valid licenses and code 1 otherwise; JSON includes renewal_required flag for automated monitoring
  • Adds comprehensive documentation to LICENSE_SETUP.md including a complete GitHub Actions workflow example

Usage

# Human-readable output
bundle exec rake react_on_rails_pro:verify_license

# JSON output for CI
FORMAT=json bundle exec rake react_on_rails_pro:verify_license

Output examples

Text format (default)

Valid license:

React on Rails Pro — License Status
========================================
Status:        VALID
Organization:  Acme Corp
Plan:          paid
Expiration:    2026-05-09
Days left:     90
Attribution:   not required

License expiring within 30 days (exits 0 but warns):

React on Rails Pro — License Status
========================================
Status:        VALID
Organization:  Acme Corp
Plan:          paid
Expiration:    2026-02-23
Days left:     15
Attribution:   not required

WARNING: License expires within 30 days. Renew at https://www.shakacode.com/react-on-rails-pro/

Expired license (exits 1):

React on Rails Pro — License Status
========================================
Status:        EXPIRED
Organization:  Acme Corp
Plan:          paid
Expiration:    2026-01-29
Days left:     -10
Attribution:   not required

WARNING: License has expired. Renew at https://www.shakacode.com/react-on-rails-pro/

Missing license (exits 1):

React on Rails Pro — License Status
========================================
Status:        MISSING

No license found. Set REACT_ON_RAILS_PRO_LICENSE
or place a key file at config/react_on_rails_pro_license.key

JSON format (FORMAT=json)

Valid license:

{
  "status": "valid",
  "organization": "Acme Corp",
  "plan": "paid",
  "expiration": "2026-05-09T12:00:00Z",
  "attribution_required": false,
  "days_remaining": 90,
  "renewal_required": false
}

Expiring soon (renewal_required flips to true when ≤ 30 days remain):

{
  "status": "valid",
  "organization": "Acme Corp",
  "plan": "paid",
  "expiration": "2026-02-23T12:00:00Z",
  "attribution_required": false,
  "days_remaining": 15,
  "renewal_required": true
}

Expired:

{
  "status": "expired",
  "organization": "Acme Corp",
  "plan": "paid",
  "expiration": "2026-01-29T12:00:00Z",
  "attribution_required": false,
  "days_remaining": -10,
  "renewal_required": true
}

Missing:

{
  "status": "missing",
  "organization": null,
  "plan": null,
  "expiration": null,
  "attribution_required": null,
  "days_remaining": null,
  "renewal_required": false
}

Test plan

  • All 10 new specs pass for LicenseTaskFormatter (valid, expired, missing, expiring-soon scenarios for both text and JSON)
  • All 59 existing LicenseValidator specs still pass
  • RuboCop passes with no offenses
  • CI passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Rake-based license verification with human-readable and JSON outputs; task exits non‑zero for missing/invalid/expired licenses.
    • GitHub Actions workflow to monitor license expiry, emit status/days, and create deduplicated, labeled renewal issues for expiring/expired licenses.
  • Documentation

    • Updated guide with JSON schema/examples, expanded verification steps, console examples, and explicit field descriptions.
  • Tests

    • Comprehensive tests for JSON/text outputs across valid, expiring, expired, and missing license scenarios.

Add `react_on_rails_pro:verify_license` rake task that verifies the
Pro license and displays status, organization, plan, expiration date,
and days remaining. Supports FORMAT=json for machine-readable output
suitable for GitHub Actions and other CI systems.

The task exits with code 0 for valid licenses and code 1 otherwise.
JSON output includes a `renewal_required` flag (true when expired or
expiring within 30 days) for automated monitoring.

Also adds documentation to LICENSE_SETUP.md with a complete GitHub
Actions workflow example that checks license status weekly and creates
an issue when renewal is needed.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a rake-based license verification task, a LicenseTaskFormatter module to produce text/JSON outputs and compute expiration/renewal flags, RSpec tests for the formatter, and documentation including a GitHub Actions workflow to check license expiry and optionally open/label renewal issues.

Changes

Cohort / File(s) Summary
Documentation
react_on_rails_pro/LICENSE_SETUP.md
Replaces prior verification instructions with a recommended rake workflow; adds human-readable and JSON outputs, JSON schema/examples, exit-code rules, and a GitHub Actions "License Expiry Check" workflow that can parse JSON, detect expiring/expired licenses, and create/label deduplicated renewal issues.
Rake task
react_on_rails_pro/lib/tasks/license.rake
New react_on_rails_pro:verify_license rake task that reads FORMAT (text/json), obtains license info via ReactOnRailsPro::LicenseValidator.license_info, formats output with LicenseTaskFormatter, prints JSON or human-readable text, and fails (non-zero exit) when the license status is not valid.
Formatter implementation
react_on_rails_pro/lib/react_on_rails_pro/license_task_formatter.rb
New module ReactOnRailsPro::LicenseTaskFormatter with build_result, add_expiration_fields, and print_* helpers to compute days_remaining, renewal_required, format ISO8601 expiration, render human-readable sections, and print renewal guidance.
Tests
react_on_rails_pro/spec/react_on_rails_pro/license_task_formatter_spec.rb
Adds RSpec coverage for build_result and printing behavior across valid, missing, expiring, and expired licenses; verifies text and JSON outputs; uses JWT fixtures and task-loading/test helpers.
Changelog
CHANGELOG.md
Documents the new react_on_rails_pro:verify_license rake task, JSON output support, exit codes, and included GitHub Actions workflow example.

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler as Scheduler (GitHub Actions)
  participant Runner as Runner (Actions)
  participant App as Rails App (rake task)
  participant Parser as JSON Parser (jq)
  participant GH as GitHub API

  Scheduler->>Runner: trigger scheduled workflow
  Runner->>App: run `bundle exec rake react_on_rails_pro:verify_license FORMAT=json`
  App-->>Runner: emit JSON license status
  Runner->>Parser: parse JSON for status & days_remaining
  Parser-->>Runner: parsed status + days
  alt renewal required or expired
    Runner->>GH: search existing issues (dedupe)
    alt no duplicate found
      Runner->>GH: create issue
      Runner->>GH: add label(s)
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through JSON, counted days with care,

I nudged the rake and whispered, "Do your share."
If expiry nears or certificates sigh,
I'll tap the issue door and give a soft cry.
Small checks, tidy notes — a rabbit's little repair.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add verify_license rake task with JSON output for CI' directly and clearly summarizes the main change: a new Rake task for license verification with JSON output tailored for CI/CD use, which is the primary focus of the entire changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jg/pro-license-verify-rake

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

Adds react_on_rails_pro:verify_license rake task with dual output formats (human-readable text and machine-parseable JSON). The implementation cleanly separates formatting logic into LicenseTaskFormatter module, which calculates days_remaining and renewal_required fields from existing LicenseValidator.license_info. The task exits with code 1 for non-valid licenses (expired, invalid, missing) and code 0 for valid licenses.

Key changes:

  • New LicenseTaskFormatter module handles all output formatting
  • Rake task uses raise (composable with rake dependencies) instead of exit 1 per previous feedback
  • JSON format controlled via FORMAT=json env var
  • renewal_required flag triggers at ≤30 days or expired status
  • Comprehensive test suite with 10 specs covering all status scenarios
  • Documentation updated with complete GitHub Actions example for automated license monitoring

Documentation note: The GitHub Actions workflow includes a note about jq pre-installation on ubuntu-latest runners, addressing previous review feedback.

Confidence Score: 5/5

  • Safe to merge with no blocking issues
  • Implementation is clean, well-tested, and addresses all previous review feedback. The formatter module has excellent separation of concerns, comprehensive test coverage, and the rake task correctly uses raise for composability. Documentation is thorough with helpful examples and appropriate caveats about jq availability.
  • No files require special attention

Important Files Changed

Filename Overview
react_on_rails_pro/lib/react_on_rails_pro/license_task_formatter.rb New formatter module with clean separation of concerns; well-structured methods for building JSON results and printing text output
react_on_rails_pro/lib/tasks/license.rake Simple rake task that formats output based on ENV var and raises on invalid licenses; uses composable approach from previous review feedback
react_on_rails_pro/spec/react_on_rails_pro/license_task_formatter_spec.rb Comprehensive test coverage with 10 specs covering valid, expired, missing, and expiring-soon scenarios in both text and JSON formats
react_on_rails_pro/LICENSE_SETUP.md Added detailed verification section with rake task examples, JSON field descriptions, and complete GitHub Actions workflow for automated monitoring

Sequence Diagram

sequenceDiagram
    participant User
    participant RakeTask as verify_license rake task
    participant Formatter as LicenseTaskFormatter
    participant Validator as LicenseValidator
    participant ENV as Environment/Config

    User->>RakeTask: bundle exec rake react_on_rails_pro:verify_license
    Note over User,RakeTask: Optional: FORMAT=json env var
    
    RakeTask->>ENV: ENV.fetch("FORMAT", "text")
    ENV-->>RakeTask: format (text or json)
    
    RakeTask->>Validator: license_info()
    Validator->>ENV: load_license_string()
    ENV-->>Validator: JWT token
    Validator->>Validator: decode & validate JWT
    Validator-->>RakeTask: info hash {status, org, plan, expiration, attribution_required}
    
    RakeTask->>Formatter: build_result(info)
    Formatter->>Formatter: calculate days_remaining
    Formatter->>Formatter: set renewal_required
    Formatter-->>RakeTask: result hash
    
    alt JSON format
        RakeTask->>RakeTask: JSON.pretty_generate(result)
        RakeTask->>User: JSON output
    else Text format
        RakeTask->>Formatter: print_text(result, info)
        Formatter->>User: Formatted text output
    end
    
    alt status != :valid
        RakeTask->>RakeTask: raise error
        RakeTask-->>User: exit code 1
    else status == :valid
        RakeTask-->>User: exit code 0
    end
Loading

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +83 to +90
if format.casecmp("json").zero?
require "json"
puts JSON.pretty_generate(result)
else
ReactOnRailsPro::LicenseTaskFormatter.print_text(result, info)
end

exit 1 if info[:status] != :valid
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rake aborts even in JSON
exit 1 will terminate the entire rake process (and any task dependencies) even when this task is invoked as part of a larger rake run. That’s fine for a dedicated CI check, but it’s a footgun if someone calls react_on_rails_pro:verify_license from another task (or uses rake -T/task chaining) because it will hard-exit instead of letting rake unwind normally. Consider using abort with a message (text mode) or raising a RuntimeError so callers can handle failures, while still yielding a non-zero exit in CI.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread react_on_rails_pro/LICENSE_SETUP.md Outdated
Comment on lines +193 to +201
- name: Check license status
id: license
env:
REACT_ON_RAILS_PRO_LICENSE: ${{ secrets.REACT_ON_RAILS_PRO_LICENSE }}
RAILS_ENV: production
run: |
result=$(FORMAT=json bundle exec rake react_on_rails_pro:verify_license 2>/dev/null) || true
echo "$result"
echo "json=$result" >> "$GITHUB_OUTPUT"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GHA example uses jq
The documented GitHub Actions workflow parses JSON via jq, but the workflow doesn’t install jq. On ubuntu-latest this may be present today, but it’s not guaranteed by the workflow itself; if it’s missing, the step will fail even when verify_license works. Either add an explicit apt-get install jq step or adjust the example to avoid jq.

Comment on lines +7 to +10
# Load the rake task to define the LicenseTaskFormatter module
task_file = File.expand_path("../../lib/tasks/license.rake", __dir__)
load task_file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rake task loaded globally
This spec does a top-level load of lib/tasks/license.rake, which defines a rake task in the global Rake.application. In a larger test suite this can leak tasks across specs and cause order-dependent failures (e.g., “task already defined” or unexpected tasks present). Prefer isolating by using a fresh Rake::Application per spec (or moving the formatter to a Ruby file that specs can require without defining rake tasks).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already addressed — the spec does not load license.rake. It only requires the pure Ruby module react_on_rails_pro/license_task_formatter (line 5), which defines no rake tasks. The formatter was intentionally extracted into lib/react_on_rails_pro/license_task_formatter.rb specifically so specs can test it without polluting the global Rake.application.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@react_on_rails_pro/LICENSE_SETUP.md`:
- Around line 198-209: The workflow currently writes possibly-multiline JSON
into GITHUB_OUTPUT via echo "json=$result", which corrupts the outputs; fix by
either removing the unused json output line (remove the echo "json=$result" >>
"$GITHUB_OUTPUT" and its echo "$result") or replace that line with the
heredoc-style output for multiline values (use cat <<EOF >> "$GITHUB_OUTPUT"
followed by "json=" then the multiline $result and EOF) and keep the subsequent
parsing of result into status/days/renewal unchanged so variables status, days,
and renewal are still written with echo "...=$var" >> "$GITHUB_OUTPUT".
- Line 130: Add a language specifier to the fenced code block in
LICENSE_SETUP.md: locate the plain triple-backtick fenced code block (``` ) and
change it to ```text so the markdownlint rule is satisfied; ensure only the
fence is modified and no other content is altered.
🧹 Nitpick comments (3)
react_on_rails_pro/LICENSE_SETUP.md (1)

215-220: Script injection risk via steps.license.outputs in the github-script body.

The values status and days are interpolated directly into the JavaScript template via ${{ steps.license.outputs.status }}. If a crafted license token somehow produces a status string containing a single quote followed by JavaScript, it could break or inject code into the script block. This is a low-probability risk given these values come from your own rake task, but the standard GitHub Actions hardening practice is to pass outputs as environment variables instead:

Suggested hardening
       - name: Create issue if renewal needed
         if: steps.license.outputs.renewal_required == 'true'
         uses: actions/github-script@v7
+        env:
+          LICENSE_STATUS: ${{ steps.license.outputs.status }}
+          LICENSE_DAYS: ${{ steps.license.outputs.days_remaining }}
         with:
           script: |
-            const status = '${{ steps.license.outputs.status }}';
-            const days = '${{ steps.license.outputs.days_remaining }}';
+            const status = process.env.LICENSE_STATUS;
+            const days = process.env.LICENSE_DAYS;
react_on_rails_pro/lib/tasks/license.rake (1)

3-6: Consider extracting LicenseTaskFormatter to its own file.

Defining a module inside a .rake file is unusual — tests must load the rake file directly to access it, and the module won't be autoloaded by Rails. Extracting it to lib/react_on_rails_pro/license_task_formatter.rb would make it independently require-able and follow standard Rails conventions.

react_on_rails_pro/spec/react_on_rails_pro/license_task_formatter_spec.rb (1)

229-238: private keyword has no effect inside an RSpec describe block.

The private on line 229 doesn't actually restrict visibility here — RSpec defines helper methods on the example group class, and private at this level doesn't behave as intended. The method works fine regardless, so this is purely cosmetic. You could simply remove the private line or leave it as a visual hint for readers.

Comment thread react_on_rails_pro/LICENSE_SETUP.md Outdated
Comment thread react_on_rails_pro/LICENSE_SETUP.md
justin808 and others added 2 commits February 8, 2026 17:28
Fixes markdownlint MD040 warning by adding `text` language specifier
to the example output code block.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Extract LicenseTaskFormatter to its own Ruby file so specs can
  require it without loading/leaking rake tasks globally
- Replace exit 1 with abort so the task doesn't hard-exit the
  process when invoked from other rake tasks
- Add note to GitHub Actions example that jq is pre-installed on
  ubuntu-latest but may need explicit install on custom runners

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 9, 2026

Code Review

I found one issue that should be addressed:

Missing CHANGELOG Entry

This PR adds a new user-visible feature (rake react_on_rails_pro:verify_license task with JSON output for CI) that should be documented in the CHANGELOG.

According to AGENTS.md line 165-168:

Update /CHANGELOG.md for user-visible changes only (features, bug fixes, breaking changes, deprecations, performance improvements).

Since this is a Pro-only feature, it should be added to CHANGELOG.md under the #### Pro section under ##### Added.

Suggested entry:

- **License verification rake task**: New `react_on_rails_pro:verify_license` rake task for checking license validity with both human-readable text output and JSON format (`FORMAT=json`) for CI/CD integration. Includes exit codes (0 for valid, 1 for invalid/expired), automatic renewal warnings for licenses expiring within 30 days, and comprehensive JSON output with all license details. [PR 2385](https://github.com/shakacode/react_on_rails/pull/2385) by [justin808](https://github.com/justin808).

Otherwise, the implementation looks solid with comprehensive test coverage and excellent documentation.

justin808 and others added 2 commits February 8, 2026 17:38
Replace bare `abort` with `raise` so callers that invoke
verify_license from another rake task can rescue the error
instead of having the entire process hard-exit.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The `echo "json=$result"` line wrote multiline JSON into GITHUB_OUTPUT,
which corrupts it (only the first line is captured). Since only the
individual fields (status, days_remaining, renewal_required) are used
downstream, remove the unused json output line entirely.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@justin808
Copy link
Copy Markdown
Member Author

@greptile, review this PR.
@claude, review this PR.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 9, 2026

Claude finished @justin808's task in 1m 43s —— View job


PR Review Complete

Todo List

  • Read repository guidelines (CLAUDE.md, AGENTS.md)
  • Review all changed files
  • Check if previous review comments were addressed
  • Analyze code quality and correctness
  • Check CHANGELOG entry
  • Post comprehensive review feedback

Summary

This PR adds a well-designed rake react_on_rails_pro:verify_license task with both human-readable text output and machine-readable JSON for CI/CD integration. The implementation is solid, test coverage is comprehensive, and documentation is excellent. Previous review issues have been addressed in commits b4c9261, 1e4900e, 8c4eeef, and 59e9ed2.

Issues Found

❌ Missing CHANGELOG Entry

According to AGENTS.md:165-168, user-visible changes require a CHANGELOG entry. This PR adds a new user-facing feature that should be documented.

Required Action: Add an entry to CHANGELOG.md under #### Pro##### Added:

- **License verification rake task**: New `react_on_rails_pro:verify_license` rake task for checking license validity with both human-readable text output and JSON format (`FORMAT=json`) for CI/CD integration. Includes exit codes (0 for valid, 1 for invalid/expired), automatic renewal warnings for licenses expiring within 30 days, and comprehensive JSON output with all license details. See LICENSE_SETUP.md for usage examples including GitHub Actions workflow. [PR 2385](https://github.com/shakacode/react_on_rails/pull/2385) by [justin808](https://github.com/justin808).

What Works Well

✅ Code Quality

react_on_rails_pro/lib/react_on_rails_pro/license_task_formatter.rb:1-74

  • Clean separation of concerns: formatter is pure Ruby, no rake dependencies
  • Well-structured methods with single responsibilities
  • Proper use of module_function for utility module
  • Good naming conventions throughout

react_on_rails_pro/lib/tasks/license.rake:1-21

  • Simple, focused rake task
  • Uses raise (line 19) which is appropriate for rake tasks (per commit 59e9ed2)
  • Clean integration with the formatter module
  • Case-insensitive FORMAT detection (line 12)

✅ Test Coverage

react_on_rails_pro/spec/react_on_rails_pro/license_task_formatter_spec.rb:1-235

  • Comprehensive coverage: valid, expired, missing, and expiring-soon scenarios
  • Tests both text and JSON output formats
  • Proper use of JWT fixtures with test key pairs
  • Good use of RSpec patterns: let blocks, context blocks, named subjects
  • Clean helper method capture_stdout (lines 227-234)

✅ Documentation

react_on_rails_pro/LICENSE_SETUP.md:114-249

  • Excellent user-facing documentation
  • Clear examples for both text and JSON output
  • Complete GitHub Actions workflow example with deduplication logic
  • Explicit note about jq being pre-installed on ubuntu-latest (lines 173-175) - addresses Greptile's concern
  • JSON field table is comprehensive and helpful (lines 158-167)

✅ Previous Review Issues Addressed

All issues from CodeRabbit and Greptile reviews have been resolved:

  • ✅ Markdown language specifier added (commit 1e4900e)
  • ✅ Multiline JSON output removed from GitHub Actions example (commit b4c9261)
  • ✅ Formatter extracted to separate file (commit 8c4eeef)
  • ✅ Changed from exit 1 to raise for composability (commit 59e9ed2)
  • ✅ Added jq availability note (commit 8c4eeef)
  • ✅ Formatter is in its own file, no global rake task pollution in specs

Code Review Notes

Design Decisions (All Good)

  1. Exit code strategy: Using raise (line 19) is the right choice for rake tasks - it provides composability while still exiting with code 1 when run standalone.

  2. JSON schema design: The renewal_required flag (lines 16, 26) is excellent for automation - flips to true when ≤ 30 days remain OR expired.

  3. Date formatting: ISO 8601 for JSON (line 13), human-readable for text (line 59) - appropriate for each context.

  4. Days calculation: Uses ceil (line 24) which is correct - "15.1 days" should show as "16 days left" to be conservative.

Minor Observations (Non-blocking)

  1. Line 8-9 in license.rake: Format detection with ENV.fetch("FORMAT", "text") works well, though ENV.fetch("FORMAT", "text").downcase would make line 12 simpler. Not worth changing.

  2. Lines 30-72 in formatter: The text printing methods are well-organized but could theoretically be split into a separate presenter class if they grow. Current structure is fine for this scope.

  3. Security note: GitHub Actions workflow (lines 215-220) interpolates outputs into JavaScript. While the risk is minimal (values come from your own rake task), CodeRabbit's suggestion to use environment variables is a valid hardening approach if you want defense-in-depth.

Test Results Mentioned in PR

According to the PR description:

  • ✅ All 10 new specs pass for LicenseTaskFormatter
  • ✅ All 59 existing LicenseValidator specs still pass
  • ✅ RuboCop passes with no offenses
  • ⏳ CI pending

Overall Assessment

Ready to merge once CHANGELOG entry is added. The implementation is production-ready with excellent test coverage and documentation. All previous review concerns have been addressed.


Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@CHANGELOG.md`:
- Line 51: The CHANGELOG entry describing the new
`react_on_rails_pro:verify_license` rake task is Pro-only and should be moved
out of the main CHANGELOG.md; remove the listed bullet from CHANGELOG.md and add
the same entry into CHANGELOG_PRO.md (or add it to both files only if the change
affects the OSS gem as well), keeping the text, PR link, author attribution, and
the `FORMAT=json`/exit-code details intact so the Pro changelog accurately
reflects this Pro-only feature.

Comment thread CHANGELOG.md
##### Added

- **Multiple License Plan Types**: License validation now supports multiple plan types beyond "paid": `startup`, `nonprofit`, `education`, `oss`, and `partner`. Non-paid plan types are displayed in the license validation success message (e.g., "License validated successfully (startup license)."). Includes thread-safe caching for plan type retrieval via `LicenseValidator.license_plan`. [PR 2334](https://github.com/shakacode/react_on_rails/pull/2334) by [justin808](https://github.com/justin808).
- **License verification rake task**: New `react_on_rails_pro:verify_license` rake task for checking license status with human-readable text and JSON output (`FORMAT=json`) for CI/CD integration. Includes exit codes, automatic renewal warnings for licenses expiring within 30 days, and a GitHub Actions workflow example. [PR 2385](https://github.com/shakacode/react_on_rails/pull/2385) by [justin808](https://github.com/justin808).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Move this Pro-only entry to CHANGELOG_PRO.md (or both if it impacts OSS).

This change appears Pro-only, so it should live in the Pro changelog rather than the unified one unless it affects both packages.

Based on learnings: “Pro-only changes go in CHANGELOG_PRO.md; changes affecting both gem and Pro package go in both changelogs”.

🤖 Prompt for AI Agents
In `@CHANGELOG.md` at line 51, The CHANGELOG entry describing the new
`react_on_rails_pro:verify_license` rake task is Pro-only and should be moved
out of the main CHANGELOG.md; remove the listed bullet from CHANGELOG.md and add
the same entry into CHANGELOG_PRO.md (or add it to both files only if the change
affects the OSS gem as well), keeping the text, PR link, author attribution, and
the `FORMAT=json`/exit-code details intact so the Pro changelog accurately
reflects this Pro-only feature.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 9, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

These three Pro changes shipped in 16.3.0 but were incorrectly listed
under Unreleased.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant