brut 0.14.0 → 0.16.0.pre
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 +2 -0
- data/CHANGELOG.md +10 -0
- data/Dockerfile.dx +3 -6
- data/Gemfile.lock +1 -1
- data/brut-css/package-lock.json +2 -2
- data/brut-css/package.json +1 -1
- data/brut-js/package-lock.json +2 -2
- data/brut-js/package.json +1 -1
- data/brut-js/specs/Toast.spec.js +34 -0
- data/brut-js/src/I18nTranslation.js +3 -0
- data/brut-js/src/Message.js +9 -3
- data/brut-js/src/RichString.js +4 -1
- data/brut-js/src/Toast.js +102 -0
- data/brut-js/src/index.js +3 -0
- data/brutrb.com/.vitepress/config.mjs +4 -3
- data/brutrb.com/brut-js.md +1 -0
- data/brutrb.com/deployment.md +23 -9
- data/brutrb.com/jobs.md +107 -7
- data/brutrb.com/recipes/dev-env-secrets.md +87 -0
- data/brutrb.com/roadmap.md +2 -7
- data/docs/404.html +3 -3
- data/docs/adrs.html +7 -7
- data/docs/ai.html +7 -7
- 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 +1 -1
- data/docs/api/Brut/CLI/AppRunner.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Create.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Drop.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Migrate.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Seed.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Status.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB.html +1 -1
- data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +1 -1
- data/docs/api/Brut/CLI/Apps/DeployBase.html +1 -1
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +1 -1
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/DbModel.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/Audit.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/E2e.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/JS.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/Run.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test.html +1 -1
- data/docs/api/Brut/CLI/Apps.html +1 -1
- data/docs/api/Brut/CLI/Command.html +1 -1
- 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 +1 -1
- data/docs/api/Brut/CLI/InvalidOption.html +1 -1
- data/docs/api/Brut/CLI/Options.html +1 -1
- 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 +1 -1
- data/docs/api/Brut/Framework/Error.html +1 -1
- data/docs/api/Brut/Framework/Errors/AbstractMethod.html +1 -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 +1 -1
- 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 +1 -1
- data/docs/api/Brut/FrontEnd/Component.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +1 -1
- 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/ButtonTag.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +1 -1
- 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 +37 -18
- 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 +1 -1
- data/docs/api/Brut/FrontEnd/CsrfProtector.html +1 -1
- 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/Button.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ButtonInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/Input.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +1 -1
- 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 +171 -3
- 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 +1 -1
- 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/Methods/ClassMethods.html +1 -1
- data/docs/api/Brut/Instrumentation/Methods.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/RubocopConfig.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 +1 -1
- 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 +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers.html +1 -1
- data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/RSpecSetup.html +1 -1
- 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/ModuleName.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 +1 -1
- data/docs/api/Sequel/Extensions/BrutMigrations.html +1 -1
- 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/_index.html +1 -1
- data/docs/api/file.README.html +1 -1
- data/docs/api/index.html +1 -1
- data/docs/api/method_list.html +157 -141
- data/docs/api/top-level-namespace.html +1 -1
- data/docs/assets/adrs.md.YglbWtQe.js +1 -0
- data/docs/assets/adrs.md.YglbWtQe.lean.js +1 -0
- data/docs/assets/ai.md.ChLnvDAX.js +1 -0
- data/docs/assets/ai.md.ChLnvDAX.lean.js +1 -0
- data/docs/assets/{app.BDtsVxyd.js → app.Dm7v_ouO.js} +1 -1
- data/docs/assets/{assets.md.7C3HWkga.js → assets.md.BEF6Oz6K.js} +2 -2
- data/docs/assets/assets.md.BEF6Oz6K.lean.js +1 -0
- data/docs/assets/{brut-js.md.B4GYxQVw.js → brut-js.md.BMz0X1Rz.js} +2 -2
- data/docs/assets/brut-js.md.BMz0X1Rz.lean.js +1 -0
- data/docs/assets/business-logic.md.DbuaOYGU.js +1 -0
- data/docs/assets/business-logic.md.DbuaOYGU.lean.js +1 -0
- data/docs/assets/chunks/@localSearchIndexroot.BiNFswvo.js +1 -0
- data/docs/assets/chunks/VPLocalSearchBox.DQK6jQou.js +8 -0
- data/docs/assets/chunks/framework.C4nOkCZI.js +18 -0
- data/docs/assets/chunks/{theme.DZKmijwi.js → theme.BuExsdM9.js} +2 -2
- data/docs/assets/{cli.md.CjsktgFz.js → cli.md.DDMar_51.js} +2 -2
- data/docs/assets/cli.md.DDMar_51.lean.js +1 -0
- data/docs/assets/{components.md.rMhQ0WdZ.js → components.md.Dfd3w6UW.js} +5 -5
- data/docs/assets/components.md.Dfd3w6UW.lean.js +1 -0
- data/docs/assets/{configuration.md.BK42Yjp_.js → configuration.md.DTYoV2Ea.js} +2 -2
- data/docs/assets/configuration.md.DTYoV2Ea.lean.js +1 -0
- data/docs/assets/{css.md.CltvJqAa.js → css.md.K5rOCOQY.js} +2 -2
- data/docs/assets/css.md.K5rOCOQY.lean.js +1 -0
- data/docs/assets/{custom-element-tests.md.B_rbta32.js → custom-element-tests.md.DiLe-eFw.js} +2 -2
- data/docs/assets/custom-element-tests.md.DiLe-eFw.lean.js +1 -0
- data/docs/assets/{database-access.md.gnluu54N.js → database-access.md.Dc8l2Plf.js} +2 -2
- data/docs/assets/database-access.md.Dc8l2Plf.lean.js +1 -0
- data/docs/assets/{database-schema.md.LpmBPVEU.js → database-schema.md.BJ_JhXmO.js} +2 -2
- data/docs/assets/database-schema.md.BJ_JhXmO.lean.js +1 -0
- data/docs/assets/{deployment.md.BLseERGV.js → deployment.md.C1u5ep0g.js} +2 -2
- data/docs/assets/deployment.md.C1u5ep0g.lean.js +1 -0
- data/docs/assets/{dev-environment.md.DRH2D2-O.js → dev-environment.md.B1S9p5ZK.js} +2 -2
- data/docs/assets/{dev-environment.md.DRH2D2-O.lean.js → dev-environment.md.B1S9p5ZK.lean.js} +1 -1
- data/docs/assets/{dir-structure.md.CWir1pic.js → dir-structure.md.D1T2kGwj.js} +2 -2
- data/docs/assets/dir-structure.md.D1T2kGwj.lean.js +1 -0
- data/docs/assets/doc-conventions.md.CDnWaEFg.js +1 -0
- data/docs/assets/doc-conventions.md.CDnWaEFg.lean.js +1 -0
- data/docs/assets/{end-to-end-tests.md.DzqRpZ43.js → end-to-end-tests.md.BJJdNDYL.js} +2 -2
- data/docs/assets/end-to-end-tests.md.BJJdNDYL.lean.js +1 -0
- data/docs/assets/{features.md.DPFXsy0z.js → features.md.BDWxnyNO.js} +2 -2
- data/docs/assets/features.md.BDWxnyNO.lean.js +1 -0
- data/docs/assets/{flash-and-session.md.nPvUpnUx.js → flash-and-session.md.CUsMxoNl.js} +2 -2
- data/docs/assets/flash-and-session.md.CUsMxoNl.lean.js +1 -0
- data/docs/assets/{form-constraints.md.KTv5cdR4.js → form-constraints.md.KlfXSKm2.js} +2 -2
- data/docs/assets/form-constraints.md.KlfXSKm2.lean.js +1 -0
- data/docs/assets/{forms.md.v9qIbmUM.js → forms.md.DEkmJUvb.js} +3 -3
- data/docs/assets/forms.md.DEkmJUvb.lean.js +1 -0
- data/docs/assets/{getting-started.md.DTOl4c2g.js → getting-started.md.DO-4eoGW.js} +4 -4
- data/docs/assets/getting-started.md.DO-4eoGW.lean.js +1 -0
- data/docs/assets/{handlers.md.h84MMB1R.js → handlers.md.C5tUwmmo.js} +2 -2
- data/docs/assets/handlers.md.C5tUwmmo.lean.js +1 -0
- data/docs/assets/{hooks.md.Jmb5VOLA.js → hooks.md.CoiYCKRc.js} +2 -2
- data/docs/assets/hooks.md.CoiYCKRc.lean.js +1 -0
- data/docs/assets/{i18n.md.BAm9t9JJ.js → i18n.md.DxkCKhUw.js} +2 -2
- data/docs/assets/i18n.md.DxkCKhUw.lean.js +1 -0
- data/docs/assets/{index.md.Bn9e0sRJ.js → index.md.DnphWyQd.js} +1 -1
- data/docs/assets/{index.md.Bn9e0sRJ.lean.js → index.md.DnphWyQd.lean.js} +1 -1
- data/docs/assets/{instrumentation.md._lNSriEZ.js → instrumentation.md.BcxjC4jd.js} +2 -2
- data/docs/assets/instrumentation.md.BcxjC4jd.lean.js +1 -0
- data/docs/assets/{javascript.md.DzrMxUmI.js → javascript.md.D6fxhaQb.js} +2 -2
- data/docs/assets/javascript.md.D6fxhaQb.lean.js +1 -0
- data/docs/assets/jobs.md.Bc7Y1YpK.js +1 -0
- data/docs/assets/jobs.md.Bc7Y1YpK.lean.js +1 -0
- data/docs/assets/{keyword-injection.md.95Zgh2eN.js → keyword-injection.md.CqLnnzIz.js} +2 -2
- data/docs/assets/keyword-injection.md.CqLnnzIz.lean.js +1 -0
- data/docs/assets/layouts.md.HEbeK7Jr.js +68 -0
- data/docs/assets/layouts.md.HEbeK7Jr.lean.js +1 -0
- data/docs/assets/lsp.md.bE9dW8n9.js +1 -0
- data/docs/assets/lsp.md.bE9dW8n9.lean.js +1 -0
- data/docs/assets/{markdown-examples.md.CCFEQO44.js → markdown-examples.md.BPmtHlc-.js} +2 -2
- data/docs/assets/markdown-examples.md.BPmtHlc-.lean.js +1 -0
- data/docs/assets/{middleware.md.Czz_UlJN.js → middleware.md.BhOIsg59.js} +2 -2
- data/docs/assets/middleware.md.BhOIsg59.lean.js +1 -0
- data/docs/assets/overview.md.BpWAgPFH.js +1 -0
- data/docs/assets/overview.md.BpWAgPFH.lean.js +1 -0
- data/docs/assets/{pages.md.B7Hc-i6H.js → pages.md.B3sQXpEd.js} +2 -2
- data/docs/assets/pages.md.B3sQXpEd.lean.js +1 -0
- data/docs/assets/{recipes_alternate-layouts.md.BwEytl59.js → recipes_alternate-layouts.md.C1QzVkA7.js} +2 -2
- data/docs/assets/recipes_alternate-layouts.md.C1QzVkA7.lean.js +1 -0
- data/docs/assets/{recipes_authentication.md.nwO6F7Ou.js → recipes_authentication.md.CyvoIW82.js} +2 -2
- data/docs/assets/recipes_authentication.md.CyvoIW82.lean.js +1 -0
- data/docs/assets/{recipes_custom-flash.md.CrQbI5eH.js → recipes_custom-flash.md.6gFqf2uL.js} +2 -2
- data/docs/assets/recipes_custom-flash.md.6gFqf2uL.lean.js +1 -0
- data/docs/assets/{recipes_form-errors.md.Bv5RCKqH.js → recipes_form-errors.md.B5ptSzMO.js} +2 -2
- data/docs/assets/recipes_form-errors.md.B5ptSzMO.lean.js +1 -0
- data/docs/assets/{recipes_indexed-forms.md.CstYyOSo.js → recipes_indexed-forms.md.BYYQGW2C.js} +2 -2
- data/docs/assets/recipes_indexed-forms.md.BYYQGW2C.lean.js +1 -0
- data/docs/assets/{recipes_migrations.md.CTcnWDJF.js → recipes_migrations.md.Cid7-3cu.js} +2 -2
- data/docs/assets/recipes_migrations.md.Cid7-3cu.lean.js +1 -0
- data/docs/assets/{recipes_text-field-component.md.H4wLAK0Z.js → recipes_text-field-component.md.VhOsCtKI.js} +2 -2
- data/docs/assets/recipes_text-field-component.md.VhOsCtKI.lean.js +1 -0
- data/docs/assets/roadmap.md.CJsbUmK_.js +1 -0
- data/docs/assets/roadmap.md.CJsbUmK_.lean.js +1 -0
- data/docs/assets/{routes.md.BD6y2i-f.js → routes.md.C1dgIBtD.js} +2 -2
- data/docs/assets/routes.md.C1dgIBtD.lean.js +1 -0
- data/docs/assets/security.md.Jn4SY1uK.js +1 -0
- data/docs/assets/security.md.Jn4SY1uK.lean.js +1 -0
- data/docs/assets/{seed-data.md.BvFZlqIk.js → seed-data.md.UZW0WxYN.js} +2 -2
- data/docs/assets/seed-data.md.UZW0WxYN.lean.js +1 -0
- data/docs/assets/space-time-continuum.md.D9rYGDFH.js +1 -0
- data/docs/assets/space-time-continuum.md.D9rYGDFH.lean.js +1 -0
- data/docs/assets/{tutorial.md.BM40jnoq.js → tutorial.md.BX6f6l00.js} +2 -2
- data/docs/assets/tutorial.md.BX6f6l00.lean.js +1 -0
- data/docs/assets/{tutorials_01-intro.md.B4sUBY3X.js → tutorials_01-intro.md.CzZ3kpF_.js} +2 -2
- data/docs/assets/{tutorials_01-intro.md.B4sUBY3X.lean.js → tutorials_01-intro.md.CzZ3kpF_.lean.js} +1 -1
- data/docs/assets/{tutorials_02-dialog.md.CPNK1SC_.js → tutorials_02-dialog.md.D2vSjDVf.js} +2 -2
- data/docs/assets/{tutorials_02-dialog.md.CPNK1SC_.lean.js → tutorials_02-dialog.md.D2vSjDVf.lean.js} +1 -1
- data/docs/assets/{unit-tests.md.DUGrnLj5.js → unit-tests.md.vDsdBbO_.js} +2 -2
- data/docs/assets/unit-tests.md.vDsdBbO_.lean.js +1 -0
- data/docs/assets/why.md.4WpxdrQ2.js +1 -0
- data/docs/assets/why.md.4WpxdrQ2.lean.js +1 -0
- data/docs/assets.html +7 -7
- data/docs/brut-js/api/AjaxSubmit.html +2 -2
- data/docs/brut-js/api/AjaxSubmit.js.html +2 -2
- data/docs/brut-js/api/Autosubmit.html +2 -2
- data/docs/brut-js/api/Autosubmit.js.html +2 -2
- data/docs/brut-js/api/BaseCustomElement.html +2 -2
- data/docs/brut-js/api/BaseCustomElement.js.html +2 -2
- data/docs/brut-js/api/BrutCustomElements.html +3 -3
- data/docs/brut-js/api/BufferedLogger.html +2 -2
- data/docs/brut-js/api/ConfirmSubmit.html +2 -2
- data/docs/brut-js/api/ConfirmSubmit.js.html +2 -2
- data/docs/brut-js/api/ConfirmationDialog.html +2 -2
- data/docs/brut-js/api/ConfirmationDialog.js.html +2 -2
- data/docs/brut-js/api/ConstraintViolationMessage.html +2 -2
- data/docs/brut-js/api/ConstraintViolationMessage.js.html +2 -2
- data/docs/brut-js/api/ConstraintViolationMessages.html +2 -2
- data/docs/brut-js/api/ConstraintViolationMessages.js.html +2 -2
- data/docs/brut-js/api/CopyToClipboard.html +2 -2
- data/docs/brut-js/api/CopyToClipboard.js.html +2 -2
- data/docs/brut-js/api/Form.html +2 -2
- data/docs/brut-js/api/Form.js.html +2 -2
- data/docs/brut-js/api/I18nTranslation.html +2 -2
- data/docs/brut-js/api/I18nTranslation.js.html +5 -2
- data/docs/brut-js/api/LocaleDetection.html +2 -2
- data/docs/brut-js/api/LocaleDetection.js.html +2 -2
- data/docs/brut-js/api/Logger.html +2 -2
- data/docs/brut-js/api/Logger.js.html +2 -2
- data/docs/brut-js/api/Message.html +2 -2
- data/docs/brut-js/api/Message.js.html +11 -5
- data/docs/brut-js/api/PrefixedLogger.html +2 -2
- data/docs/brut-js/api/RichString.html +9 -9
- data/docs/brut-js/api/RichString.js.html +6 -3
- data/docs/brut-js/api/Tabs.html +2 -2
- data/docs/brut-js/api/Tabs.js.html +2 -2
- data/docs/brut-js/api/Toast.html +270 -0
- data/docs/brut-js/api/Toast.js.html +153 -0
- data/docs/brut-js/api/Tracing.html +2 -2
- data/docs/brut-js/api/Tracing.js.html +2 -2
- data/docs/brut-js/api/external-CustomElementRegistry.html +3 -3
- data/docs/brut-js/api/external-Performance.html +3 -3
- data/docs/brut-js/api/external-Promise.html +3 -3
- data/docs/brut-js/api/external-ValidityState.html +3 -3
- data/docs/brut-js/api/external-Window.html +4 -4
- data/docs/brut-js/api/external-fetch.html +3 -3
- data/docs/brut-js/api/global.html +3 -3
- data/docs/brut-js/api/index.html +2 -2
- data/docs/brut-js/api/index.js.html +5 -2
- data/docs/brut-js/api/module-testing.html +2 -2
- data/docs/brut-js/api/testing.AssetMetadata.html +2 -2
- data/docs/brut-js/api/testing.AssetMetadataLoader.html +2 -2
- data/docs/brut-js/api/testing.CustomElementTest.html +2 -2
- data/docs/brut-js/api/testing.DOMCreator.html +2 -2
- data/docs/brut-js/api/testing_AssetMetadata.js.html +2 -2
- data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +2 -2
- data/docs/brut-js/api/testing_CustomElementTest.js.html +2 -2
- data/docs/brut-js/api/testing_DOMCreator.js.html +2 -2
- data/docs/brut-js/api/testing_index.js.html +2 -2
- data/docs/brut-js.html +8 -8
- data/docs/business-logic.html +7 -7
- data/docs/cli.html +7 -7
- data/docs/components.html +10 -10
- data/docs/configuration.html +7 -7
- data/docs/css.html +7 -7
- data/docs/custom-element-tests.html +7 -7
- data/docs/database-access.html +7 -7
- data/docs/database-schema.html +7 -7
- data/docs/deployment.html +7 -7
- data/docs/dev-environment.html +7 -7
- data/docs/dir-structure.html +7 -7
- data/docs/doc-conventions.html +7 -7
- data/docs/end-to-end-tests.html +7 -7
- data/docs/features.html +7 -7
- data/docs/flash-and-session.html +7 -7
- data/docs/form-constraints.html +7 -7
- data/docs/forms.html +8 -8
- data/docs/getting-started.html +9 -9
- data/docs/handlers.html +7 -7
- data/docs/hashmap.json +1 -1
- data/docs/hooks.html +7 -7
- data/docs/i18n.html +7 -7
- data/docs/index.html +6 -6
- data/docs/instrumentation.html +7 -7
- data/docs/javascript.html +7 -7
- data/docs/jobs.html +7 -7
- data/docs/keyword-injection.html +7 -7
- data/docs/layouts.html +42 -12
- data/docs/lsp.html +7 -7
- data/docs/markdown-examples.html +7 -7
- data/docs/middleware.html +7 -7
- data/docs/overview.html +7 -7
- data/docs/pages.html +7 -7
- data/docs/recipes/alternate-layouts.html +8 -8
- data/docs/recipes/authentication.html +7 -7
- data/docs/recipes/custom-flash.html +8 -8
- data/docs/recipes/form-errors.html +7 -7
- data/docs/recipes/indexed-forms.html +7 -7
- data/docs/recipes/migrations.html +7 -7
- data/docs/recipes/text-field-component.html +7 -7
- data/docs/roadmap.html +7 -7
- data/docs/routes.html +7 -7
- data/docs/security.html +7 -7
- data/docs/seed-data.html +7 -7
- data/docs/space-time-continuum.html +7 -7
- data/docs/tutorial.html +7 -7
- data/docs/tutorials/01-intro.html +7 -7
- data/docs/tutorials/02-dialog.html +7 -7
- data/docs/unit-tests.html +7 -7
- data/docs/why.html +7 -7
- data/dx/bash_customizations +3 -4
- data/dx/build.pre +15 -0
- data/lib/brut/cli/apps/heroku_container_based_deploy.rb +41 -15
- data/lib/brut/cli/apps/test.rb +2 -0
- data/lib/brut/framework/container.rb +6 -4
- data/lib/brut/framework/mcp.rb +1 -1
- data/lib/brut/version.rb +1 -1
- data/mkbrut/Gemfile.lock +2 -2
- data/mkbrut/lib/mkbrut/add_segment.rb +38 -0
- data/mkbrut/lib/mkbrut/add_segment_options.rb +22 -0
- data/mkbrut/lib/mkbrut/app.rb +7 -2
- data/mkbrut/lib/mkbrut/base.rb +1 -0
- data/mkbrut/lib/mkbrut/cli.rb +90 -8
- data/mkbrut/lib/mkbrut/ops/insert_code_in_method.rb +19 -7
- data/mkbrut/lib/mkbrut/ops/insert_into_file.rb +36 -0
- data/mkbrut/lib/mkbrut/ops/prism_parsing_op.rb +14 -2
- data/mkbrut/lib/mkbrut/ops.rb +1 -0
- data/mkbrut/lib/mkbrut/segments/bare_bones.rb +8 -0
- data/mkbrut/lib/mkbrut/segments/demo.rb +8 -0
- data/mkbrut/lib/mkbrut/segments/heroku.rb +23 -3
- data/mkbrut/lib/mkbrut/segments/sidekiq.rb +136 -1
- data/mkbrut/lib/mkbrut/segments.rb +1 -1
- data/mkbrut/lib/mkbrut/version.rb +1 -1
- data/mkbrut/lib/mkbrut.rb +2 -0
- data/mkbrut/templates/Base/.gitignore +3 -0
- data/mkbrut/templates/Base/Dockerfile.dx +18 -21
- data/mkbrut/templates/Base/Gemfile.erb +1 -1
- data/mkbrut/templates/Base/bin/run +107 -67
- data/mkbrut/templates/Base/bin/run.run +4 -0
- data/mkbrut/templates/Base/bin/setup +32 -1
- data/mkbrut/templates/Base/dx/bash_customizations +0 -4
- data/mkbrut/templates/Base/package.json.erb +1 -1
- data/mkbrut/templates/segments/Heroku/deploy/Dockerfile +15 -15
- data/mkbrut/templates/segments/Heroku/deploy/heroku_config.rb +5 -4
- data/mkbrut/templates/segments/Sidekiq/app/boot_sidekiq.rb +2 -0
- data/mkbrut/templates/segments/Sidekiq/app/config/sidekiq.yml +4 -0
- data/mkbrut/templates/segments/Sidekiq/app/src/back_end/jobs/app_job.rb +3 -0
- data/mkbrut/templates/segments/Sidekiq/app/src/back_end/jobs/example_job.rb +12 -0
- data/mkbrut/templates/segments/Sidekiq/app/src/back_end/segments/sidekiq_segment.rb +56 -0
- data/mkbrut/templates/segments/Sidekiq/bin/run.sidekiq +4 -0
- data/mkbrut/templates/segments/Sidekiq/specs/back_end/jobs/example_job.spec.rb +5 -0
- data/mkbrut/templates/segments/Sidekiq/specs/integration/sidekiq_works.spec.rb +38 -0
- metadata +131 -116
- data/docs/assets/adrs.md.BxjHi9-8.js +0 -1
- data/docs/assets/adrs.md.BxjHi9-8.lean.js +0 -1
- data/docs/assets/ai.md.Cy9GWnER.js +0 -1
- data/docs/assets/ai.md.Cy9GWnER.lean.js +0 -1
- data/docs/assets/assets.md.7C3HWkga.lean.js +0 -1
- data/docs/assets/brut-js.md.B4GYxQVw.lean.js +0 -1
- data/docs/assets/business-logic.md.BY4hGy0m.js +0 -1
- data/docs/assets/business-logic.md.BY4hGy0m.lean.js +0 -1
- data/docs/assets/chunks/@localSearchIndexroot.BWVzhs5N.js +0 -1
- data/docs/assets/chunks/VPLocalSearchBox.DCJk5nAW.js +0 -8
- data/docs/assets/chunks/framework.1L-BeKqY.js +0 -18
- data/docs/assets/cli.md.CjsktgFz.lean.js +0 -1
- data/docs/assets/components.md.rMhQ0WdZ.lean.js +0 -1
- data/docs/assets/configuration.md.BK42Yjp_.lean.js +0 -1
- data/docs/assets/css.md.CltvJqAa.lean.js +0 -1
- data/docs/assets/custom-element-tests.md.B_rbta32.lean.js +0 -1
- data/docs/assets/database-access.md.gnluu54N.lean.js +0 -1
- data/docs/assets/database-schema.md.LpmBPVEU.lean.js +0 -1
- data/docs/assets/deployment.md.BLseERGV.lean.js +0 -1
- data/docs/assets/dir-structure.md.CWir1pic.lean.js +0 -1
- data/docs/assets/doc-conventions.md.DOkAuXlt.js +0 -1
- data/docs/assets/doc-conventions.md.DOkAuXlt.lean.js +0 -1
- data/docs/assets/end-to-end-tests.md.DzqRpZ43.lean.js +0 -1
- data/docs/assets/features.md.DPFXsy0z.lean.js +0 -1
- data/docs/assets/flash-and-session.md.nPvUpnUx.lean.js +0 -1
- data/docs/assets/form-constraints.md.KTv5cdR4.lean.js +0 -1
- data/docs/assets/forms.md.v9qIbmUM.lean.js +0 -1
- data/docs/assets/getting-started.md.DTOl4c2g.lean.js +0 -1
- data/docs/assets/handlers.md.h84MMB1R.lean.js +0 -1
- data/docs/assets/hooks.md.Jmb5VOLA.lean.js +0 -1
- data/docs/assets/i18n.md.BAm9t9JJ.lean.js +0 -1
- data/docs/assets/instrumentation.md._lNSriEZ.lean.js +0 -1
- data/docs/assets/javascript.md.DzrMxUmI.lean.js +0 -1
- data/docs/assets/jobs.md.S-2amAYp.js +0 -1
- data/docs/assets/jobs.md.S-2amAYp.lean.js +0 -1
- data/docs/assets/keyword-injection.md.95Zgh2eN.lean.js +0 -1
- data/docs/assets/layouts.md.CVGl9xIO.js +0 -38
- data/docs/assets/layouts.md.CVGl9xIO.lean.js +0 -1
- data/docs/assets/lsp.md.Dn1rIiW0.js +0 -1
- data/docs/assets/lsp.md.Dn1rIiW0.lean.js +0 -1
- data/docs/assets/markdown-examples.md.CCFEQO44.lean.js +0 -1
- data/docs/assets/middleware.md.Czz_UlJN.lean.js +0 -1
- data/docs/assets/overview.md.DlKiRRG_.js +0 -1
- data/docs/assets/overview.md.DlKiRRG_.lean.js +0 -1
- data/docs/assets/pages.md.B7Hc-i6H.lean.js +0 -1
- data/docs/assets/recipes_alternate-layouts.md.BwEytl59.lean.js +0 -1
- data/docs/assets/recipes_authentication.md.nwO6F7Ou.lean.js +0 -1
- data/docs/assets/recipes_blank-layouts.md.fyAUJyJR.js +0 -15
- data/docs/assets/recipes_blank-layouts.md.fyAUJyJR.lean.js +0 -1
- data/docs/assets/recipes_custom-flash.md.CrQbI5eH.lean.js +0 -1
- data/docs/assets/recipes_form-errors.md.Bv5RCKqH.lean.js +0 -1
- data/docs/assets/recipes_indexed-forms.md.CstYyOSo.lean.js +0 -1
- data/docs/assets/recipes_migrations.md.CTcnWDJF.lean.js +0 -1
- data/docs/assets/recipes_text-field-component.md.H4wLAK0Z.lean.js +0 -1
- data/docs/assets/roadmap.md.C6PRi0DX.js +0 -1
- data/docs/assets/roadmap.md.C6PRi0DX.lean.js +0 -1
- data/docs/assets/routes.md.BD6y2i-f.lean.js +0 -1
- data/docs/assets/security.md.C0G_AZR-.js +0 -1
- data/docs/assets/security.md.C0G_AZR-.lean.js +0 -1
- data/docs/assets/seed-data.md.BvFZlqIk.lean.js +0 -1
- data/docs/assets/space-time-continuum.md.xl44xDos.js +0 -1
- data/docs/assets/space-time-continuum.md.xl44xDos.lean.js +0 -1
- data/docs/assets/tutorial.md.BM40jnoq.lean.js +0 -1
- data/docs/assets/unit-tests.md.DUGrnLj5.lean.js +0 -1
- data/docs/assets/why.md.C-hk5xgJ.js +0 -1
- data/docs/assets/why.md.C-hk5xgJ.lean.js +0 -1
- data/docs/recipes/blank-layouts.html +0 -43
@@ -1,86 +1,126 @@
|
|
1
|
-
#!/bin/
|
1
|
+
#!/usr/bin/env bash
|
2
2
|
|
3
3
|
set -e
|
4
|
-
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
5
|
-
|
6
|
-
usage() {
|
7
|
-
echo "Usage: $0"
|
8
|
-
echo
|
9
|
-
echo " Run the app in the given RACK_ENV."
|
10
|
-
echo " You likely want to use bin/dev instead of this command."
|
11
|
-
echo
|
12
|
-
echo "ENVIRONMENT VARIABLES"
|
13
|
-
echo
|
14
|
-
echo " PORT - The port to run the app on. Default is 6502"
|
15
|
-
echo " RACK_ENV - The Rack environment to use. Default is development"
|
16
|
-
echo
|
17
|
-
}
|
18
|
-
|
19
|
-
for arg in "$@"; do
|
20
|
-
if [ "${arg}" = "-h" ] || [ "${arg}" = "--help" ] || [ "${arg}" = "help" ]; then
|
21
|
-
usage
|
22
|
-
exit 0
|
23
|
-
fi
|
24
|
-
done
|
25
4
|
|
5
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
26
6
|
PORT="${PORT:-6502}"
|
27
7
|
RACK_ENV="${RACK_ENV:-development}"
|
28
8
|
|
29
9
|
export PORT
|
30
10
|
export RACK_ENV
|
31
11
|
|
32
|
-
|
12
|
+
declare -A CMD_MAP
|
13
|
+
declare -A PIDFILE_MAP
|
14
|
+
declare -A CREATES_PIDFILE_MAP
|
33
15
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
pid=$(cat tmp/pidfile)
|
41
|
-
|
42
|
-
# First, try to gracefully stop the server with kill
|
43
|
-
if ps -p "${pid}" > /dev/null; then
|
44
|
-
echo "[ $0 ] Attempting to kill PID '${pid}'"
|
45
|
-
kill "${pid}"
|
46
|
-
else
|
47
|
-
echo "[ $0 ] PID '${pid}' no longer running"
|
16
|
+
kill_previous() {
|
17
|
+
local pidfile=$1
|
18
|
+
|
19
|
+
if [[ -z "$pidfile" ]]; then
|
20
|
+
echo "[ $0 ] Error: no pidfile path given"
|
21
|
+
return 0
|
48
22
|
fi
|
49
23
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
24
|
+
if [ -f "${pidfile}" ]; then
|
25
|
+
echo "[ $0 ] pidfile found"
|
26
|
+
pid=$(cat "${pidfile}")
|
27
|
+
|
28
|
+
if [[ -z "$pid" || ! "$pid" =~ ^[0-9]+$ ]]; then
|
29
|
+
echo "[ $0 ] Invalid or empty PID in $pidfile: '$pid'; removing"
|
30
|
+
rm -f "$pidfile"
|
31
|
+
return 0
|
32
|
+
fi
|
33
|
+
|
34
|
+
if ps -p "${pid}" > /dev/null; then
|
35
|
+
echo "[ $0 ] Attempting to kill PID '${pid}'"
|
36
|
+
kill "${pid}"
|
37
|
+
else
|
38
|
+
echo "[ $0 ] PID '${pid}' no longer running"
|
39
|
+
fi
|
40
|
+
if timeout 5 tail --pid="${pid}" -f /dev/null; then
|
41
|
+
echo "[ $0 ] PID '${pid}' stopped. Restarting server"
|
60
42
|
else
|
61
|
-
echo "[ $0 ] PID '${pid}'
|
62
|
-
|
43
|
+
echo "[ $0 ] PID '${pid}' has not stopped. Trying kill -9"
|
44
|
+
kill -9 "${pid}"
|
45
|
+
if timeout 1 tail --pid="${pid}" -f /dev/null; then
|
46
|
+
echo "[ $0 ] PID '${pid}' killed. Restarting server"
|
47
|
+
else
|
48
|
+
echo "[ $0 ] PID '${pid}' still running. Something seriously wrong"
|
49
|
+
fi
|
63
50
|
exit 1
|
64
51
|
fi
|
52
|
+
|
53
|
+
else
|
54
|
+
echo "[ $0 ] No pidfile-Starting up"
|
65
55
|
fi
|
56
|
+
}
|
66
57
|
|
67
|
-
|
68
|
-
|
58
|
+
dotenv_run() {
|
59
|
+
local env_files="${SCRIPT_DIR}/../.env.${RACK_ENV}.local,${SCRIPT_DIR}/../.env.${RACK_ENV}"
|
60
|
+
dotenv -f "$env_files" --ignore -- "$@"
|
61
|
+
}
|
62
|
+
|
63
|
+
|
64
|
+
for f in "$SCRIPT_DIR"/run.*; do
|
65
|
+
if [[ -f "$f" ]]; then
|
66
|
+
echo "[ $0 ] Sourcing $f"
|
67
|
+
. "$f"
|
68
|
+
fi
|
69
|
+
done
|
70
|
+
|
71
|
+
case $# in
|
72
|
+
0) name="run" ;;
|
73
|
+
1) name="$1" ;;
|
74
|
+
*) echo "Error: too many arguments ($#)." >&2; usage; exit 2 ;;
|
75
|
+
esac
|
76
|
+
|
77
|
+
if [[ ! -v CMD_MAP[$name] ]]; then
|
78
|
+
echo "[ $0 ] Error: unknown service '$name'." >&2
|
79
|
+
echo -n "[ $0 ] Known services: " >&2
|
80
|
+
printf "%s " "${!CMD_MAP[@]}" >&2
|
81
|
+
echo >&2
|
82
|
+
exit 1
|
69
83
|
fi
|
70
84
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
cmd="${CMD_MAP[$name]}"
|
86
|
+
creates_pidfile="${CREATES_PIDFILE_MAP[$name]:-false}"
|
87
|
+
pidfile="${PIDFILE_MAP[$name]:-}"
|
88
|
+
|
89
|
+
echo "[ $0 ]: Command for $name:"
|
90
|
+
echo
|
91
|
+
echo " $cmd"
|
92
|
+
echo
|
93
|
+
|
94
|
+
kill_previous "$pidfile"
|
95
|
+
|
96
|
+
if [[ "$creates_pidfile" == true ]]; then
|
97
|
+
echo "[ $0 ] Running '$cmd', which creates its own pidfile"
|
98
|
+
eval "dotenv_run $cmd"
|
99
|
+
else
|
100
|
+
# Command wont' create a pidfile, so we will
|
101
|
+
if [[ -z "${pidfile:-}" ]]; then
|
102
|
+
echo "Error: no pidfile path configured for '$name' but creates_pidfile=false." >&2
|
103
|
+
exit 1
|
104
|
+
fi
|
105
|
+
echo "[ $0 ] Running '$cmd', which will not create a pidfile"
|
106
|
+
echo "[ $0 ] We will do that and save it to ${pidfile}"
|
107
|
+
|
108
|
+
echo "[ $0 ] Ensuring $(dirname "$pidfile") exists"
|
109
|
+
mkdir -p "$(dirname "$pidfile")"
|
110
|
+
|
111
|
+
eval "dotenv_run $cmd &"
|
112
|
+
child_pid=$!
|
113
|
+
|
114
|
+
set +e
|
115
|
+
echo "$child_pid" > "$pidfile"
|
116
|
+
|
117
|
+
trap 'kill -TERM "$child_pid" 2>/dev/null' TERM INT
|
118
|
+
|
119
|
+
wait "$child_pid"
|
120
|
+
|
121
|
+
echo "[ $0 ] TERM or INT received, removing ${pidfile} and exiting"
|
122
|
+
|
123
|
+
status=$?
|
124
|
+
rm -f "$pidfile"
|
125
|
+
exit "$status"
|
126
|
+
fi
|
@@ -1,10 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
3
|
require "fileutils"
|
5
4
|
require "open3"
|
6
5
|
require "optparse"
|
7
6
|
require "pathname"
|
7
|
+
require "bundler"
|
8
|
+
require "json"
|
8
9
|
|
9
10
|
# This is intended to run inside the Workspace (i.e. Docker container) to
|
10
11
|
# set up the Foundation, thus enabling development. This script should:
|
@@ -21,6 +22,7 @@ require "pathname"
|
|
21
22
|
# Take care to only add code and not change what is here.
|
22
23
|
|
23
24
|
def setup(update_gems:,update_node:)
|
25
|
+
ensure_versions_are_consistent!
|
24
26
|
if update_gems
|
25
27
|
log "Updating gems"
|
26
28
|
system! "bundle update"
|
@@ -82,6 +84,35 @@ def setup(update_gems:,update_node:)
|
|
82
84
|
help
|
83
85
|
end
|
84
86
|
|
87
|
+
def ensure_versions_are_consistent!
|
88
|
+
gemfile = Bundler::Definition.build(ROOT_DIR / "Gemfile", ROOT_DIR / "Gemfile.lock", nil)
|
89
|
+
package_json = JSON.parse(File.read(ROOT_DIR / "package.json"))
|
90
|
+
|
91
|
+
playwright_version = nil
|
92
|
+
gemfile.dependencies.each do |dep|
|
93
|
+
if dep.name == "playwright-ruby-client"
|
94
|
+
if !dep.specific?
|
95
|
+
puts "You must specify an exact/specific version of 'playwright-ruby-client' in your Gemfile"
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
playwright_version = dep.requirement.requirements.first[1]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if playwright_version
|
103
|
+
playwright_version_in_package_json = package_json.dig("devDependencies","playwright")
|
104
|
+
if !playwright_version_in_package_json
|
105
|
+
puts "You must have 'playwright' in the devDependencies section of your package.json"
|
106
|
+
exit 1
|
107
|
+
end
|
108
|
+
if playwright_version != playwright_version_in_package_json
|
109
|
+
puts "The version of 'playwright' in package.json (#{playwright_version_in_package_json}) does not match the version of 'playwright-ruby-client' in the Gemfile (#{playwright_version})"
|
110
|
+
puts "They must be exactly the same, or your end-to-end tests may behave strangely"
|
111
|
+
exit 1
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
85
116
|
def setup_dot_env_local
|
86
117
|
|
87
118
|
dot_env = ROOT_DIR / ".env.development"
|
@@ -6,7 +6,3 @@ if [ ! -n "$PROJECT_ROOT" ]; then
|
|
6
6
|
fi
|
7
7
|
export GEM_HOME=${PROJECT_ROOT}/local-gems/gem-home
|
8
8
|
export PATH=${PATH}:${GEM_HOME}/bin
|
9
|
-
# This sets up the Node version so we don't have to do it before every. single.
|
10
|
-
# shell. invocation.
|
11
|
-
. ~/.nvm/nvm.sh
|
12
|
-
nvm use default
|
@@ -37,7 +37,8 @@ WORKDIR /brut-app
|
|
37
37
|
# - lsb-release is used to generically access information for this OS's version
|
38
38
|
# - wget allows us to copy/paste commands from vendors about how to install
|
39
39
|
# software even though it does the same thing as curl
|
40
|
-
RUN apt
|
40
|
+
RUN --mount=type=cache,target=/var/cache/apt \
|
41
|
+
apt-get update --quiet --yes && \
|
41
42
|
apt-get install --no-install-recommends --quiet --yes \
|
42
43
|
ca-certificates \
|
43
44
|
curl \
|
@@ -62,8 +63,7 @@ RUN /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \
|
|
62
63
|
ENV RACK_ENV="production" \
|
63
64
|
BUNDLE_DEPLOYMENT="1" \
|
64
65
|
BUNDLE_PATH="/usr/local/bundle" \
|
65
|
-
BUNDLE_WITHOUT="development"
|
66
|
-
APP_GIT_SHA1="${app_git_sha1}"
|
66
|
+
BUNDLE_WITHOUT="development"
|
67
67
|
|
68
68
|
# This makes a new image that we'll throw away after building
|
69
69
|
# needed artifacts.
|
@@ -74,30 +74,29 @@ FROM base AS build
|
|
74
74
|
# - libpq-dev is needed by postgres
|
75
75
|
# - pkg-config is, I guess, not considered "essential" (as in build-essential),
|
76
76
|
# but still needed to install downstream stuff
|
77
|
-
RUN apt
|
77
|
+
RUN --mount=type=cache,target=/var/cache/apt \
|
78
|
+
apt-get update --quiet --yes && \
|
78
79
|
apt-get install --no-install-recommends --quiet --yes \
|
79
80
|
build-essential \
|
80
81
|
git \
|
81
82
|
libpq-dev \
|
82
83
|
pkg-config
|
83
84
|
|
84
|
-
# Install NodeJS
|
85
|
-
|
86
|
-
\. "$HOME/.nvm/nvm.sh" && \
|
87
|
-
nvm install 22 && \
|
88
|
-
node -v && nvm current && npm -v
|
85
|
+
# Install NodeJS from their Docker image
|
86
|
+
COPY --from=node:22-slim /usr/local /usr/local
|
89
87
|
|
90
|
-
|
91
|
-
COPY . .
|
88
|
+
COPY Gemfile Gemfile.lock .
|
92
89
|
|
93
90
|
# Install RubyGems from app's Gemfile
|
94
|
-
RUN
|
91
|
+
RUN --mount=type=cache,target=${BUNDLE_PATH}/cache \
|
92
|
+
bundle install --verbose && \
|
95
93
|
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git
|
96
94
|
|
95
|
+
COPY package.json package-lock.json ./
|
97
96
|
# Install Node Modules from package.json
|
98
|
-
RUN
|
99
|
-
|
100
|
-
|
97
|
+
RUN npm clean-install --no-audit --no-fund --verbose
|
98
|
+
|
99
|
+
COPY . .
|
101
100
|
|
102
101
|
# Build all assets
|
103
102
|
RUN \. "$HOME/.nvm/nvm.sh" && \
|
@@ -118,6 +117,7 @@ RUN groupadd --system --gid 1000 brut && \
|
|
118
117
|
chown -R brut:brut logs tmp
|
119
118
|
USER 1000:1000
|
120
119
|
|
120
|
+
ENV APP_GIT_SHA1="${app_git_sha1}"
|
121
121
|
# This is used to execute other commands. When the app is run in production,
|
122
122
|
# this script is used to run it.
|
123
123
|
ENTRYPOINT ["/brut-app/deploy/docker-entrypoint"]
|
@@ -8,8 +8,8 @@ class HerokuConfig
|
|
8
8
|
# The format of this Hash is:
|
9
9
|
#
|
10
10
|
# {
|
11
|
-
#
|
12
|
-
# cmd:
|
11
|
+
# *image name* => {
|
12
|
+
# cmd: *command line for Dockerfile RUN directive*,
|
13
13
|
# }
|
14
14
|
# }
|
15
15
|
#
|
@@ -21,6 +21,7 @@ class HerokuConfig
|
|
21
21
|
# cmd: "bin/run-sidekiq",
|
22
22
|
# }
|
23
23
|
# }
|
24
|
-
|
24
|
+
#
|
25
|
+
def self.additional_images
|
26
|
+
end
|
25
27
|
end
|
26
|
-
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# This is entirely to allow the integration test to run
|
2
|
+
# that verifies you have Sidekqi working and the segment was
|
3
|
+
# installed correctly. Once you have created a real job for
|
4
|
+
# your app and done whatever testing you need, please delete
|
5
|
+
# this job and the integration test.
|
6
|
+
class ExampleJob < AppJob
|
7
|
+
def perform(path_to_file, contents)
|
8
|
+
File.open(path_to_file, "w") do |f|
|
9
|
+
f.puts(contents)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "sidekiq"
|
2
|
+
# Encapsulates all Sidekiq configuraiton beyond what can be done in
|
3
|
+
# app/config/sidekiq.yml. You can edit this as needed.
|
4
|
+
class SidekiqSegment
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
Brut.container.store(
|
8
|
+
"flush_spans_in_sidekiq?",
|
9
|
+
"Boolean",
|
10
|
+
"True if sidekiq jobs should flush all OTel spans after the job completes"
|
11
|
+
) do |project_env|
|
12
|
+
if ENV["FLUSH_SPANS_IN_SIDEKIQ"] == "true"
|
13
|
+
true
|
14
|
+
elsif ENV["FLUSH_SPANS_IN_SIDEKIQ"] == "false"
|
15
|
+
false
|
16
|
+
else
|
17
|
+
project_env.development?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def boot!
|
23
|
+
Sidekiq.configure_server do |config|
|
24
|
+
config.redis = {
|
25
|
+
# Per https://devcenter.heroku.com/articles/connecting-heroku-redis#connecting-in-ruby
|
26
|
+
ssl_params: {
|
27
|
+
verify_mode: OpenSSL::SSL::VERIFY_NONE,
|
28
|
+
},
|
29
|
+
}
|
30
|
+
config.logger = SemanticLogger["Sidekiq:server"]
|
31
|
+
if Brut.container.flush_spans_in_sidekiq?
|
32
|
+
SemanticLogger[self.class].info("Sidekiq jobs will flush spans")
|
33
|
+
config.server_middleware do |chain|
|
34
|
+
if defined? OpenTelemetry::Instrumentation::Sidekiq::Middlewares::Server::TracerMiddleware
|
35
|
+
chain.insert_before OpenTelemetry::Instrumentation::Sidekiq::Middlewares::Server::TracerMiddleware,
|
36
|
+
Brut::BackEnd::Sidekiq::Middlewares::Server::FlushSpans
|
37
|
+
else
|
38
|
+
SemanticLogger["Sidekiq:server"].warn("OpenTelemetry::Instrumentation::Sidekiq::Middlewares::Server::TracerMiddleware not defined")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
else
|
42
|
+
SemanticLogger[self.class].info("Sidekiq jobs will not flush spans")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Sidekiq.configure_client do |config|
|
47
|
+
config.redis = {
|
48
|
+
# Per https://devcenter.heroku.com/articles/connecting-heroku-redis#connecting-in-ruby
|
49
|
+
ssl_params: {
|
50
|
+
verify_mode: OpenSSL::SSL::VERIFY_NONE,
|
51
|
+
},
|
52
|
+
}
|
53
|
+
config.logger = SemanticLogger["Sidekiq:client"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "timeout"
|
3
|
+
|
4
|
+
# This test will ensure that Sidekiq segment was installed
|
5
|
+
# correctly and your app can use Sidekiq. Once you have
|
6
|
+
# created a real job for your app, delete ExampleJob and this test.
|
7
|
+
RSpec.describe "Sidekiq is working", e2e: true do
|
8
|
+
it "processes jobs using the real Sidekiq server" do
|
9
|
+
# ExampleJob will write contents to a file. This
|
10
|
+
# test will delete that fail, queue the job, then
|
11
|
+
# wait up to 5 seconds for the job to run and create
|
12
|
+
# the file with the contents. This should be more than
|
13
|
+
# enough time.
|
14
|
+
file = Brut.container.tmp_dir / "sidekiq_test.txt"
|
15
|
+
if file.exist?
|
16
|
+
file.delete
|
17
|
+
end
|
18
|
+
|
19
|
+
# If the file still exists at this point, the test
|
20
|
+
# will pass even if Sidekiq is not working.
|
21
|
+
confidence_check { expect(file.exist?).to eq(false) }
|
22
|
+
|
23
|
+
ExampleJob.perform_async(file.to_s, "test content for file")
|
24
|
+
queue_name = ExampleJob.sidekiq_options["queue"]
|
25
|
+
expect {
|
26
|
+
Timeout.timeout(5) do
|
27
|
+
loop do
|
28
|
+
if file.exist?
|
29
|
+
break
|
30
|
+
end
|
31
|
+
sleep 0.1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
}.not_to raise_error
|
35
|
+
content = File.read(file)
|
36
|
+
expect(content).to eq("test content for file\n")
|
37
|
+
end
|
38
|
+
end
|