Add verify_license rake task with JSON output for CI#2385
Conversation
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]>
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
Greptile OverviewGreptile SummaryAdds Key changes:
Documentation note: The GitHub Actions workflow includes a note about Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
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
|
| 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 |
There was a problem hiding this comment.
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!
| - 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" |
There was a problem hiding this comment.
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.
| # Load the rake task to define the LicenseTaskFormatter module | ||
| task_file = File.expand_path("../../lib/tasks/license.rake", __dir__) | ||
| load task_file | ||
|
|
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 viasteps.license.outputsin thegithub-scriptbody.The values
statusanddaysare 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 extractingLicenseTaskFormatterto its own file.Defining a module inside a
.rakefile is unusual — tests mustloadthe rake file directly to access it, and the module won't be autoloaded by Rails. Extracting it tolib/react_on_rails_pro/license_task_formatter.rbwould make it independentlyrequire-able and follow standard Rails conventions.react_on_rails_pro/spec/react_on_rails_pro/license_task_formatter_spec.rb (1)
229-238:privatekeyword has no effect inside an RSpecdescribeblock.The
privateon line 229 doesn't actually restrict visibility here — RSpec defines helper methods on the example group class, andprivateat this level doesn't behave as intended. The method works fine regardless, so this is purely cosmetic. You could simply remove theprivateline or leave it as a visual hint for readers.
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]>
Code ReviewI found one issue that should be addressed: Missing CHANGELOG EntryThis PR adds a new user-visible feature ( According to AGENTS.md line 165-168:
Since this is a Pro-only feature, it should be added to 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. |
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]>
|
@greptile, review this PR. |
|
Claude finished @justin808's task in 1m 43s —— View job PR Review CompleteTodo List
SummaryThis PR adds a well-designed Issues Found❌ Missing CHANGELOG EntryAccording 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 - **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 Qualityreact_on_rails_pro/lib/react_on_rails_pro/license_task_formatter.rb:1-74
react_on_rails_pro/lib/tasks/license.rake:1-21
✅ Test Coveragereact_on_rails_pro/spec/react_on_rails_pro/license_task_formatter_spec.rb:1-235
✅ Documentationreact_on_rails_pro/LICENSE_SETUP.md:114-249
✅ Previous Review Issues AddressedAll issues from CodeRabbit and Greptile reviews have been resolved:
Code Review NotesDesign Decisions (All Good)
Minor Observations (Non-blocking)
Test Results Mentioned in PRAccording to the PR description:
Overall AssessmentReady 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. |
Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
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.
| ##### 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). |
There was a problem hiding this comment.
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.
Code reviewNo 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]>
Summary
react_on_rails_pro:verify_licenserake task that verifies the Pro license and displays status, organization, plan, expiration date, and days remainingFORMAT=jsonfor machine-readable output suitable for GitHub Actions and other CI systemsrenewal_requiredflag for automated monitoringLICENSE_SETUP.mdincluding a complete GitHub Actions workflow exampleUsage
Output examples
Text format (default)
Valid license:
License expiring within 30 days (exits 0 but warns):
Expired license (exits 1):
Missing license (exits 1):
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_requiredflips totruewhen ≤ 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
LicenseTaskFormatter(valid, expired, missing, expiring-soon scenarios for both text and JSON)LicenseValidatorspecs still pass🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests