rolemodel-rails 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -2
- data/lib/generators/rolemodel/all_generator.rb +1 -0
- data/lib/generators/rolemodel/core_setup/README.md +27 -0
- data/lib/generators/rolemodel/core_setup/USAGE +12 -0
- data/lib/generators/rolemodel/core_setup/core_setup_generator.rb +19 -0
- data/lib/generators/rolemodel/github/README.md +4 -0
- data/lib/generators/rolemodel/github/templates/workflows/deploy-production.yml +34 -0
- data/lib/generators/rolemodel/github/templates/workflows/deploy-staging.yml +35 -0
- data/lib/generators/rolemodel/good_job/good_job_generator.rb +0 -2
- data/lib/generators/rolemodel/heroku/README.md +20 -1
- data/lib/generators/rolemodel/heroku/heroku_generator.rb +35 -0
- data/lib/generators/rolemodel/heroku/templates/app.json.tt +5 -2
- data/lib/generators/rolemodel/heroku/templates/deploy-app/SKILL.md +202 -0
- data/lib/generators/rolemodel/linters/eslint/eslint_generator.rb +1 -0
- data/lib/generators/rolemodel/linters/rubocop/rubocop_generator.rb +5 -1
- data/lib/generators/rolemodel/lograge/README.md +1 -1
- data/lib/generators/rolemodel/lograge/templates/config/initializers/lograge.rb +1 -1
- data/lib/generators/rolemodel/optics/base/base_generator.rb +1 -0
- data/lib/generators/rolemodel/react/react_generator.rb +1 -0
- data/lib/generators/rolemodel/readme/templates/README.md.erb +2 -4
- data/lib/generators/rolemodel/sentry/README.md +25 -0
- data/lib/generators/rolemodel/sentry/USAGE +13 -0
- data/lib/generators/rolemodel/sentry/sentry_generator.rb +126 -0
- data/lib/generators/rolemodel/sentry/templates/app/javascript/initializers/sentry.js +34 -0
- data/lib/generators/rolemodel/sentry/templates/config/initializers/sentry.rb +68 -0
- data/lib/generators/rolemodel/simple_form/README.md +6 -0
- data/lib/generators/rolemodel/simple_form/USAGE +3 -0
- data/lib/generators/rolemodel/simple_form/simple_form_generator.rb +11 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/switch_checkbox_input.rb +1 -1
- data/lib/generators/rolemodel/tailored_select/USAGE +2 -1
- data/lib/generators/rolemodel/tailored_select/tailored_select_generator.rb +15 -0
- data/lib/generators/rolemodel/testing/factory_bot/templates/support/factory_bot.rb +2 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/jasmine_playwright_generator.rb +2 -2
- data/lib/generators/rolemodel/testing/rspec/templates/spec/rails_helper.rb.tt +4 -1
- data/lib/generators/rolemodel/testing/rspec/templates/spec/support/capybara_drivers.rb.tt +2 -0
- data/lib/generators/rolemodel/testing/rspec/templates/spec/support/helpers/action_cable_helper.rb +2 -0
- data/lib/generators/rolemodel/testing/rspec/templates/spec/support/helpers/test_element_helper.rb +2 -0
- data/lib/generators/rolemodel/testing/rspec/templates/spec/support/helpers.rb.tt +3 -1
- data/lib/generators/rolemodel/testing/vitest/vitest_generator.rb +1 -0
- data/lib/generators/rolemodel/ui_components/modals/modals_generator.rb +1 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/helpers/turbo_frame_link_helper.rb +2 -0
- data/lib/generators/rolemodel/ui_components/navbar/navbar_generator.rb +1 -0
- data/lib/generators/rolemodel/webpack/README.md +2 -1
- data/lib/generators/rolemodel/webpack/templates/webpack.config.js +2 -12
- data/lib/generators/rolemodel/webpack/webpack_generator.rb +19 -11
- data/lib/rolemodel/generator_base.rb +37 -0
- data/lib/rolemodel/version.rb +1 -1
- data/lib/rolemodel-rails.rb +1 -0
- metadata +13 -12
- data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/form_error_response.rb +0 -54
- data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/no_chrome_tag.rb +0 -45
- data/lib/generators/rolemodel/semaphore/README.md +0 -15
- data/lib/generators/rolemodel/semaphore/USAGE +0 -11
- data/lib/generators/rolemodel/semaphore/semaphore_generator.rb +0 -25
- data/lib/generators/rolemodel/semaphore/templates/heroku-deployment-commands.sh +0 -3
- data/lib/generators/rolemodel/semaphore/templates/production-deploy.yml.erb +0 -17
- data/lib/generators/rolemodel/semaphore/templates/semaphore.yml.erb +0 -145
- data/lib/generators/rolemodel/semaphore/templates/staging-deploy.yml.erb +0 -17
- data/lib/generators/rolemodel/webpack/templates/app/javascript/initializers/honeybadger.js +0 -26
- /data/lib/generators/rolemodel/{simple_form → tailored_select}/templates/app/inputs/tailored_select_input.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1cf52276aac5192b4349379e6f7792232fbdabae218e3d3ac6fbde81cd1ae01
|
|
4
|
+
data.tar.gz: 3d13d291529c487fb93b8d7c7816acb05e3b686fd4129173208611c0c714558d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2fdd780f5256aac4772e65e9282569956b2b7e8a2fd663caa068d072a720a7905a721953725df5ccf07d671f600e31d7ec781831782128b63182b8cf586af61b
|
|
7
|
+
data.tar.gz: 453e93d083a80ff9ce7a2b2ea1f02079e334e2a4ae5028ee91d7b67d0c6cb7d7d8f013e9bab777a9da2f77b767f354af38688a2ac101ba8e94dd28c5979e22ee
|
data/README.md
CHANGED
|
@@ -40,7 +40,14 @@ And then execute:
|
|
|
40
40
|
|
|
41
41
|
## Usage
|
|
42
42
|
|
|
43
|
-
Run
|
|
43
|
+
Run the core generators (recommended on a new app — sets up our standard
|
|
44
|
+
baseline so the app is ready to push straight to Heroku)
|
|
45
|
+
|
|
46
|
+
```shell
|
|
47
|
+
bin/rails g rolemodel:core_setup
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or run every generator, including app-specific extras like React, SaaS/Devise, and GoodJob
|
|
44
51
|
|
|
45
52
|
```shell
|
|
46
53
|
bin/rails g rolemodel:all
|
|
@@ -66,6 +73,7 @@ bin/rails g
|
|
|
66
73
|
|
|
67
74
|
## Generators
|
|
68
75
|
|
|
76
|
+
* [Core Setup](./lib/generators/rolemodel/core_setup)
|
|
69
77
|
* [Github](./lib/generators/rolemodel/github)
|
|
70
78
|
* [Semaphore](./lib/generators/rolemodel/semaphore)
|
|
71
79
|
* [Heroku](./lib/generators/rolemodel/heroku)
|
|
@@ -215,7 +223,7 @@ DRY_RUN=true rake users:dev[_,bob@example.com]
|
|
|
215
223
|
|
|
216
224
|
## Development
|
|
217
225
|
|
|
218
|
-
Install the versions of Node and Ruby specified in `.node-version` and `.ruby-version` on your machine. https://asdf-vm.com/ is a great tool for managing language versions. Then run `
|
|
226
|
+
Install the versions of Node and Ruby specified in `.node-version` and `.ruby-version` on your machine. https://asdf-vm.com/ is a great tool for managing language versions. Then run `corepack enable` to activate the Yarn 4+ version pinned by each project's `packageManager` field.
|
|
219
227
|
|
|
220
228
|
## Adding new Generators
|
|
221
229
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Core Setup Generator
|
|
2
|
+
|
|
3
|
+
Runs the core generators every new Rails app should have. Unlike
|
|
4
|
+
`rolemodel:all`, this skips the app-specific extras (React, SaaS/Devise,
|
|
5
|
+
GoodJob, Kaminari, etc.) so you get just the standard baseline — a new Rails
|
|
6
|
+
app you can push straight to Heroku right after generation.
|
|
7
|
+
|
|
8
|
+
## Prerequisites
|
|
9
|
+
|
|
10
|
+
- A freshly generated Rails app
|
|
11
|
+
|
|
12
|
+
## What you get
|
|
13
|
+
|
|
14
|
+
- [GitHub](../github) — standard GitHub configuration
|
|
15
|
+
- [Heroku](../heroku) — standard Heroku deployment configuration
|
|
16
|
+
- [Readme](../readme) — standard project README
|
|
17
|
+
- [Webpack](../webpack) — Webpack v5 for JS and CSS
|
|
18
|
+
- [Sentry](../sentry) — error monitoring for Ruby and JavaScript
|
|
19
|
+
- [Slim](../slim) — Slim templates
|
|
20
|
+
- [Optics](../optics) — Optics design system
|
|
21
|
+
- [Testing](../testing) — RSpec, FactoryBot, parallel_tests, TestProf
|
|
22
|
+
(pass `--js-runner` to include jasmine-playwright-runner)
|
|
23
|
+
- [SimpleForm](../simple_form) — SimpleForm with our configuration
|
|
24
|
+
- [Linters](../linters) — Rubocop and ESLint
|
|
25
|
+
- [UI Components](../ui_components) — flash, the modal pattern, & Turbo 8 support
|
|
26
|
+
- [Editors](../editors) — EditorConfig and recommended VSCode extensions
|
|
27
|
+
- [Lograge](../lograge) — condensed request logging
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Runs the core generators every new Rails app should have
|
|
3
|
+
|
|
4
|
+
Sets up GitHub config, Heroku deployment, README, Webpack, Sentry, Slim,
|
|
5
|
+
Optics, testing (RSpec & friends), SimpleForm, linters, Turbo 8+ support,
|
|
6
|
+
and Lograge. The result is an app that is ready to push directly to Heroku.
|
|
7
|
+
|
|
8
|
+
Pass --js-runner to also include jasmine-playwright-runner for browser
|
|
9
|
+
JS testing.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
rails generate rolemodel:core_setup
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Rolemodel
|
|
2
|
+
class CoreSetupGenerator < ::Rolemodel::GeneratorBase
|
|
3
|
+
def run_the_core_generators
|
|
4
|
+
generate 'rolemodel:github'
|
|
5
|
+
generate 'rolemodel:heroku'
|
|
6
|
+
generate 'rolemodel:readme'
|
|
7
|
+
generate 'rolemodel:webpack'
|
|
8
|
+
generate 'rolemodel:sentry'
|
|
9
|
+
generate 'rolemodel:slim'
|
|
10
|
+
generate 'rolemodel:optics:all'
|
|
11
|
+
generate 'rolemodel:testing:all'
|
|
12
|
+
generate 'rolemodel:simple_form'
|
|
13
|
+
generate 'rolemodel:linters:all'
|
|
14
|
+
generate 'rolemodel:ui_components:flash'
|
|
15
|
+
generate 'rolemodel:ui_components:modals'
|
|
16
|
+
generate 'rolemodel:lograge'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -9,6 +9,10 @@ It doesn't need to be run first, but the parallel_tests generator must be run in
|
|
|
9
9
|
- CI workflow
|
|
10
10
|
- A sensible default `ci.yml` to get you started with Github Actions. This will run linters, model tests, and system tests.
|
|
11
11
|
- Along with the `ci.yml`, your `database.yml` will be modified to be able to be run in GHA.
|
|
12
|
+
- Deploy workflows
|
|
13
|
+
- `deploy-staging.yml` deploys to Heroku on every push to `main` (or manually); `deploy-production.yml` deploys manually via `workflow_dispatch`.
|
|
14
|
+
- Both target a GitHub deployment environment (`Staging`/`Production`) that provides `HEROKU_APP_NAME` and `HEROKU_APP_URL` variables, and authenticate with the org-level `HEROKU_IT_SUPPORT_API_KEY` secret and `HEROKU_IT_SUPPORT_EMAIL` variable.
|
|
15
|
+
- Note: the staging workflow will fail on pushes to `main` until the environment exists — run the `deploy-app` agent skill (installed by the heroku generator) to create the Heroku app and the GitHub environment.
|
|
12
16
|
- Pull Request Template
|
|
13
17
|
- When you open a Pull Request in Github it will use the Markdown file as a [template](./templates/pull_request_template.md) for the content of the PR.
|
|
14
18
|
- Helpful for reminding collaborators to add specific details to the PR.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Deploy to Heroku Production
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
sha:
|
|
7
|
+
description: 'Specific SHA or Branch name (optional)'
|
|
8
|
+
required: false
|
|
9
|
+
type: string
|
|
10
|
+
|
|
11
|
+
concurrency: production-deployment
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
deploy:
|
|
15
|
+
name: Deploy
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
timeout-minutes: 20
|
|
18
|
+
environment:
|
|
19
|
+
name: Production
|
|
20
|
+
url: ${{ vars.HEROKU_APP_URL }}
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
|
|
24
|
+
- name: Install Heroku CLI
|
|
25
|
+
run: |
|
|
26
|
+
curl https://cli-assets.heroku.com/install.sh | sh
|
|
27
|
+
|
|
28
|
+
- uses: akhileshns/heroku-deploy@v3.15.15
|
|
29
|
+
with:
|
|
30
|
+
heroku_api_key: ${{ secrets.HEROKU_IT_SUPPORT_API_KEY }}
|
|
31
|
+
heroku_app_name: ${{ vars.HEROKU_APP_NAME }}
|
|
32
|
+
heroku_email: ${{ vars.HEROKU_IT_SUPPORT_EMAIL }}
|
|
33
|
+
branch: ${{ inputs.sha || 'HEAD' }}
|
|
34
|
+
healthcheck: '${{ vars.HEROKU_APP_URL }}/up'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Deploy to Heroku Staging
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
sha:
|
|
7
|
+
description: 'Specific SHA or Branch name (optional)'
|
|
8
|
+
required: false
|
|
9
|
+
type: string
|
|
10
|
+
push: { branches: [ staging ] }
|
|
11
|
+
|
|
12
|
+
concurrency: staging-deployment
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
deploy:
|
|
16
|
+
name: Deploy
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
timeout-minutes: 20
|
|
19
|
+
environment:
|
|
20
|
+
name: Staging
|
|
21
|
+
url: ${{ vars.HEROKU_APP_URL }}
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
|
+
|
|
25
|
+
- name: Install Heroku CLI
|
|
26
|
+
run: |
|
|
27
|
+
curl https://cli-assets.heroku.com/install.sh | sh
|
|
28
|
+
|
|
29
|
+
- uses: akhileshns/heroku-deploy@v3.15.15
|
|
30
|
+
with:
|
|
31
|
+
heroku_api_key: ${{ secrets.HEROKU_IT_SUPPORT_API_KEY }}
|
|
32
|
+
heroku_app_name: ${{ vars.HEROKU_APP_NAME }}
|
|
33
|
+
heroku_email: ${{ vars.HEROKU_IT_SUPPORT_EMAIL }}
|
|
34
|
+
branch: ${{ inputs.sha || 'HEAD' }}
|
|
35
|
+
healthcheck: "${{ vars.HEROKU_APP_URL }}/up"
|
|
@@ -64,8 +64,6 @@ module Rolemodel
|
|
|
64
64
|
|
|
65
65
|
def finishing_notes
|
|
66
66
|
say <<~NOTES
|
|
67
|
-
*** Reminder to update Honeybadger gem to version 5.7.0 or later to get correct GoodJob error notifications in Honeybadger
|
|
68
|
-
|
|
69
67
|
*** Reminder to also update your job classes to include appropriate concurrency controls (enqueue_limit/perform_limit with keys)
|
|
70
68
|
NOTES
|
|
71
69
|
end
|
|
@@ -4,5 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
* Procfile configured for a server process and a release command to run migrations
|
|
6
6
|
* Basic app.json preconfigured with a script to initialize the database and common environment variables, addons, and buildpacks
|
|
7
|
-
|
|
8
7
|
This is the basic config needed to deploy to Heroku.
|
|
8
|
+
|
|
9
|
+
## Deploying the app
|
|
10
|
+
|
|
11
|
+
Deployment setup itself is handled by the `deploy-app` agent skill, which ships inside the
|
|
12
|
+
`rolemodel-rails` gem rather than being copied into your repo — it's one-time setup, so nothing
|
|
13
|
+
skill-related is committed to the app. When the generator finishes, it prints the path to the
|
|
14
|
+
skill's `SKILL.md`; point any coding agent at that file to deploy the app. You can also locate
|
|
15
|
+
it yourself:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
$(bundle show rolemodel-rails)/lib/generators/rolemodel/heroku/templates/deploy-app/SKILL.md
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The skill cleans up the generated Gemfile (merges duplicate groups, removes comments,
|
|
22
|
+
alphabetizes), verifies the test suite and RuboCop pass, creates the Sentry project and wires
|
|
23
|
+
up the DSN, creates and deploys the Heroku staging app (buildpacks, dynos, Postgres,
|
|
24
|
+
Papertrail), and creates the GitHub `Staging` environment with the
|
|
25
|
+
`HEROKU_APP_NAME`/`HEROKU_APP_URL` variables the deploy workflow consumes. The skill is
|
|
26
|
+
LLM-agnostic (Agent Skills format). Requires the Heroku CLI, the GitHub CLI, and the Sentry
|
|
27
|
+
MCP server.
|
|
@@ -15,6 +15,33 @@ module Rolemodel
|
|
|
15
15
|
template 'Procfile'
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def pin_ruby_version_for_buildpack
|
|
19
|
+
say 'Pin the Ruby version in the Gemfile so the Heroku buildpack respects it.', :green
|
|
20
|
+
|
|
21
|
+
# A bare .ruby-version file is not enough: without a `ruby` directive the version
|
|
22
|
+
# never lands in Gemfile.lock, so the Heroku Ruby buildpack falls back to its own
|
|
23
|
+
# default and can install an incompatible Ruby. Tie the Gemfile to .ruby-version.
|
|
24
|
+
gemfile = File.join(destination_root, 'Gemfile')
|
|
25
|
+
return if File.exist?(gemfile) && File.read(gemfile).match?(/^\s*ruby\s/)
|
|
26
|
+
|
|
27
|
+
inject_into_file 'Gemfile', "\nruby file: '.ruby-version'\n", after: /^source .*$/
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def use_database_url_in_production
|
|
31
|
+
say 'Point the production database at DATABASE_URL for Heroku.', :green
|
|
32
|
+
|
|
33
|
+
# Rails' generated production block hardcodes database/username/<APP>_DATABASE_PASSWORD,
|
|
34
|
+
# none of which exist on Heroku, where the Postgres add-on provides a full DATABASE_URL.
|
|
35
|
+
# Replace the whole block with a url-based config.
|
|
36
|
+
gsub_file 'config/database.yml',
|
|
37
|
+
/^production:\n(?:[ \t]+.*\n?)+/,
|
|
38
|
+
<<~YAML
|
|
39
|
+
production:
|
|
40
|
+
<<: *default
|
|
41
|
+
url: <%= ENV["DATABASE_URL"] %>
|
|
42
|
+
YAML
|
|
43
|
+
end
|
|
44
|
+
|
|
18
45
|
def force_ssl
|
|
19
46
|
say 'Require SSL for production environment.', :green
|
|
20
47
|
|
|
@@ -48,5 +75,13 @@ module Rolemodel
|
|
|
48
75
|
end
|
|
49
76
|
RAKE
|
|
50
77
|
end
|
|
78
|
+
|
|
79
|
+
def show_deploy_app_skill_path
|
|
80
|
+
# The deploy-app skill is one-time deployment setup, so it ships inside the
|
|
81
|
+
# rolemodel-rails gem instead of being copied into the app. Point the user
|
|
82
|
+
# at it so they can hand it to a coding agent when they're ready to deploy.
|
|
83
|
+
say "\nWhen you're ready to deploy, point your coding agent at the deploy-app skill:", :green
|
|
84
|
+
say File.expand_path('templates/deploy-app/SKILL.md', __dir__), :yellow
|
|
85
|
+
end
|
|
51
86
|
end
|
|
52
87
|
end
|
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
"postdeploy": "bin/rails db:seed"
|
|
5
5
|
},
|
|
6
6
|
"env": {
|
|
7
|
-
"
|
|
7
|
+
"SENTRY_DSN": {
|
|
8
8
|
"required": true
|
|
9
9
|
},
|
|
10
|
-
"
|
|
10
|
+
"SENTRY_ENVIRONMENT": {
|
|
11
11
|
"required": true,
|
|
12
12
|
"value": "review-app"
|
|
13
|
+
},
|
|
14
|
+
"SENTRY_AUTH_TOKEN": {
|
|
15
|
+
"required": false
|
|
13
16
|
}
|
|
14
17
|
},
|
|
15
18
|
"addons": [
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deploy-app
|
|
3
|
+
description: >
|
|
4
|
+
Set up deployment for a RoleModel Rails app after running the rolemodel_rails
|
|
5
|
+
core_setup generator. Cleans up the generated Gemfile, verifies RuboCop, the test
|
|
6
|
+
suite, and a local production smoke test pass, creates the Sentry project and wires
|
|
7
|
+
up the DSN, creates and deploys the Heroku app (buildpacks, dynos, Postgres,
|
|
8
|
+
Papertrail), and creates the GitHub deployment environment + deploy workflow. Use
|
|
9
|
+
when the user says "deploy app",
|
|
10
|
+
"set up staging", "set up heroku", "set up sentry for deploy", or "set up production
|
|
11
|
+
deploy". Defaults to staging; pass "production" for the production flow.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Deploy App
|
|
15
|
+
|
|
16
|
+
Completes deployment setup for a RoleModel Rails app in five phases: Gemfile cleanup,
|
|
17
|
+
green build (RuboCop + tests + production smoke test), Sentry, Heroku, GitHub. Default
|
|
18
|
+
mode is **staging**. If invoked with `production`, follow the
|
|
19
|
+
[Production mode](#production-mode) differences.
|
|
20
|
+
|
|
21
|
+
Every step must be **idempotent**: check whether the resource already exists before
|
|
22
|
+
creating it, and skip or repair rather than failing. Report each phase's outcome as you
|
|
23
|
+
go. Ask the user questions **one at a time**.
|
|
24
|
+
|
|
25
|
+
## Phase 0: Preflight
|
|
26
|
+
|
|
27
|
+
Run these checks before touching anything. Stop and tell the user how to fix any that
|
|
28
|
+
fail:
|
|
29
|
+
|
|
30
|
+
1. `git remote get-url origin` — must be a GitHub repo. Derive `REPO_NAME` from
|
|
31
|
+
`gh repo view --json name -q .name` (fallback: basename of the origin URL).
|
|
32
|
+
2. `gh auth status` — GitHub CLI authenticated.
|
|
33
|
+
3. `heroku auth:whoami` — Heroku CLI installed and logged in.
|
|
34
|
+
4. Sentry MCP tools available (try listing organizations). If no Sentry MCP server is
|
|
35
|
+
connected, ask the user to add/authorize the Sentry MCP server
|
|
36
|
+
(https://mcp.sentry.dev) in their coding agent's MCP configuration and stop — do not
|
|
37
|
+
fall back to another mechanism.
|
|
38
|
+
5. Read `Procfile` — note whether a `worker` process exists.
|
|
39
|
+
6. Read `config/initializers/sentry.rb` — determine how the DSN is consumed:
|
|
40
|
+
- reads `ENV['SENTRY_DSN']` → **env-var mode** (RoleModel standard)
|
|
41
|
+
- reads `Rails.application.credentials...` → **credentials mode**
|
|
42
|
+
7. Deploy-readiness (recent `rolemodel-rails` bakes these in; older apps need the manual
|
|
43
|
+
fixes noted in each phase). Confirm the generated app already has:
|
|
44
|
+
- `terser-webpack-plugin` in `package.json` (webpack config imports it)
|
|
45
|
+
- custom cops under `.rubocop/cops/`, not `lib/cops/` (the latter crashes prod boot)
|
|
46
|
+
- `config/initializers/lograge.rb` uses `controller.try(:current_user)`
|
|
47
|
+
- `config/database.yml` `production:` block uses `url: <%= ENV["DATABASE_URL"] %>`
|
|
48
|
+
- a `ruby` directive in the `Gemfile` (so the version reaches `Gemfile.lock`)
|
|
49
|
+
- `stackprof` in the `Gemfile` (Sentry profiling)
|
|
50
|
+
If any are missing, apply the fix inline and note the app predates the generator update.
|
|
51
|
+
|
|
52
|
+
Set `APP_NAME` = `<REPO_NAME>-staging` (staging) or `<REPO_NAME>` (production), but
|
|
53
|
+
confirm it with the user before creating anything on Heroku.
|
|
54
|
+
|
|
55
|
+
## Phase 1: Gemfile cleanup
|
|
56
|
+
|
|
57
|
+
The rolemodel_rails generators append gems as they run, leaving multiple blocks for the
|
|
58
|
+
same group and top-level gems scattered between them. Normalize the Gemfile first (skip
|
|
59
|
+
this phase if it's already clean):
|
|
60
|
+
|
|
61
|
+
1. Merge duplicate `group` blocks so each unique group combination
|
|
62
|
+
(e.g. `:development, :test`, `:development`, `:test`) appears exactly once.
|
|
63
|
+
2. Remove all comments, including commented-out gems (e.g. `# gem "redis" ...`).
|
|
64
|
+
3. Alphabetize the gems — the top-level list and the list within each group.
|
|
65
|
+
4. Preserve every gem's version constraint and options (`require:`, `platforms:`,
|
|
66
|
+
`path:`, etc.) exactly as written. File order: `source`, then `ruby` (if present),
|
|
67
|
+
then top-level gems, then the group blocks.
|
|
68
|
+
5. Run `bundle install` and confirm it succeeds. `git diff Gemfile.lock` must show no
|
|
69
|
+
changes — this is an ordering-only cleanup; if the lockfile changed, you altered a
|
|
70
|
+
dependency and must fix it.
|
|
71
|
+
|
|
72
|
+
## Phase 2: Green build + production smoke test
|
|
73
|
+
|
|
74
|
+
Do not deploy a broken app. This is a **verification gate**: on a current generated app
|
|
75
|
+
these should pass with no changes. A failure here usually means a generator regression —
|
|
76
|
+
fix the root cause (and flag it for the generator), never paper over it.
|
|
77
|
+
|
|
78
|
+
1. RuboCop: `bin/rubocop` (fallback: `bundle exec rubocop`). If there are offenses,
|
|
79
|
+
apply safe autocorrections (`rubocop -a`), then fix the remainder by hand.
|
|
80
|
+
2. Test suite: `bundle exec rspec` (fallback: `bin/rspec`). Fix any failures at the
|
|
81
|
+
root cause — never skip, pend, or delete tests to get to green.
|
|
82
|
+
3. **Local production smoke test** — this is what catches the boot/asset/DB failures that
|
|
83
|
+
only surface under `RAILS_ENV=production` (eager loading, `force_ssl`, DATABASE_URL).
|
|
84
|
+
Run against a throwaway local Postgres DB (do not touch development/test data):
|
|
85
|
+
```
|
|
86
|
+
export PROD="RAILS_ENV=production SECRET_KEY_BASE=smoketest \
|
|
87
|
+
DATABASE_URL=postgres://$(whoami)@localhost/<repo>_prodsmoke"
|
|
88
|
+
env $PROD bundle exec rails db:create
|
|
89
|
+
env $PROD bundle exec rails assets:precompile # webpack + asset pipeline
|
|
90
|
+
env $PROD RAILS_SERVE_STATIC_FILES=true PORT=3999 bundle exec puma -C config/puma.rb &
|
|
91
|
+
sleep 6
|
|
92
|
+
curl -s -o /dev/null -w '%{http_code}\n' -H 'X-Forwarded-Proto: https' \
|
|
93
|
+
http://localhost:3999/up # expect 200 (plain http returns 301 due to force_ssl)
|
|
94
|
+
kill %1; env $PROD bundle exec rails db:drop
|
|
95
|
+
```
|
|
96
|
+
`assets:precompile` succeeding and `/up` → 200 is the gate. If `/up` 500s, read the
|
|
97
|
+
server log for the root cause before proceeding.
|
|
98
|
+
4. Re-run until clean, then commit the Gemfile cleanup and any fixes (the deploy later
|
|
99
|
+
pushes this branch, so everything must be committed).
|
|
100
|
+
|
|
101
|
+
## Phase 3: Sentry project + DSN
|
|
102
|
+
|
|
103
|
+
1. List the Sentry organizations/teams via the Sentry MCP. Ask the user which team the
|
|
104
|
+
project belongs under (skip the question if there is only one option).
|
|
105
|
+
2. Check whether a project named `REPO_NAME` already exists in that org. If it does,
|
|
106
|
+
reuse it and fetch its DSN instead of creating a duplicate.
|
|
107
|
+
3. Otherwise create the project: slug/name = `REPO_NAME`, platform `ruby-rails`,
|
|
108
|
+
assigned to the confirmed team.
|
|
109
|
+
4. Fetch the project's client key (DSN).
|
|
110
|
+
5. Deliver the DSN according to the mode detected in preflight:
|
|
111
|
+
- **env-var mode**: no code change needed. The DSN is set as a Heroku config var in
|
|
112
|
+
Phase 4 (`SENTRY_DSN`, plus `SENTRY_ENVIRONMENT=staging`). Mention that local
|
|
113
|
+
error reporting (if ever wanted) uses the same `SENTRY_DSN` env var.
|
|
114
|
+
- **credentials mode**: do NOT edit credentials yourself. Print the DSN and exact
|
|
115
|
+
instructions — e.g. `bin/rails credentials:edit --environment production`, add
|
|
116
|
+
`sentry_dsn: <DSN>` — then wait for the user to confirm they've saved it. Verify
|
|
117
|
+
afterwards with
|
|
118
|
+
`bin/rails runner "abort 'missing' unless Rails.application.credentials.sentry_dsn"`
|
|
119
|
+
(adjust env/key path to match the initializer) before moving on.
|
|
120
|
+
|
|
121
|
+
## Phase 4: Heroku app
|
|
122
|
+
|
|
123
|
+
1. `heroku teams` — ask the user which team to create the app in. **Do not create the
|
|
124
|
+
app until they confirm the team and the app name** (default `<REPO_NAME>-staging`).
|
|
125
|
+
2. Ensure the current branch is pushed: check `git status` and
|
|
126
|
+
`git rev-parse @ @{u}`. If there's no upstream or local is ahead, ask the user to
|
|
127
|
+
push (or push for them if they say so) before continuing.
|
|
128
|
+
3. Create the app if it doesn't exist (`heroku apps:info -a $APP_NAME` to check):
|
|
129
|
+
`heroku apps:create $APP_NAME --team <team>`
|
|
130
|
+
4. Buildpacks, in this exact order (check `heroku buildpacks -a $APP_NAME` first):
|
|
131
|
+
1. `heroku buildpacks:add heroku/nodejs -a $APP_NAME`
|
|
132
|
+
2. `heroku buildpacks:add heroku/ruby -a $APP_NAME`
|
|
133
|
+
5. Add-ons (skip any that already exist per `heroku addons -a $APP_NAME`):
|
|
134
|
+
- `heroku addons:create heroku-postgresql:essential-0 -a $APP_NAME`
|
|
135
|
+
- Papertrail: run `heroku addons:plans papertrail` and pick the plan whose
|
|
136
|
+
name/description matches "Development" (case-insensitive); if no plan matches,
|
|
137
|
+
show the plan list and ask the user which to use. Then
|
|
138
|
+
`heroku addons:create papertrail:<plan> -a $APP_NAME`.
|
|
139
|
+
6. Config vars:
|
|
140
|
+
- `RAILS_MASTER_KEY`: **never read `config/master.key` (or
|
|
141
|
+
`config/credentials/production.key`) — the key must not enter the model's context.**
|
|
142
|
+
Pause and tell the user to run this in their own terminal:
|
|
143
|
+
`heroku config:set RAILS_MASTER_KEY=$(cat config/master.key) -a $APP_NAME`
|
|
144
|
+
(substitute `config/credentials/production.key` if per-environment credentials are
|
|
145
|
+
in use). Once they confirm, verify presence without exposing the value:
|
|
146
|
+
`heroku config --json -a $APP_NAME | jq 'has("RAILS_MASTER_KEY")'` — must be `true`.
|
|
147
|
+
- env-var mode only, set these yourself:
|
|
148
|
+
`heroku config:set SENTRY_DSN=<dsn> SENTRY_ENVIRONMENT=staging -a $APP_NAME`
|
|
149
|
+
7. Enable runtime dyno metadata (idempotent) so Sentry can detect releases:
|
|
150
|
+
`heroku labs:enable runtime-dyno-metadata -a $APP_NAME`. This adds `HEROKU_*`
|
|
151
|
+
env vars (e.g. `HEROKU_SLUG_COMMIT`) on the next release; without it the release
|
|
152
|
+
command logs a warning about dyno metadata.
|
|
153
|
+
8. Initial deploy from the local machine:
|
|
154
|
+
- `heroku git:remote -a $APP_NAME -r heroku-staging`
|
|
155
|
+
- `git push heroku-staging <current-branch>:main`
|
|
156
|
+
- If the build or release phase fails, read the build output / `heroku logs` and fix
|
|
157
|
+
the root cause before proceeding — do not create the GitHub environment until the
|
|
158
|
+
app deploys and boots.
|
|
159
|
+
9. Dyno formation (after the first successful deploy):
|
|
160
|
+
- `heroku ps:type web=basic -a $APP_NAME`
|
|
161
|
+
- If the Procfile has a `worker` process: `heroku ps:scale worker=1:basic -a $APP_NAME`
|
|
162
|
+
10. Verify: get the app URL from `heroku apps:info -a $APP_NAME --json` (`web_url`), then
|
|
163
|
+
curl `<web_url>/up` and confirm a 200. Save the URL as `APP_URL` (no trailing slash).
|
|
164
|
+
|
|
165
|
+
## Phase 5: GitHub environment + deploy workflow
|
|
166
|
+
|
|
167
|
+
1. Create the environment (idempotent PUT):
|
|
168
|
+
`gh api -X PUT repos/{owner}/{repo}/environments/Staging`
|
|
169
|
+
2. Set the environment variables:
|
|
170
|
+
- `gh variable set HEROKU_APP_NAME --env Staging --body "$APP_NAME"`
|
|
171
|
+
- `gh variable set HEROKU_APP_URL --env Staging --body "$APP_URL"`
|
|
172
|
+
3. Confirm `.github/workflows/deploy-staging.yml` exists (the rolemodel-rails github
|
|
173
|
+
generator installs it). If it's missing, the app skipped the github generator — tell
|
|
174
|
+
the user to run it (`rails generate rolemodel:github`) rather than hand-writing the
|
|
175
|
+
workflow. The workflow relies on the RoleModel **org-level**
|
|
176
|
+
`HEROKU_IT_SUPPORT_API_KEY` secret and `HEROKU_IT_SUPPORT_EMAIL` variable — do not
|
|
177
|
+
create per-repo copies.
|
|
178
|
+
4. Verify end-to-end: `gh workflow run deploy-staging.yml` then `gh run watch` the run.
|
|
179
|
+
A green run (including its `/up` healthcheck) is the definition of done.
|
|
180
|
+
|
|
181
|
+
## Production mode
|
|
182
|
+
|
|
183
|
+
Same phases with these differences — ask, don't assume, on every sizing choice:
|
|
184
|
+
|
|
185
|
+
- App name defaults to `<REPO_NAME>` (confirm with the user).
|
|
186
|
+
- Sentry: reuse the existing project; set `SENTRY_ENVIRONMENT=production`.
|
|
187
|
+
- Heroku tiers: ask the user for dyno type (basic/standard-1x/standard-2x/performance),
|
|
188
|
+
Postgres plan, and Papertrail plan instead of assuming the staging defaults.
|
|
189
|
+
- GitHub environment is `Production`; the workflow is
|
|
190
|
+
`.github/workflows/deploy-production.yml` (also installed by the github generator; manual
|
|
191
|
+
`workflow_dispatch` only — production never auto-deploys on push).
|
|
192
|
+
|
|
193
|
+
## Notes
|
|
194
|
+
|
|
195
|
+
- Never run destructive Heroku commands (`apps:destroy`, `addons:destroy`,
|
|
196
|
+
`pg:reset`) as part of this skill.
|
|
197
|
+
- Never read secret material into the model's context: `config/master.key`,
|
|
198
|
+
`config/credentials/*.key`, or the output of `heroku config` without `--json | jq`
|
|
199
|
+
filtering. When a secret must be set, have the user run the command themselves and
|
|
200
|
+
verify only the key's presence afterwards.
|
|
201
|
+
- If any phase was already completed on a previous run, say so and continue with the
|
|
202
|
+
next phase rather than starting over.
|
|
@@ -16,7 +16,11 @@ module Rolemodel
|
|
|
16
16
|
|
|
17
17
|
def add_config
|
|
18
18
|
copy_file '.rubocop.yml', force: true
|
|
19
|
-
|
|
19
|
+
# Custom cops live in .rubocop/cops (loaded via .rubocop.yml's require:),
|
|
20
|
+
# not lib/cops — keeping them out of Rails' autoload/eager-load paths so
|
|
21
|
+
# they don't crash production boot referencing the dev/test-only RuboCop
|
|
22
|
+
# constant.
|
|
23
|
+
directory '.rubocop/cops'
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
26
|
end
|
|
@@ -7,4 +7,4 @@
|
|
|
7
7
|
Installs [Lograge](https://github.com/roidrage/lograge).
|
|
8
8
|
|
|
9
9
|
Lograge is an opinionated gem that slims down the amount of logs that Rails generates, with the goal of reducing
|
|
10
|
-
noise that's handled by other services.
|
|
10
|
+
noise that's handled by other services.
|
|
@@ -4,7 +4,7 @@ Rails.application.configure do
|
|
|
4
4
|
config.lograge.enabled = true
|
|
5
5
|
config.lograge.custom_payload do |controller|
|
|
6
6
|
{
|
|
7
|
-
user_id: controller.current_user.try(:id)
|
|
7
|
+
user_id: controller.try(:current_user).try(:id)
|
|
8
8
|
}
|
|
9
9
|
end
|
|
10
10
|
config.lograge.custom_options = lambda do |event|
|
|
@@ -81,12 +81,10 @@ When finished with the feature and the code has been reviewed, the commits shoul
|
|
|
81
81
|
## [Staging](http://staging.<applicationname>.com)
|
|
82
82
|
## [Production](http://app.<applicationname>.com)
|
|
83
83
|
## External services
|
|
84
|
-
* [
|
|
85
|
-
* [Skylight](http://skylight.io)
|
|
84
|
+
* [Sentry](https://sentry.io)
|
|
86
85
|
* [SendGrid](http://sendgrid.com/RoleModel)
|
|
87
86
|
* [Heroku](http://herokuapp.com)
|
|
88
87
|
|
|
89
|
-
## [CI](http://semaphoreci.com/RoleModel)
|
|
90
88
|
## [Core project presentation](http://docs.google.com)
|
|
91
89
|
## [List of contributors](http://github.com/RoleModel)
|
|
92
90
|
## [Change log](file://./docs/change_log.md)
|
|
@@ -113,4 +111,4 @@ The application is deployed to Heroku. They are also hosting the DNS. We certifi
|
|
|
113
111
|
* Larry Anderson - 919-555-1213
|
|
114
112
|
|
|
115
113
|
# Copyright & licensing
|
|
116
|
-
Copyright (c)
|
|
114
|
+
Copyright (c) 2026 Closed Source @CompanyName
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Sentry Generator
|
|
2
|
+
|
|
3
|
+
## What you get
|
|
4
|
+
|
|
5
|
+
Error monitoring and performance tracing via [Sentry](https://sentry.io) for both the Ruby and JavaScript sides of the app.
|
|
6
|
+
|
|
7
|
+
### Ruby
|
|
8
|
+
|
|
9
|
+
* The `sentry-rails` gem
|
|
10
|
+
* `config/initializers/sentry.rb` with sensible defaults: traces sampling, profiling, PII filtering via Rails' parameter filter, noisy-exception exclusion, and health-check transaction filtering
|
|
11
|
+
* Sentry user context wired into `app/controllers/application_controller.rb` via a `set_sentry_user` before_action (Devise-friendly, gated on `user_signed_in?`)
|
|
12
|
+
|
|
13
|
+
### JavaScript
|
|
14
|
+
|
|
15
|
+
* `@sentry/browser` and `@sentry/webpack-plugin` dependencies
|
|
16
|
+
* `app/javascript/initializers/sentry.js`, which initializes Sentry in production and staging only (avoids ad-blocker noise in development) and attaches the current user from a `current-user-id` meta tag
|
|
17
|
+
* The `sentryWebpackPlugin` wired into `webpack.config.js` to upload source maps in production
|
|
18
|
+
|
|
19
|
+
Depends on the `rolemodel:webpack` generator having already created `webpack.config.js` and `app/javascript/application.js`.
|
|
20
|
+
|
|
21
|
+
## After running
|
|
22
|
+
|
|
23
|
+
* Update the `project` and `applicationKey` in `webpack.config.js`, and the matching `filterKeys` in `app/javascript/initializers/sentry.js`, to match your Sentry project.
|
|
24
|
+
* Set the `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, and `SENTRY_AUTH_TOKEN` environment variables.
|
|
25
|
+
* Render a `current-user-id` meta tag in your layout so the browser SDK can attach user context.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Sets up Sentry error monitoring for both Ruby and JavaScript
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
rails generate rolemodel:sentry
|
|
6
|
+
|
|
7
|
+
This will:
|
|
8
|
+
Add the sentry-rails gem
|
|
9
|
+
Create config/initializers/sentry.rb
|
|
10
|
+
Add Sentry user context to app/controllers/application_controller.rb
|
|
11
|
+
Add @sentry/browser and @sentry/webpack-plugin JS dependencies
|
|
12
|
+
Create app/javascript/initializers/sentry.js
|
|
13
|
+
Wire the Sentry webpack plugin into webpack.config.js
|