brut 0.0.27 → 0.0.29
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/.gitignore +6 -0
- data/.projections.json +10 -0
- data/.rspec +3 -0
- data/Dockerfile.dx +32 -14
- data/Gemfile.lock +1 -1
- data/assets/Logo-Square.pxd +0 -0
- data/assets/LogoPylon.pxd +0 -0
- data/assets/LogoStop.pxd +0 -0
- data/assets/LogoTall.pxd +0 -0
- data/bin/docs +24 -2
- data/bin/rspec +27 -0
- data/bin/setup +3 -3
- data/brutrb.com/.vitepress/config.mjs +1 -0
- data/brutrb.com/.vitepress/theme/custom.css +7 -0
- data/brutrb.com/.vitepress/theme/style.css +26 -15
- data/brutrb.com/deployment.md +123 -45
- data/brutrb.com/dev-environment.md +6 -5
- data/brutrb.com/doc-conventions.md +1 -1
- data/brutrb.com/getting-started.md +64 -28
- data/brutrb.com/images/LogoPylon.png +0 -0
- data/brutrb.com/images/LogoSquare.png +0 -0
- data/brutrb.com/images/LogoStop.png +0 -0
- data/brutrb.com/images/LogoTall.png +0 -0
- data/brutrb.com/images/OverviewMetro.graffle +0 -0
- data/brutrb.com/images/OverviewMetro.png +0 -0
- data/brutrb.com/index.md +4 -3
- data/brutrb.com/instrumentation.md +12 -0
- data/brutrb.com/layouts.md +130 -0
- data/brutrb.com/overview.md +6 -6
- data/docker-compose.dx.yml +5 -2
- data/docs/404.html +3 -3
- data/docs/ai.html +6 -6
- data/docs/api/Brut/BackEnd/SeedData.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq.html +1 -1
- data/docs/api/Brut/BackEnd/Validators/FormValidator.html +1 -1
- data/docs/api/Brut/BackEnd/Validators.html +1 -1
- data/docs/api/Brut/BackEnd.html +1 -1
- data/docs/api/Brut/CLI/App.html +38 -13
- data/docs/api/Brut/CLI/AppRunner.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Create.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Drop.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Migrate.html +9 -3
- data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +11 -11
- data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Seed.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Status.html +12 -12
- data/docs/api/Brut/CLI/Apps/DB.html +1 -1
- data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +270 -0
- data/docs/api/Brut/CLI/Apps/DeployBase.html +257 -0
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +585 -0
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +196 -0
- data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/Audit.html +12 -10
- data/docs/api/Brut/CLI/Apps/Test/E2e.html +8 -8
- data/docs/api/Brut/CLI/Apps/Test/JS.html +9 -9
- data/docs/api/Brut/CLI/Apps/Test/Run.html +18 -18
- data/docs/api/Brut/CLI/Apps/Test.html +1 -1
- data/docs/api/Brut/CLI/Apps.html +2 -2
- data/docs/api/Brut/CLI/Command.html +113 -28
- data/docs/api/Brut/CLI/Error.html +1 -1
- data/docs/api/Brut/CLI/ExecutionResults/Result.html +1 -1
- data/docs/api/Brut/CLI/ExecutionResults.html +1 -1
- data/docs/api/Brut/CLI/Executor.html +169 -38
- data/docs/api/Brut/CLI/InvalidOption.html +1 -1
- data/docs/api/Brut/CLI/Options.html +68 -19
- data/docs/api/Brut/CLI/Output.html +1 -1
- data/docs/api/Brut/CLI/SystemExecError.html +1 -1
- data/docs/api/Brut/CLI.html +1 -1
- data/docs/api/Brut/FactoryBot.html +1 -1
- data/docs/api/Brut/Framework/App.html +1 -1
- data/docs/api/Brut/Framework/Config.html +1 -1
- data/docs/api/Brut/Framework/Container.html +110 -29
- data/docs/api/Brut/Framework/Error.html +1 -1
- data/docs/api/Brut/Framework/Errors/AbstractMethod.html +89 -1
- data/docs/api/Brut/Framework/Errors/Bug.html +1 -1
- data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +1 -1
- data/docs/api/Brut/Framework/Errors/MissingParameter.html +1 -1
- data/docs/api/Brut/Framework/Errors/NoClassForPath.html +1 -1
- data/docs/api/Brut/Framework/Errors/NotFound.html +1 -1
- data/docs/api/Brut/Framework/Errors/NotImplemented.html +1 -1
- data/docs/api/Brut/Framework/Errors.html +31 -8
- data/docs/api/Brut/Framework/FussyTypeEnforcement.html +1 -1
- data/docs/api/Brut/Framework/MCP.html +1 -1
- data/docs/api/Brut/Framework/ProjectEnvironment.html +1 -1
- data/docs/api/Brut/Framework.html +1 -1
- data/docs/api/Brut/FrontEnd/AssetPathResolver.html +1 -1
- data/docs/api/Brut/FrontEnd/Component/Helpers.html +36 -26
- data/docs/api/Brut/FrontEnd/Component.html +7 -7
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +37 -29
- data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Input.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +20 -117
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +25 -23
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +73 -380
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +22 -138
- data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/TimeTag.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Traceparent.html +1 -1
- data/docs/api/Brut/FrontEnd/Components.html +23 -2
- data/docs/api/Brut/FrontEnd/Download.html +1 -1
- data/docs/api/Brut/FrontEnd/Flash.html +1 -1
- data/docs/api/Brut/FrontEnd/Form.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +24 -68
- data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +201 -0
- data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +535 -0
- data/docs/api/Brut/FrontEnd/Forms/Input.html +983 -35
- data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +4 -4
- data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +29 -19
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +9 -3
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +9 -3
- data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +72 -22
- data/docs/api/Brut/FrontEnd/Forms.html +1 -1
- data/docs/api/Brut/FrontEnd/GenericResponse.html +1 -1
- data/docs/api/Brut/FrontEnd/Handler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers.html +1 -1
- data/docs/api/Brut/FrontEnd/HandlingResults.html +1 -1
- data/docs/api/Brut/FrontEnd/HttpMethod.html +1 -1
- data/docs/api/Brut/FrontEnd/HttpStatus.html +1 -1
- data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +1 -1
- data/docs/api/Brut/FrontEnd/Layout.html +1 -1
- data/docs/api/Brut/FrontEnd/Middleware.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +6 -2
- data/docs/api/Brut/FrontEnd/Middlewares.html +1 -1
- data/docs/api/Brut/FrontEnd/Page.html +1 -1
- data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +1 -1
- data/docs/api/Brut/FrontEnd/Pages.html +1 -1
- data/docs/api/Brut/FrontEnd/RequestContext.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHook.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/Route.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing.html +1 -1
- data/docs/api/Brut/FrontEnd/Session.html +1 -1
- data/docs/api/Brut/FrontEnd.html +1 -1
- data/docs/api/Brut/I18n/BaseMethods.html +1 -1
- data/docs/api/Brut/I18n/ForBackEnd.html +1 -1
- data/docs/api/Brut/I18n/ForCLI.html +1 -1
- data/docs/api/Brut/I18n/ForHTML.html +1 -1
- data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +1 -1
- data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +1 -1
- data/docs/api/Brut/I18n.html +1 -1
- data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +1 -1
- data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +1 -1
- data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +1 -1
- data/docs/api/Brut/Instrumentation/OpenTelemetry.html +1 -1
- data/docs/api/Brut/Instrumentation.html +1 -1
- data/docs/api/Brut/SinatraHelpers/ClassMethods.html +1 -1
- data/docs/api/Brut/SinatraHelpers.html +1 -1
- data/docs/api/Brut/SpecSupport/ClockSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/ComponentSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/E2ETestServer.html +20 -20
- data/docs/api/Brut/SpecSupport/E2eSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/EnhancedNode.html +1 -1
- data/docs/api/Brut/SpecSupport/FlashSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +1 -1
- data/docs/api/Brut/SpecSupport/GeneralSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/HandlerSupport.html +2 -2
- data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +142 -0
- data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +142 -0
- data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +155 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +55 -25
- data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +149 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +46 -19
- data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +149 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +149 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +165 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +158 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +156 -0
- data/docs/api/Brut/SpecSupport/Matchers.html +2 -2
- data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +24 -24
- data/docs/api/Brut/SpecSupport/RSpecSetup.html +55 -20
- data/docs/api/Brut/SpecSupport/SessionSupport.html +1 -1
- data/docs/api/Brut/SpecSupport.html +1 -1
- data/docs/api/Brut.html +1 -1
- data/docs/api/Clock.html +1 -1
- data/docs/api/RichString.html +1 -1
- data/docs/api/SemanticLogger/Appender/Async.html +1 -1
- data/docs/api/Sequel/Extensions/BrutInstrumentation.html +5 -1
- data/docs/api/Sequel/Extensions/BrutMigrations.html +36 -28
- data/docs/api/Sequel/Extensions.html +1 -1
- data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +1 -1
- data/docs/api/Sequel/Plugins/CreatedAt.html +1 -1
- data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +1 -1
- data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +1 -1
- data/docs/api/Sequel/Plugins/ExternalId.html +1 -1
- data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +1 -1
- data/docs/api/Sequel/Plugins/FindBang.html +1 -1
- data/docs/api/Sequel/Plugins.html +1 -1
- data/docs/api/Sequel.html +1 -1
- data/docs/api/SpecSupport/Matchers/BeABug.html +143 -0
- data/docs/api/_index.html +106 -1
- data/docs/api/class_list.html +1 -1
- data/docs/api/css/full_list.css +2 -1
- data/docs/api/css/style.css +14 -13
- data/docs/api/file.README.html +1 -1
- data/docs/api/index.html +1 -1
- data/docs/api/method_list.html +530 -330
- data/docs/api/top-level-namespace.html +1 -1
- data/docs/assets/LogoStop.X8x-4riz.png +0 -0
- data/docs/assets/OverviewMetro.DUS-5fUZ.png +0 -0
- data/docs/assets/{ai.md.tZrjP9im.js → ai.md._6HCDL6d.js} +1 -1
- data/docs/assets/ai.md._6HCDL6d.lean.js +1 -0
- data/docs/assets/{app.D_yaTITQ.js → app.BhrfSt68.js} +1 -1
- data/docs/assets/chunks/@localSearchIndexroot.CeRAdP1K.js +1 -0
- data/docs/assets/chunks/{VPLocalSearchBox.B2-ZzyTY.js → VPLocalSearchBox.Dpot_2H4.js} +1 -1
- data/docs/assets/chunks/{theme.CfGFVRvE.js → theme.N2SNVLgU.js} +2 -2
- data/docs/assets/{components.md.eCttGlN-.js → components.md.CRUMdRoN.js} +1 -1
- data/docs/assets/{configuration.md.BRriU0cL.js → configuration.md.LG-zIBww.js} +1 -1
- data/docs/assets/deployment.md.BLseERGV.js +48 -0
- data/docs/assets/deployment.md.BLseERGV.lean.js +1 -0
- data/docs/assets/{dev-environment.md.BNc8AYiK.js → dev-environment.md.GZv6xvi9.js} +1 -1
- data/docs/assets/doc-conventions.md.-kN3Xo5C.js +1 -0
- data/docs/assets/{doc-conventions.md.DCfRXXi-.lean.js → doc-conventions.md.-kN3Xo5C.lean.js} +1 -1
- data/docs/assets/{forms.md.CBTYQ_Cz.js → forms.md.B-koVgyw.js} +23 -23
- data/docs/assets/{forms.md.CBTYQ_Cz.lean.js → forms.md.B-koVgyw.lean.js} +1 -1
- data/docs/assets/getting-started.md.Dj0qtZI2.js +25 -0
- data/docs/assets/getting-started.md.Dj0qtZI2.lean.js +1 -0
- data/docs/assets/index.md.CuBB-BdM.js +1 -0
- data/docs/assets/index.md.CuBB-BdM.lean.js +1 -0
- data/docs/assets/{instrumentation.md.CL6ax7nT.js → instrumentation.md.a9Pjps4P.js} +2 -2
- data/docs/assets/{instrumentation.md.CL6ax7nT.lean.js → instrumentation.md.a9Pjps4P.lean.js} +1 -1
- data/docs/assets/layouts.md.cPnh3NId.js +51 -0
- data/docs/assets/layouts.md.cPnh3NId.lean.js +1 -0
- data/docs/assets/lsp.md.Bsu-f6VU.js +1 -0
- data/docs/assets/lsp.md.Bsu-f6VU.lean.js +1 -0
- data/docs/assets/{overview.md.CDalkuxV.js → overview.md.DVKRM8zl.js} +4 -4
- data/docs/assets/overview.md.DVKRM8zl.lean.js +1 -0
- data/docs/assets/recipes_authentication.md.CAsXf7hk.js +1 -0
- data/docs/assets/recipes_authentication.md.CAsXf7hk.lean.js +1 -0
- data/docs/assets/{style.D73IYGCX.css → style.B2o1L9eN.css} +1 -1
- data/docs/assets.html +5 -5
- data/docs/brut-js/api/AjaxSubmit.html +1 -1
- data/docs/brut-js/api/AjaxSubmit.js.html +1 -1
- data/docs/brut-js/api/Autosubmit.html +1 -1
- data/docs/brut-js/api/Autosubmit.js.html +1 -1
- data/docs/brut-js/api/BaseCustomElement.html +1 -1
- data/docs/brut-js/api/BaseCustomElement.js.html +1 -1
- data/docs/brut-js/api/BrutCustomElements.html +1 -1
- data/docs/brut-js/api/BufferedLogger.html +1 -1
- data/docs/brut-js/api/ConfirmSubmit.html +1 -1
- data/docs/brut-js/api/ConfirmSubmit.js.html +1 -1
- data/docs/brut-js/api/ConfirmationDialog.html +1 -1
- data/docs/brut-js/api/ConfirmationDialog.js.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessage.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessage.js.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessages.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessages.js.html +1 -1
- data/docs/brut-js/api/CopyToClipboard.html +1 -1
- data/docs/brut-js/api/CopyToClipboard.js.html +1 -1
- data/docs/brut-js/api/Form.html +1 -1
- data/docs/brut-js/api/Form.js.html +1 -1
- data/docs/brut-js/api/I18nTranslation.html +1 -1
- data/docs/brut-js/api/I18nTranslation.js.html +1 -1
- data/docs/brut-js/api/LocaleDetection.html +1 -1
- data/docs/brut-js/api/LocaleDetection.js.html +1 -1
- data/docs/brut-js/api/Logger.html +1 -1
- data/docs/brut-js/api/Logger.js.html +1 -1
- data/docs/brut-js/api/Message.html +1 -1
- data/docs/brut-js/api/Message.js.html +1 -1
- data/docs/brut-js/api/PrefixedLogger.html +1 -1
- data/docs/brut-js/api/RichString.html +1 -1
- data/docs/brut-js/api/RichString.js.html +1 -1
- data/docs/brut-js/api/Tabs.html +1 -1
- data/docs/brut-js/api/Tabs.js.html +1 -1
- data/docs/brut-js/api/Tracing.html +1 -1
- data/docs/brut-js/api/Tracing.js.html +1 -1
- data/docs/brut-js/api/external-CustomElementRegistry.html +1 -1
- data/docs/brut-js/api/external-Performance.html +1 -1
- data/docs/brut-js/api/external-Promise.html +1 -1
- data/docs/brut-js/api/external-ValidityState.html +1 -1
- data/docs/brut-js/api/external-Window.html +1 -1
- data/docs/brut-js/api/external-fetch.html +1 -1
- data/docs/brut-js/api/global.html +1 -1
- data/docs/brut-js/api/index.html +1 -1
- data/docs/brut-js/api/index.js.html +1 -1
- data/docs/brut-js/api/module-testing.html +1 -1
- data/docs/brut-js/api/testing.AssetMetadata.html +1 -1
- data/docs/brut-js/api/testing.AssetMetadataLoader.html +1 -1
- data/docs/brut-js/api/testing.CustomElementTest.html +1 -1
- data/docs/brut-js/api/testing.DOMCreator.html +1 -1
- data/docs/brut-js/api/testing_AssetMetadata.js.html +1 -1
- data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +1 -1
- data/docs/brut-js/api/testing_CustomElementTest.js.html +1 -1
- data/docs/brut-js/api/testing_DOMCreator.js.html +1 -1
- data/docs/brut-js/api/testing_index.js.html +1 -1
- data/docs/brut-js.html +5 -5
- data/docs/business-logic.html +5 -5
- data/docs/cli.html +5 -5
- data/docs/components.html +7 -7
- data/docs/configuration.html +6 -6
- data/docs/css.html +5 -5
- data/docs/custom-element-tests.html +5 -5
- data/docs/database-access.html +5 -5
- data/docs/database-schema.html +5 -5
- data/docs/deployment.html +53 -6
- data/docs/dev-environment.html +6 -6
- data/docs/doc-conventions.html +6 -6
- data/docs/end-to-end-tests.html +5 -5
- data/docs/flash-and-session.html +5 -5
- data/docs/forms.html +28 -28
- data/docs/getting-started.html +30 -7
- data/docs/handlers.html +5 -5
- data/docs/hashmap.json +1 -1
- data/docs/hooks.html +5 -5
- data/docs/i18n.html +5 -5
- data/docs/index.html +6 -6
- data/docs/instrumentation.html +6 -6
- data/docs/javascript.html +5 -5
- data/docs/jobs.html +5 -5
- data/docs/keyword-injection.html +5 -5
- data/docs/layouts.html +74 -0
- data/docs/lsp.html +24 -0
- data/docs/markdown-examples.html +5 -5
- data/docs/middleware.html +5 -5
- data/docs/not-released.html +5 -5
- data/docs/overview.html +9 -9
- data/docs/pages.html +6 -6
- data/docs/recipes/authentication.html +24 -0
- data/docs/routes.html +5 -5
- data/docs/security.html +5 -5
- data/docs/seed-data.html +5 -5
- data/docs/space-time-continuum.html +5 -5
- data/docs/tutorial.html +5 -5
- data/docs/unit-tests.html +5 -5
- data/dx/bash_customizations +7 -0
- data/dx/build +13 -2
- data/dx/docker-compose.env +1 -1
- data/dx/exec +25 -8
- data/lib/brut/cli/app.rb +7 -2
- data/lib/brut/cli/apps/deploy_base.rb +86 -0
- data/lib/brut/cli/apps/heroku_container_based_deploy.rb +194 -0
- data/lib/brut/cli/command.rb +7 -13
- data/lib/brut/cli/executor.rb +31 -5
- data/lib/brut/cli/options.rb +4 -0
- data/lib/brut/cli.rb +4 -3
- data/lib/brut/framework/container.rb +25 -7
- data/lib/brut/framework/errors/abstract_method.rb +7 -0
- data/lib/brut/framework/errors.rb +4 -2
- data/lib/brut/front_end/forms/input.rb +253 -20
- data/lib/brut/front_end/forms/input_definition.rb +15 -12
- data/lib/brut/front_end/middlewares/reload_app.rb +2 -0
- data/lib/brut/front_end.rb +1 -0
- data/lib/brut/spec_support/rspec_setup.rb +42 -2
- data/lib/brut/version.rb +1 -1
- data/lib/sequel/extensions/brut_instrumentation.rb +4 -0
- data/specs/brut/front_end/forms/input.spec.rb +978 -0
- data/specs/spec_helper.rb +27 -0
- data/specs/support/matchers/have_constraint_violation.rb +23 -0
- data/specs/support/matchers.rb +5 -0
- data/specs/support.rb +3 -0
- metadata +77 -29
- data/docs/assets/ai.md.tZrjP9im.lean.js +0 -1
- data/docs/assets/chunks/@localSearchIndexroot.BsN5i0Fi.js +0 -1
- data/docs/assets/deployment.md.Dbka4OTr.js +0 -1
- data/docs/assets/deployment.md.Dbka4OTr.lean.js +0 -1
- data/docs/assets/doc-conventions.md.DCfRXXi-.js +0 -1
- data/docs/assets/getting-started.md.Bz2s1Vjb.js +0 -2
- data/docs/assets/getting-started.md.Bz2s1Vjb.lean.js +0 -1
- data/docs/assets/index.md.B28EwVpq.js +0 -1
- data/docs/assets/index.md.B28EwVpq.lean.js +0 -1
- data/docs/assets/overview.Da81cB9R.png +0 -0
- data/docs/assets/overview.md.CDalkuxV.lean.js +0 -1
- /data/docs/assets/{components.md.eCttGlN-.lean.js → components.md.CRUMdRoN.lean.js} +0 -0
- /data/docs/assets/{configuration.md.BRriU0cL.lean.js → configuration.md.LG-zIBww.lean.js} +0 -0
- /data/docs/assets/{dev-environment.md.BNc8AYiK.lean.js → dev-environment.md.GZv6xvi9.lean.js} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b77e4a2a30122b1805ecf5cb52a5313bb137c188364a6baac62270918cd1640
|
4
|
+
data.tar.gz: 393ad694666d889d5672fb592e7f188e19f78f519f19fbd4a5edb1af32ef5d21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 769c54918d2cb9a3e40e007d954c70ef6ec4033bb1a159d616cc4680aaf5b5d650e0335d729a5acc10b0d9f96574c4dfe5ec5f563bbd82828c6878ea4a532338
|
7
|
+
data.tar.gz: 510b4299c42f476f61110382afdb26c1c71ae8f6aecf16f95bebcf30bb5ac14b0817b08bb0787e3b9b541be59add9e35d4d60df78debbe0627b371aa4639ce00
|
data/.gitignore
CHANGED
@@ -32,3 +32,9 @@
|
|
32
32
|
/brut-css/dist
|
33
33
|
# This is where the CSS lives temporarily while docs are being built
|
34
34
|
/brut-css/src/docs/brut.css
|
35
|
+
|
36
|
+
# Per-developer Bash customizations that could contain secrets
|
37
|
+
/dx/bash_customizations.local
|
38
|
+
|
39
|
+
# Gems are installed here for LSP convienience
|
40
|
+
/local-gems
|
data/.projections.json
ADDED
data/.rspec
ADDED
data/Dockerfile.dx
CHANGED
@@ -10,28 +10,46 @@ RUN apt-get -y clean && \
|
|
10
10
|
apt-get -y update && \
|
11
11
|
apt-get install --quiet --yes ca-certificates curl gnupg rsync
|
12
12
|
|
13
|
-
# Install NODE per https://github.com/nodesource/distributions?tab=readme-ov-file#using-debian-as-root-nodejs-22
|
14
|
-
RUN curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh && \
|
15
|
-
bash /tmp/nodesource_setup.sh && \
|
16
|
-
apt-get install -y nodejs
|
17
|
-
|
18
|
-
# Install Postgres client per https://www.postgresql.org/download/linux/debian/ - note that the
|
19
|
-
# automated configuration doesn't work, I think because it assumes non-root.
|
20
|
-
RUN apt-get -y install lsb-release && \
|
21
|
-
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
|
22
|
-
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
|
23
|
-
apt-get update && \
|
24
|
-
apt-get -y install postgresql-client-16
|
25
|
-
|
26
13
|
RUN echo "gem: --no-document" >> ~/.gemrc && \
|
27
14
|
gem update --system && \
|
28
15
|
gem install bundler
|
29
|
-
|
30
16
|
# Need vim at all times
|
31
17
|
ENV EDITOR=vim
|
32
18
|
RUN apt-get install -y vim && \
|
33
19
|
echo "set -o vi" >> /root/.bashrc
|
34
20
|
|
21
|
+
|
22
|
+
# Setup a non-root user
|
23
|
+
|
24
|
+
# Their user id, which ideally matches their user id on the host
|
25
|
+
ARG user_uid=10001
|
26
|
+
# Their group id, which ideally matches their group id on the host
|
27
|
+
ARG user_gid=10002
|
28
|
+
|
29
|
+
# Create the user's group ID if it does not exist
|
30
|
+
RUN getent group ${user_gid} || groupadd --gid ${user_gid} appgroup
|
31
|
+
# Create the user. Note that we put bash_customizations in both .profile and .bashrc
|
32
|
+
# to increase the chances they are used when running bash in various configurations
|
33
|
+
RUN useradd --uid ${user_uid} --gid ${user_gid} --create-home --home-dir /home/appuser appuser && \
|
34
|
+
echo ". ~/.bash_customizations" >> /home/appuser/.profile && \
|
35
|
+
echo ". ~/.bash_customizations.local" >> /home/appuser/.profile && \
|
36
|
+
echo ". ~/.bash_customizations" >> /home/appuser/.bashrc && \
|
37
|
+
echo ". ~/.bash_customizations.local" >> /home/appuser/.bashrc
|
38
|
+
|
39
|
+
COPY --chown=appuser:${user_gid} dx/show-help-in-app-container-then-wait.sh /home/appuser
|
40
|
+
COPY --chown=appuser:${user_gid} dx/bash_customizations /home/appuser/.bash_customizations
|
41
|
+
COPY --chown=appuser:${user_gid} dx/bash_customizations.local /home/appuser/.bash_customizations.local
|
42
|
+
|
43
|
+
# NOT including the group here as that will place the user's environment
|
44
|
+
# ONLY in that group and not in all the groups in which they are a part.
|
45
|
+
USER appuser
|
46
|
+
|
47
|
+
# Install NodeJS, per https://nodejs.org/en/download
|
48
|
+
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && \
|
49
|
+
\. "$HOME/.nvm/nvm.sh" && \
|
50
|
+
nvm install 22 && \
|
51
|
+
node -v && nvm current && npm -v
|
52
|
+
|
35
53
|
# Node's colors are hand-crafted to always look bad and render at least some text unreadable
|
36
54
|
# no matter what your setup. Cool.
|
37
55
|
ENV NODE_DISABLE_COLORS=1
|
data/Gemfile.lock
CHANGED
Binary file
|
Binary file
|
data/assets/LogoStop.pxd
ADDED
Binary file
|
data/assets/LogoTall.pxd
ADDED
Binary file
|
data/bin/docs
CHANGED
@@ -14,14 +14,36 @@ OptionParser.new do |opts|
|
|
14
14
|
end
|
15
15
|
end.parse!
|
16
16
|
|
17
|
-
public_dir = (Pathname(__FILE__).dirname / ".." / "brutrb.com" / "public" ).expand_path
|
18
|
-
docs_dir = public_dir
|
17
|
+
public_dir = (Pathname(__FILE__).dirname / ".." / "brutrb.com" / "public" ).expand_path
|
18
|
+
docs_dir = public_dir / "api"
|
19
19
|
brutjs_dir = (Pathname(__FILE__).dirname / ".." / "brut-js" ).expand_path.to_s
|
20
20
|
|
21
21
|
system(
|
22
22
|
"bundle exec yard doc -o '#{docs_dir}' -m markdown -M rdiscount --backtrace"
|
23
23
|
)
|
24
24
|
|
25
|
+
puts "Hacking CSS"
|
26
|
+
[
|
27
|
+
docs_dir / "css" / "style.css",
|
28
|
+
docs_dir / "css" / "full_list.css"
|
29
|
+
].each do |css_file_to_hack|
|
30
|
+
lines = File.read(css_file_to_hack).split(/\n/)
|
31
|
+
File.open(css_file_to_hack, "w") do |f|
|
32
|
+
lines.each do |line|
|
33
|
+
if line =~ /\"Lucida Sans"/
|
34
|
+
f.puts line.gsub(/\"Lucida Sans\"/, '"Helvetica Neue", "Lucida Sans"')
|
35
|
+
elsif line =~ / Monaco,/
|
36
|
+
f.puts line.gsub(/ Monaco,/, '"Courier New", Monaco,')
|
37
|
+
elsif line =~ /font-family: monospace;/
|
38
|
+
f.puts line.gsub(/font-family: monospace;/, 'font-family: "Courier New", monospace;')
|
39
|
+
else
|
40
|
+
f.puts line
|
41
|
+
end
|
42
|
+
end
|
43
|
+
f.puts "code { font-family: 'Courier New', monospace; font-weight: 600; }"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
25
47
|
FileUtils.chdir brutjs_dir do
|
26
48
|
system("bin/build")
|
27
49
|
end
|
data/bin/rspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/setup
CHANGED
@@ -83,7 +83,7 @@ def setup(update_gems:,setup_credentials:)
|
|
83
83
|
system! "ssh-add #{key_file}"
|
84
84
|
end
|
85
85
|
|
86
|
-
known_hosts_dest = Pathname("/") / "
|
86
|
+
known_hosts_dest = Pathname("/") / "home" / "appuser" / ".ssh" / "known_hosts"
|
87
87
|
if known_hosts_dest.exist?
|
88
88
|
log "#{known_hosts_dest} exists, your ssh key should work with GitHub"
|
89
89
|
else
|
@@ -117,7 +117,7 @@ def setup(update_gems:,setup_credentials:)
|
|
117
117
|
end
|
118
118
|
log "Your ssh key looks good"
|
119
119
|
|
120
|
-
gem_credentials_dest = Pathname("/") / "
|
120
|
+
gem_credentials_dest = Pathname("/") / "home" / "appuser" / ".gem" / "credentials"
|
121
121
|
if gem_credentials_dest.exist?
|
122
122
|
log "Gem credentials look good"
|
123
123
|
else
|
@@ -139,7 +139,7 @@ def setup(update_gems:,setup_credentials:)
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
-
npm_credentials_dest = Pathname("/") / "
|
142
|
+
npm_credentials_dest = Pathname("/") / "home" / "appuser" / ".npmrc"
|
143
143
|
if npm_credentials_dest.exist?
|
144
144
|
log "NPM credentials look good"
|
145
145
|
else
|
@@ -39,6 +39,7 @@ export default defineConfig({
|
|
39
39
|
items: [
|
40
40
|
{ text: "Routes", link: "/routes" },
|
41
41
|
{ text: "Pages", link: "/pages" },
|
42
|
+
{ text: "Layouts", link: "/layouts" },
|
42
43
|
{ text: "Forms", link: "/forms" },
|
43
44
|
{ text: "Handlers and Actions", link: "/handlers" },
|
44
45
|
{ text: "Components", link: "/components" },
|
@@ -51,13 +51,14 @@
|
|
51
51
|
|
52
52
|
--blue-vp-c-brand-1: #0C00A7;
|
53
53
|
--blue-vp-c-brand-2: #6357FF;
|
54
|
-
--blue-vp-c-brand-3: #
|
55
|
-
--blue-vp-c-brand-soft: #
|
54
|
+
--blue-vp-c-brand-3: #4C0606;
|
55
|
+
--blue-vp-c-brand-soft: #FFF9F9;
|
56
|
+
|
57
|
+
--vp-c-brand-1: #362400;
|
58
|
+
--vp-c-brand-2: #F1A100;
|
59
|
+
--vp-c-brand-3: #281B00;
|
60
|
+
--vp-c-brand-soft: #FFF1D6;
|
56
61
|
|
57
|
-
--vp-c-brand-1: #A70C00;
|
58
|
-
--vp-c-brand-2: #FF6357;
|
59
|
-
--vp-c-brand-3: #e21000;
|
60
|
-
--vp-c-brand-soft: #FFE7E5;
|
61
62
|
|
62
63
|
--xvp-c-brand-1: var(--vp-c-indigo-1);
|
63
64
|
--xvp-c-brand-2: var(--vp-c-indigo-2);
|
@@ -69,15 +70,25 @@
|
|
69
70
|
--vp-c-tip-3: var(--vp-c-brand-3);
|
70
71
|
--vp-c-tip-soft: var(--vp-c-brand-soft);
|
71
72
|
|
72
|
-
--
|
73
|
-
--
|
74
|
-
--
|
75
|
-
--
|
76
|
-
|
77
|
-
--vp-c-
|
78
|
-
--vp-c-
|
79
|
-
--vp-c-
|
80
|
-
--vp-c-
|
73
|
+
--xvp-c-warning-1: var(--vp-c-yellow-1);
|
74
|
+
--xvp-c-warning-2: var(--vp-c-yellow-2);
|
75
|
+
--xvp-c-warning-3: var(--vp-c-yellow-3);
|
76
|
+
--xvp-c-warning-soft: var(--vp-c-yellow-soft);
|
77
|
+
|
78
|
+
--vp-c-warning-1: #9E5601;
|
79
|
+
--vp-c-warning-2: #FDAF53;
|
80
|
+
--vp-c-warning-3: #5E3301;
|
81
|
+
--vp-c-warning-soft: #FFF3E5;
|
82
|
+
|
83
|
+
--vp-c-danger-1: #AC0E0E;
|
84
|
+
--vp-c-danger-2: #F14E4E;
|
85
|
+
--vp-c-danger-3: #4C0606;
|
86
|
+
--vp-c-danger-soft: #FFF9F9;
|
87
|
+
|
88
|
+
--xvp-c-danger-1: var(--vp-c-red-1);
|
89
|
+
--xvp-c-danger-2: var(--vp-c-red-2);
|
90
|
+
--xvp-c-danger-3: var(--vp-c-red-3);
|
91
|
+
--xvp-c-danger-soft: var(--vp-c-red-soft);
|
81
92
|
}
|
82
93
|
|
83
94
|
/**
|
data/brutrb.com/deployment.md
CHANGED
@@ -1,66 +1,144 @@
|
|
1
1
|
# Deployment
|
2
2
|
|
3
3
|
Brut apps are Rack apps, so they can be deployed in conventional
|
4
|
-
ways.
|
5
|
-
development are inteded to work for production as well.
|
4
|
+
ways.
|
6
5
|
|
7
6
|
## Overview
|
8
7
|
|
9
|
-
|
10
|
-
simple solution for all deployment setups, so this document will
|
11
|
-
outline considerations when setting up deployment.
|
8
|
+
There are just too many ways to deploy. Brut attempts to address this by adhering to [12-factor principles](https://12factor.net). Brut also tries not to create artifacts like `Procfile` or `Dockerfile` that would conflict with the artifacts you'd need to manage deployment.
|
12
9
|
|
13
|
-
|
14
|
-
at `deploy/Dockerfile`, which is the foundation of a `Dockerfile`
|
15
|
-
you can use. In particular, it shows you the commands needed to
|
16
|
-
setup and run the app in production:
|
10
|
+
That said, Brut includes first-class support for deploying to Heroku using containers. More options will be included as necessary, either through direct support in code/tooling, or documentation here.
|
17
11
|
|
18
|
-
|
19
|
-
as whatever is needed for NodeJS and Postgres, the Brut-specific
|
20
|
-
parts look like so:
|
12
|
+
### Heroku Container-based Deployment
|
21
13
|
|
22
|
-
|
23
|
-
2. Install Node modules with `npm clean-install`
|
24
|
-
3. Build all assets with `bin/build-assets` (this will bundle all
|
25
|
-
CSS and Javascript, plus copy over any other [assets](/assets)
|
26
|
-
to the locations from where the Brut app will serve them)
|
27
|
-
4. Run the app with `bin/run`
|
14
|
+
When creating your Brut app with `mkbrut`, the Heroku segment can be used to create files and scripts for a [Heroku container-based deployment](https://devcenter.heroku.com/articles/container-registry-and-runtime).
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
16
|
+
| File | Purpose | Notes |
|
17
|
+
|------|---------|-------|
|
18
|
+
| `bin/deploy` | Script to use to perform the deployment | This wraps `HerokuContainerBasedDeploy` in `Brut::CLI::Apps` |
|
19
|
+
| `deploy/Dockerfile` | Template `Dockerfile` used to create a `Dockerfile` for each process type | Heroku requires each process (web, worker, release, etc.) to have its own `Dockerfile` and own image |
|
20
|
+
| `deploy/heroku_config.rb` | Class that exports optional processes | By default, your app has a web and release process. `HerokuConfig` can export others, like Sidekiq |
|
21
|
+
| `deploy/docker-entrypoint` | The [`ENTRYPOINT`](https://docs.docker.com/reference/dockerfile/#entrypoint) for production Docker images, which is set up to use jemalloc | You can modify or remove this as needed |
|
22
|
+
|
23
|
+
How to deploy:
|
24
|
+
|
25
|
+
1. Auth to Heroku from inside your dev container:
|
26
|
+
|
27
|
+
```
|
28
|
+
your-computer> dx/exec bash
|
29
|
+
devcontainer> heroku auth:login
|
30
|
+
# You will need to copy/paste the URL to log in
|
31
|
+
devcontainer> heroku container:login
|
32
|
+
```
|
33
|
+
|
34
|
+
2. Create your app using the container stack:
|
35
|
+
|
36
|
+
```
|
37
|
+
> heroku create --stack container -a «your heroku app name»
|
38
|
+
```
|
39
|
+
3. Ensure your app's source code is all checked in, there are no uncommitted or unadded files, and you have pushed to main.
|
40
|
+
4. `bin/deploy`
|
41
|
+
|
42
|
+
This will generate a `Dockerfile` for each process (by default, `Dockerfile.web` and `Dockerfile.release`), build images, push those images to Heroku, and ask Heroku to release them.
|
43
|
+
|
44
|
+
Debugging Tips:
|
45
|
+
|
46
|
+
* Keep in mind it's hard to make general deployment tools. You are expected to understand your deployment and be capable of deploying an arbitrary Rack app manually. Brut's tooling automates what you need to know.
|
47
|
+
* `bin/deploy` runs the `deploy` subcommand, so `bin/deploy help deploy` can provide
|
48
|
+
some options for debugging issues:
|
49
|
+
|
50
|
+
```
|
51
|
+
devcontainer> bin/deploy help deploy
|
52
|
+
Usage: bin/deploy [global options] deploy [command options]
|
53
|
+
|
54
|
+
Build images, push them to Heroku, and deploy them
|
55
|
+
|
56
|
+
Manages a deploy process based on using Heroku's Container Registry. See
|
57
|
+
|
58
|
+
https://devcenter.heroku.com/articles/container-registry-and-runtime
|
59
|
+
|
60
|
+
for details. You are assumed to understand this.
|
61
|
+
This command will make the process somewhat easier.
|
62
|
+
|
63
|
+
This will use deploy/Dockerfile as a template to create
|
64
|
+
one Dockerfile for each process you want to run in Heroku.
|
65
|
+
deploy/heroku_config.rb is where the processes and their
|
66
|
+
commands are configured.
|
67
|
+
|
68
|
+
The release phase is included automatically, based on bin/release.
|
69
|
+
|
70
|
+
GLOBAL OPTIONS
|
71
|
+
|
72
|
+
-h, --help Get help
|
73
|
+
--log-level=LEVEL Set log level. Allowed values: debug,
|
74
|
+
info, warn, error, fatal. Default 'fatal'
|
75
|
+
--verbose Set log level to 'debug', which will produce
|
76
|
+
maximum output
|
77
|
+
|
78
|
+
ENVIRONMENT VARIABLES
|
79
|
+
|
80
|
+
BRUT_CLI_RAISE_ON_ERROR - if set, shows backtrace on errors
|
81
|
+
LOG_LEVEL - log level if --log-level or --verbose is omitted
|
82
|
+
|
83
|
+
|
84
|
+
COMMAND OPTIONS
|
85
|
+
|
86
|
+
--platform=PLATFORM Override default platform. Can be any Docker
|
87
|
+
platform.
|
88
|
+
--[no-]dry-run Print the commands that would be run and
|
89
|
+
don't actually do anything. Implies --skip-checks
|
90
|
+
--[no-]skip-checks Skip checks for code having been
|
91
|
+
committed and pushed
|
92
|
+
--[no-]deploy After images are pushed, actually deploy them
|
93
|
+
--[no-]push After images are created, push them
|
94
|
+
to Heroku's registry. If false,
|
95
|
+
implies --no-deploy
|
96
|
+
```
|
97
|
+
* Try building images first: `bin/deploy deploy --no-push --skip-checks`
|
98
|
+
* It's possible to run the images locally. If you are on Apple Silicon, you'll
|
99
|
+
need to set --platform:
|
100
|
+
|
101
|
+
* `bin/deploy deploy --no-push --skip-checks --platform linux/arm64`
|
102
|
+
* Create `docker-compose.yml` for your image and any other services e.g. databases
|
103
|
+
* Set required environment variables in `docker-compose.yml`
|
104
|
+
* Start up Docker compose and poke around
|
105
|
+
|
106
|
+
You'll need to have a better understanding of Docker to do this, however if you
|
107
|
+
are deploying with Docker, this is an understanding you hopefully already have.
|
108
|
+
|
109
|
+
|
110
|
+
### Other Mechanisms for Deployment
|
111
|
+
|
112
|
+
As a Rack app, other deployments should be possible. To make the app work, you'll need to make sure a few things are dealt with:
|
113
|
+
|
114
|
+
* `RACK_ENV` **must** be `"production"`
|
115
|
+
* `bin/build-assets` will build all assets by default. This must either be done on production servers or done ahead of time and the results packaged with the app.
|
116
|
+
* `bin/build-assets` outputs files in `app/public` and `app/config`. Those files are used at runtime. Brut **will not** initiate the build of any assets.
|
117
|
+
* If you are going to build assets on production servers, you *must* included developer tooling. This means NodeJS, all modules in `package.json` and all RubyGems in `Gemfile`.
|
118
|
+
|
119
|
+
The `deploy/Dockerfile` created by `mkbrut --segment-heroku` is not very Heroku-specific and could serve as a reference.
|
33
120
|
|
34
121
|
## Testing
|
35
122
|
|
36
|
-
|
37
|
-
them locally to see how they work. You will need to have local
|
38
|
-
versions of all infrastructure (database, Redis, etc.), but if
|
39
|
-
these work locally, there is a high chance they work in
|
40
|
-
production.
|
123
|
+
Testing deployments is a bit out of scope, but in general:
|
41
124
|
|
42
|
-
|
43
|
-
|
125
|
+
* A container-based deployment can theoretically be run on your computer as a test.
|
126
|
+
* Non-production, but production-like environments can be used to validate production configurations.
|
127
|
+
* You own the means of production…not Brut.
|
44
128
|
|
45
129
|
## Recommended Practices
|
46
130
|
|
47
|
-
|
48
|
-
|
49
|
-
|
131
|
+
* Avoid a lot of code that checks `Brut.container.project_env`. Try to consolidate all prod/test/dev differences in environment variables.
|
132
|
+
* Have a way to get a shell into your production environment for debugging.
|
133
|
+
* Brut doesn't log much, but if you remove the `OTEL_*` environment variables, Brut will log OTel telemetry to the console, which may be useful.
|
134
|
+
* Setting `OTEL_LOG_LEVEL=debug` is advised if the app isn't starting or you aren't seeing any telemetry or logging
|
50
135
|
|
51
|
-
|
52
|
-
of surprises. That all being said, here are some recommendations:
|
136
|
+
## Technical Notes
|
53
137
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
card you charge and refund.
|
58
|
-
* Configure observability so you know what your app is doing at
|
59
|
-
all times.
|
60
|
-
* Configure a URL that, when accessed, produces an error. This
|
61
|
-
allows you to check your error reporting system.
|
62
|
-
* Create a page somewhere that shows the git SHA of your
|
63
|
-
deployment, or some other unique, unambiguous version number. This
|
64
|
-
will clarify what version of the code is actually running.
|
138
|
+
> [!IMPORTANT]
|
139
|
+
> Technical Notes are for deeper understanding and debugging. While we will try to keep them up-to-date with changes to Brut's
|
140
|
+
> internals, the source code is always more correct.
|
65
141
|
|
142
|
+
_Last Updated July 3, 2025_
|
66
143
|
|
144
|
+
None at this time.
|
@@ -137,16 +137,17 @@ that the versions of these command line apps provided when you set up your app a
|
|
137
137
|
While you are free to set up mise or rbenv or whatever to run all this on your computer, this way of
|
138
138
|
working is currently not supported nor encouraged. For now, Brut will focus on the Docker-based approach.
|
139
139
|
|
140
|
-
|
141
|
-
|
140
|
+
The primary reason is that it's a tightly controlled environment that is almost
|
141
|
+
entirely scriptable, but does not require devs to abandon their preffered editor.
|
142
|
+
Environment manager-based approaches tend to be more fussy and require documentation
|
143
|
+
to ensure they are set up.
|
142
144
|
|
143
|
-
|
145
|
+
Keep in mind a few things when adding your own automation:
|
144
146
|
|
145
147
|
* The *Foundational Core* is bootstrapped in a degenerate environment without reliable tools beyond Bash.
|
146
148
|
This is why it's almost entirely written in Bash, since it's available everywhere and relatively stable.
|
147
149
|
* The *Workspace* **can and should** rely on the languages and third party modules that are part of your
|
148
|
-
app.
|
149
|
-
particular Ruby gem having been installed.
|
150
|
+
app. The only exception is `bin/setup`, since it installs third party modules. As such, it should work entirely based on Ruby and its standard library.
|
150
151
|
|
151
152
|
## Technical Notes
|
152
153
|
|
@@ -6,7 +6,7 @@ Brut attempts to use existing terminology where possible, particularly where tha
|
|
6
6
|
|
7
7
|
When speaking about Ruby, we prefer the term *initializer* over constructor, *parameters* over arguments, and *methods* over messages. We also prefer *tests* over specs, however test files *are* located in `specs/` and named `*.spec.rb` to be consistent with RSpec's nomenclature. We prefer *end-to-end* or *e2e* tests instead of browser tests or request specs.
|
8
8
|
|
9
|
-
Further, Brut doesn't render HTML, it *generates* it. The browser renders the HTML for the website's visitor.
|
9
|
+
Further, Brut doesn't render HTML, it *generates* it. The browser renders the HTML for the website's visitor. One exception is Phlex, which uses the term *render* to mean "generate HTML to an internal buffer that will be delivered to the client later". Thus, you will need to call Phlex's `render` method from time to time, even though it is not rendering HTML but helping to generate it.
|
10
10
|
|
11
11
|
Lastly, the documentation tries to talk about the person accessing a website as a "vistor" not a "user". Though the "user" nomenclature is near-ossified in software development, we feel "visitor" is more apt.
|
12
12
|
|