brut 0.4.0 → 0.8.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/.gitignore +4 -0
- data/CHANGELOG.md +36 -1
- data/Dockerfile.dx +19 -0
- data/Gemfile.lock +1 -1
- data/README.md +19 -0
- data/assets/MetroIcon.graffle +0 -0
- data/assets/YouTubeThumb.pxd +0 -0
- data/bin/build +86 -0
- data/bin/ci +36 -0
- data/bin/docs +39 -9
- data/bin/publish +61 -0
- data/bin/setup +6 -0
- data/brut-css/bin/build +19 -0
- data/brut-css/bin/ci +19 -0
- data/brut-css/bin/docs +19 -0
- data/brut-css/bin/publish +21 -0
- data/brut-css/bin/setup +1 -0
- data/brut-css/package-lock.json +2 -2
- data/brut-css/package.json +1 -1
- data/brut-css/src/css/flex.css +1 -1
- data/brut-css/src/docs/includes/body-and-header.html.ejs +1 -1
- data/brut-js/bin/build +15 -6
- data/brut-js/bin/docs +25 -0
- data/brut-js/bin/publish +21 -0
- data/brut-js/bin/setup +1 -0
- data/brut-js/dx +1 -0
- data/brut-js/package-lock.json +2 -2
- data/brut-js/package.json +1 -1
- data/brut-js/specs/AjaxSubmit.spec.js +100 -7
- data/brut-js/src/AjaxSubmit.js +76 -40
- data/brut.gemspec +2 -2
- data/brutrb.com/adrs.md +1 -0
- data/brutrb.com/bin/setup +1 -0
- data/brutrb.com/getting-started.md +3 -0
- data/brutrb.com/overview.md +6 -0
- data/brutrb.com/tutorial.md +7 -3
- data/docs/404.html +2 -2
- data/docs/adrs.html +5 -5
- data/docs/ai.html +3 -3
- 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 +2 -2
- 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 +86 -2
- data/docs/api/Brut/FrontEnd/Component.html +78 -9
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Input.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/TimeTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Traceparent.html +3 -3
- data/docs/api/Brut/FrontEnd/Components.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/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 +3 -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 +31 -23
- data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +3 -3
- 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 +13 -11
- 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 +92 -76
- data/docs/api/top-level-namespace.html +1 -1
- data/docs/assets/{adrs.md.JRxZ5uYE.js → adrs.md.BxjHi9-8.js} +1 -1
- data/docs/assets/adrs.md.BxjHi9-8.lean.js +1 -0
- data/docs/assets/{app.AkS4fHzI.js → app.DyQLb4Ot.js} +1 -1
- data/docs/assets/chunks/@localSearchIndexroot.CmtZyrFA.js +1 -0
- data/docs/assets/chunks/{VPLocalSearchBox.By6un1FD.js → VPLocalSearchBox.T1iA-eJx.js} +1 -1
- data/docs/assets/chunks/{theme.DwiUPdci.js → theme.ChwsbWjK.js} +2 -2
- data/docs/assets/{components.md.BfeWD9sX.js → components.md.DHh-NwKs.js} +3 -3
- data/docs/assets/{configuration.md.DoSBNc0H.js → configuration.md.D8Wz3oJU.js} +1 -1
- data/docs/assets/{forms.md.DFveP5g_.js → forms.md.BRE85eju.js} +1 -1
- data/docs/assets/{getting-started.md.DZWjCVC0.js → getting-started.md.2ioiTe-B.js} +6 -3
- data/docs/assets/{getting-started.md.DZWjCVC0.lean.js → getting-started.md.2ioiTe-B.lean.js} +1 -1
- data/docs/assets/overview.md.DlKiRRG_.js +1 -0
- data/docs/assets/overview.md.DlKiRRG_.lean.js +1 -0
- data/docs/assets/tutorial.md.BIb7XT6j.js +1 -0
- data/docs/assets/tutorial.md.BIb7XT6j.lean.js +1 -0
- data/docs/assets.html +3 -3
- data/docs/brut-css/brut.max.css +1 -1
- data/docs/brut-css/classes/appearances.html +1 -1
- data/docs/brut-css/classes/background-colors.html +1 -1
- data/docs/brut-css/classes/border-colors.html +1 -1
- data/docs/brut-css/classes/borders.html +1 -1
- data/docs/brut-css/classes/dimensions.html +1 -1
- data/docs/brut-css/classes/flex.html +3 -3
- data/docs/brut-css/classes/foreground-colors.html +1 -1
- data/docs/brut-css/classes/junk-drawer.html +1 -1
- data/docs/brut-css/classes/layout.html +1 -1
- data/docs/brut-css/classes/lists.html +1 -1
- data/docs/brut-css/classes/positioning.html +1 -1
- data/docs/brut-css/classes/spacings.html +1 -1
- data/docs/brut-css/classes/typography.html +1 -1
- data/docs/brut-css/customization/advanced-configuration.html +1 -1
- data/docs/brut-css/customization/breakpoints.html +1 -1
- data/docs/brut-css/customization/design-system.html +1 -1
- data/docs/brut-css/customization/pseudo-classes.html +1 -1
- data/docs/brut-css/getting-started/core-concepts.html +1 -1
- data/docs/brut-css/getting-started/installation.html +1 -1
- data/docs/brut-css/getting-started/overview.html +1 -1
- data/docs/brut-css/getting-started/simple-example.html +1 -1
- data/docs/brut-css/index.html +1 -1
- data/docs/brut-css/properties/colors.html +1 -1
- data/docs/brut-css/properties/spacings.html +1 -1
- data/docs/brut-css/properties/typography.html +1 -1
- data/docs/brut-js/api/AjaxSubmit.html +56 -7
- data/docs/brut-js/api/AjaxSubmit.js.html +77 -41
- 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 +3 -3
- data/docs/business-logic.html +3 -3
- data/docs/cli.html +3 -3
- data/docs/components.html +7 -7
- data/docs/configuration.html +5 -5
- data/docs/css.html +3 -3
- data/docs/custom-element-tests.html +3 -3
- data/docs/database-access.html +3 -3
- data/docs/database-schema.html +3 -3
- data/docs/deployment.html +3 -3
- data/docs/dev-environment.html +3 -3
- data/docs/dir-structure.html +3 -3
- data/docs/doc-conventions.html +3 -3
- data/docs/end-to-end-tests.html +3 -3
- data/docs/features.html +3 -3
- data/docs/flash-and-session.html +3 -3
- data/docs/form-constraints.html +3 -3
- data/docs/forms.html +5 -5
- data/docs/getting-started.html +9 -6
- data/docs/handlers.html +3 -3
- data/docs/hashmap.json +1 -1
- data/docs/hooks.html +3 -3
- data/docs/i18n.html +3 -3
- data/docs/index.html +3 -3
- data/docs/instrumentation.html +3 -3
- data/docs/javascript.html +3 -3
- data/docs/jobs.html +3 -3
- data/docs/keyword-injection.html +3 -3
- data/docs/layouts.html +3 -3
- data/docs/lsp.html +3 -3
- data/docs/markdown-examples.html +3 -3
- data/docs/middleware.html +3 -3
- data/docs/overview.html +5 -5
- data/docs/pages.html +3 -3
- data/docs/recipes/alternate-layouts.html +3 -3
- data/docs/recipes/authentication.html +3 -3
- data/docs/recipes/blank-layouts.html +3 -3
- data/docs/recipes/custom-flash.html +3 -3
- data/docs/recipes/indexed-forms.html +3 -3
- data/docs/recipes/migrations.html +3 -3
- data/docs/recipes/text-field-component.html +3 -3
- data/docs/roadmap.html +3 -3
- data/docs/routes.html +3 -3
- data/docs/security.html +3 -3
- data/docs/seed-data.html +3 -3
- data/docs/space-time-continuum.html +3 -3
- data/docs/tutorial.html +5 -5
- data/docs/unit-tests.html +3 -3
- data/docs/why.html +3 -3
- data/lib/brut/cli/apps/scaffold.rb +1 -1
- data/lib/brut/framework/mcp.rb +1 -1
- data/lib/brut/front_end/component.rb +19 -0
- data/lib/brut/front_end/components/form_tag.rb +2 -2
- data/lib/brut/front_end/page.rb +11 -7
- data/lib/brut/sinatra_helpers.rb +1 -0
- data/lib/brut/version.rb +1 -1
- data/mkbrut/.gitignore +16 -0
- data/mkbrut/CODE_OF_CONDUCT.txt +100 -0
- data/mkbrut/Gemfile +3 -0
- data/mkbrut/Gemfile.lock +19 -0
- data/mkbrut/LICENSE.txt +370 -0
- data/mkbrut/README.md +145 -0
- data/mkbrut/Rakefile +2 -0
- data/mkbrut/bin/build +36 -0
- data/mkbrut/bin/ci +19 -0
- data/mkbrut/bin/docs +19 -0
- data/mkbrut/bin/publish +129 -0
- data/mkbrut/bin/rake +16 -0
- data/mkbrut/bin/setup +30 -0
- data/mkbrut/brut-welcome.png +0 -0
- data/mkbrut/deploy/.dockerignore +2 -0
- data/mkbrut/deploy/Dockerfile +25 -0
- data/mkbrut/exe/mkbrut +5 -0
- data/mkbrut/lib/mkbrut/app.rb +79 -0
- data/mkbrut/lib/mkbrut/app_id.rb +8 -0
- data/mkbrut/lib/mkbrut/app_name.rb +29 -0
- data/mkbrut/lib/mkbrut/app_options.rb +36 -0
- data/mkbrut/lib/mkbrut/base.rb +57 -0
- data/mkbrut/lib/mkbrut/cli.rb +107 -0
- data/mkbrut/lib/mkbrut/erb_binding_delegate.rb +20 -0
- data/mkbrut/lib/mkbrut/internet_identifier.rb +32 -0
- data/mkbrut/lib/mkbrut/invalid_identifier.rb +4 -0
- data/mkbrut/lib/mkbrut/ops/add_css_import.rb +42 -0
- data/mkbrut/lib/mkbrut/ops/add_i18n_message.rb +74 -0
- data/mkbrut/lib/mkbrut/ops/add_method.rb +48 -0
- data/mkbrut/lib/mkbrut/ops/append_to_file.rb +20 -0
- data/mkbrut/lib/mkbrut/ops/base_op.rb +21 -0
- data/mkbrut/lib/mkbrut/ops/copy_file.rb +12 -0
- data/mkbrut/lib/mkbrut/ops/insert_code_in_method.rb +58 -0
- data/mkbrut/lib/mkbrut/ops/insert_route.rb +52 -0
- data/mkbrut/lib/mkbrut/ops/mkdir.rb +13 -0
- data/mkbrut/lib/mkbrut/ops/prism_parsing_op.rb +70 -0
- data/mkbrut/lib/mkbrut/ops/render_template.rb +26 -0
- data/mkbrut/lib/mkbrut/ops/skip_file.rb +10 -0
- data/mkbrut/lib/mkbrut/ops.rb +16 -0
- data/mkbrut/lib/mkbrut/organization.rb +5 -0
- data/mkbrut/lib/mkbrut/prefix.rb +26 -0
- data/mkbrut/lib/mkbrut/prefixed_io.rb +16 -0
- data/mkbrut/lib/mkbrut/segments/bare_bones.rb +185 -0
- data/mkbrut/lib/mkbrut/segments/demo.rb +121 -0
- data/mkbrut/lib/mkbrut/segments/heroku.rb +30 -0
- data/mkbrut/lib/mkbrut/segments/sidekiq.rb +3 -0
- data/mkbrut/lib/mkbrut/segments.rb +8 -0
- data/mkbrut/lib/mkbrut/version.rb +3 -0
- data/mkbrut/lib/mkbrut/versions.rb +13 -0
- data/mkbrut/lib/mkbrut.rb +18 -0
- data/mkbrut/mkbrut.gemspec +32 -0
- data/mkbrut/templates/Base/.dockerignore +25 -0
- data/mkbrut/templates/Base/.env.development.erb +60 -0
- data/mkbrut/templates/Base/.env.test.erb +8 -0
- data/mkbrut/templates/Base/.gitignore +31 -0
- data/mkbrut/templates/Base/.projections.json +59 -0
- data/mkbrut/templates/Base/Dockerfile.dx +205 -0
- data/mkbrut/templates/Base/Gemfile.erb +53 -0
- data/mkbrut/templates/Base/Procfile.development +5 -0
- data/mkbrut/templates/Base/Procfile.test +1 -0
- data/mkbrut/templates/Base/README.md +4 -0
- data/mkbrut/templates/Base/README.md.erb +40 -0
- data/mkbrut/templates/Base/app/bootstrap.rb +61 -0
- data/mkbrut/templates/Base/app/config/i18n/en/1_defaults.rb +128 -0
- data/mkbrut/templates/Base/app/config/i18n/en/2_app.rb +24 -0
- data/mkbrut/templates/Base/app/public/static/manifest.json.erb +33 -0
- data/mkbrut/templates/Base/app/src/app.rb.erb +37 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/app_data_model.rb +5 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/db.rb +19 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/migrations/20240101130000_citext.rb +6 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/seed/seed_data.rb +9 -0
- data/mkbrut/templates/Base/app/src/front_end/components/app_component.rb +8 -0
- data/mkbrut/templates/Base/app/src/front_end/components/custom_element_registration.rb.erb +7 -0
- data/mkbrut/templates/Base/app/src/front_end/css/index.css +2 -0
- data/mkbrut/templates/Base/app/src/front_end/css/svgs.css +12 -0
- data/mkbrut/templates/Base/app/src/front_end/forms/app_form.rb +4 -0
- data/mkbrut/templates/Base/app/src/front_end/handlers/app_handler.rb +4 -0
- data/mkbrut/templates/Base/app/src/front_end/images/LogoPylon.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/LogoTransit.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-120x120.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-152x152.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-167x167.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-180x180.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/favicon.ico +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/icon.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/mkicons.sh +6 -0
- data/mkbrut/templates/Base/app/src/front_end/js/index.js +6 -0
- data/mkbrut/templates/Base/app/src/front_end/layouts/default_layout.rb.erb +73 -0
- data/mkbrut/templates/Base/app/src/front_end/pages/app_page.rb +11 -0
- data/mkbrut/templates/Base/app/src/front_end/pages/home_page.rb +62 -0
- data/mkbrut/templates/Base/app/src/front_end/support/app_session.rb +6 -0
- data/mkbrut/templates/Base/app/src/front_end/svgs/README.md +5 -0
- data/mkbrut/templates/Base/app/src/front_end/svgs/comment-button.svg +59 -0
- data/mkbrut/templates/Base/bin/README.md.erb +5 -0
- data/mkbrut/templates/Base/bin/build-assets +7 -0
- data/mkbrut/templates/Base/bin/ci +39 -0
- data/mkbrut/templates/Base/bin/console +31 -0
- data/mkbrut/templates/Base/bin/db +9 -0
- data/mkbrut/templates/Base/bin/dbconsole +51 -0
- data/mkbrut/templates/Base/bin/dev +25 -0
- data/mkbrut/templates/Base/bin/release +26 -0
- data/mkbrut/templates/Base/bin/run +86 -0
- data/mkbrut/templates/Base/bin/scaffold +9 -0
- data/mkbrut/templates/Base/bin/setup +256 -0
- data/mkbrut/templates/Base/bin/startup-message +65 -0
- data/mkbrut/templates/Base/bin/test +9 -0
- data/mkbrut/templates/Base/bin/test-server +29 -0
- data/mkbrut/templates/Base/bin/watch-and-build-assets +37 -0
- data/mkbrut/templates/Base/config.ru +16 -0
- data/mkbrut/templates/Base/docker-compose.dx.yml +92 -0
- data/mkbrut/templates/Base/dx/README.md +28 -0
- data/mkbrut/templates/Base/dx/bash_customizations +12 -0
- data/mkbrut/templates/Base/dx/bash_customizations.local +8 -0
- data/mkbrut/templates/Base/dx/build +107 -0
- data/mkbrut/templates/Base/dx/docker-compose.env.erb +25 -0
- data/mkbrut/templates/Base/dx/dx.sh.lib +137 -0
- data/mkbrut/templates/Base/dx/exec +68 -0
- data/mkbrut/templates/Base/dx/prune +19 -0
- data/mkbrut/templates/Base/dx/show-help-in-app-container-then-wait.sh +38 -0
- data/mkbrut/templates/Base/dx/start +30 -0
- data/mkbrut/templates/Base/dx/stop +23 -0
- data/mkbrut/templates/Base/package.json.erb +37 -0
- data/mkbrut/templates/Base/puma.config.rb +53 -0
- data/mkbrut/templates/Base/specs/e2e/home_page.spec.rb.erb +23 -0
- data/mkbrut/templates/Base/specs/front_end/js/SpecHelper.js +24 -0
- data/mkbrut/templates/Base/specs/front_end/pages/home_page.spec.rb +22 -0
- data/mkbrut/templates/Base/specs/lint_factories.spec.rb +7 -0
- data/mkbrut/templates/Base/specs/spec_helper.rb +78 -0
- data/mkbrut/templates/Base/specs/support.rb +2 -0
- data/mkbrut/templates/segments/BareBones/app/src/front_end/handlers/trigger_exception_handler.rb +24 -0
- data/mkbrut/templates/segments/BareBones/app/src/front_end/js/Example.js.erb +49 -0
- data/mkbrut/templates/segments/BareBones/specs/front_end/handlers/trigger_exception_handler.spec.rb +41 -0
- data/mkbrut/templates/segments/BareBones/specs/front_end/js/Example.spec.js.erb +38 -0
- data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/db/guestbook_message.rb +3 -0
- data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/migrations/20250628194124_guestbook.rb +14 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/components/flash_component.rb +36 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/css/constraint-violations.css +18 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/css/fonts.css +19 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/fonts/monaspace-xenon.ttf +0 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/forms/guestbook_message_form.rb +4 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/handlers/guestbook_message_handler.rb +64 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page/message_component.rb +41 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page.rb +43 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/pages/new_guestbook_message_page.rb +64 -0
- data/mkbrut/templates/segments/Demo/specs/back_end/data_models/db/guestbook_message.spec.rb +5 -0
- data/mkbrut/templates/segments/Demo/specs/e2e/guest_message.spec.rb +54 -0
- data/mkbrut/templates/segments/Demo/specs/factories/db/guestbook_message.factory.rb +7 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/components/flash_component.spec.rb +5 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/handlers/guestbook_message_handler.spec.rb +122 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page/message_component.spec.rb +5 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page.spec.rb +52 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/pages/new_guestbook_message_page.spec.rb +5 -0
- data/mkbrut/templates/segments/Heroku/bin/deploy +11 -0
- data/mkbrut/templates/segments/Heroku/deploy/Dockerfile +125 -0
- data/mkbrut/templates/segments/Heroku/deploy/docker-entrypoint +15 -0
- data/mkbrut/templates/segments/Heroku/deploy/heroku_config.rb +26 -0
- metadata +188 -24
- data/brut-js/CHANGELOG.md +0 -5
- data/docs/assets/adrs.md.JRxZ5uYE.lean.js +0 -1
- data/docs/assets/chunks/@localSearchIndexroot.C9FqcQxD.js +0 -1
- data/docs/assets/overview.md.iMnwLO4x.js +0 -1
- data/docs/assets/overview.md.iMnwLO4x.lean.js +0 -1
- data/docs/assets/tutorial.md.BYXj4cOu.js +0 -1
- data/docs/assets/tutorial.md.BYXj4cOu.lean.js +0 -1
- /data/docs/assets/{components.md.BfeWD9sX.lean.js → components.md.DHh-NwKs.lean.js} +0 -0
- /data/docs/assets/{configuration.md.DoSBNc0H.lean.js → configuration.md.D8Wz3oJU.lean.js} +0 -0
- /data/docs/assets/{forms.md.DFveP5g_.lean.js → forms.md.BRE85eju.lean.js} +0 -0
data/mkbrut/bin/build
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "pathname"
|
5
|
+
require "fileutils"
|
6
|
+
require_relative "../../bin/bin_kit"
|
7
|
+
|
8
|
+
def main
|
9
|
+
|
10
|
+
log "Building mkbrut gem"
|
11
|
+
system!("bin/rake build")
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
OptionParser.new do |opts|
|
16
|
+
opts.banner = "Usage: build [options]\n\n Builds deployable artifacts\n\nOPTIONS"
|
17
|
+
|
18
|
+
opts.on("-h", "--help", "Display this help message") do
|
19
|
+
puts opts
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end.parse!
|
23
|
+
|
24
|
+
def require_clean_repo!
|
25
|
+
out, err = capture!("git status --porcelain")
|
26
|
+
if out.to_s.strip != ""
|
27
|
+
log out
|
28
|
+
log err
|
29
|
+
log "Your git repository is not clean. Please commit or stash your changes before running this script."
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require_clean_repo!
|
35
|
+
main
|
36
|
+
|
data/mkbrut/bin/ci
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
5
|
+
ROOT_DIR=$(realpath "$SCRIPT_DIR/..")
|
6
|
+
|
7
|
+
usage() {
|
8
|
+
echo "Usage: $0"
|
9
|
+
echo
|
10
|
+
echo " No-op to comply with workspace protocol"
|
11
|
+
echo
|
12
|
+
}
|
13
|
+
|
14
|
+
for arg in "$@"; do
|
15
|
+
if [ "${arg}" = "-h" ] || [ "${arg}" = "--help" ] || [ "${arg}" = "help" ]; then
|
16
|
+
usage
|
17
|
+
exit 0
|
18
|
+
fi
|
19
|
+
done
|
data/mkbrut/bin/docs
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
5
|
+
ROOT_DIR=$(realpath "$SCRIPT_DIR/..")
|
6
|
+
|
7
|
+
usage() {
|
8
|
+
echo "Usage: $0"
|
9
|
+
echo
|
10
|
+
echo " No-op to comply with workspace protocol"
|
11
|
+
echo
|
12
|
+
}
|
13
|
+
|
14
|
+
for arg in "$@"; do
|
15
|
+
if [ "${arg}" = "-h" ] || [ "${arg}" = "--help" ] || [ "${arg}" = "help" ]; then
|
16
|
+
usage
|
17
|
+
exit 0
|
18
|
+
fi
|
19
|
+
done
|
data/mkbrut/bin/publish
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
5
|
+
ROOT_DIR=$(realpath "$SCRIPT_DIR/..")
|
6
|
+
|
7
|
+
main() {
|
8
|
+
detect_gem_version
|
9
|
+
detect_docker_platform
|
10
|
+
release_gem
|
11
|
+
build_and_maybe_push
|
12
|
+
}
|
13
|
+
|
14
|
+
log() {
|
15
|
+
echo "[ mkbrut/bin/publish ] ${*}"
|
16
|
+
}
|
17
|
+
|
18
|
+
usage() {
|
19
|
+
echo "Usage: $0"
|
20
|
+
echo
|
21
|
+
echo " Publish Ruby Gem and Docker image"
|
22
|
+
echo
|
23
|
+
}
|
24
|
+
|
25
|
+
release_gem() {
|
26
|
+
log "Releasing Gem"
|
27
|
+
rake release
|
28
|
+
wait_for_rubygems
|
29
|
+
}
|
30
|
+
|
31
|
+
wait_for_rubygems() {
|
32
|
+
timeout=30
|
33
|
+
interval=2
|
34
|
+
elapsed=0
|
35
|
+
|
36
|
+
log "Waiting ${timeout} seconds for mkbrut $GEM_VERSION to be available on RubyGems"
|
37
|
+
while (( elapsed < timeout )); do
|
38
|
+
if gem list -r "mkbrut" -a | grep -q "$GEM_VERSION"; then
|
39
|
+
log "mkbrut $GEM_VERSION is available on RubyGems"
|
40
|
+
return 0
|
41
|
+
fi
|
42
|
+
sleep $interval
|
43
|
+
(( elapsed += interval ))
|
44
|
+
done
|
45
|
+
|
46
|
+
log "mkbrut $GEM_VERSION is not available on RubyGems after $timeout seconds"
|
47
|
+
log "Something may have gone wrong. Or, it could just be taking a while"
|
48
|
+
log "You can re-run this with -G to bypassing pushing to RubyGems"
|
49
|
+
echo
|
50
|
+
log " bin/deploy -G"
|
51
|
+
exit 1
|
52
|
+
}
|
53
|
+
|
54
|
+
setup_docker_buildx() {
|
55
|
+
local builder_name=mkbrut-builder
|
56
|
+
|
57
|
+
if ! docker buildx ls | grep -q "^$builder_name"; then
|
58
|
+
log "Creating Docker buildx builder: $builder_name"
|
59
|
+
docker buildx create --name "$builder_name" --use
|
60
|
+
docker buildx inspect "$builder_name" --bootstrap
|
61
|
+
else
|
62
|
+
log "Docker buildx builder $builder_name already exists"
|
63
|
+
docker buildx use "$builder_name"
|
64
|
+
fi
|
65
|
+
}
|
66
|
+
|
67
|
+
detect_gem_version() {
|
68
|
+
|
69
|
+
GEM_VERSION=$( rake -T | grep "rake install " | sed 's/^.*mkbrut-//g' | sed 's/\.gem.*$//g')
|
70
|
+
if [[ "$GEM_VERSION" =~ ^[0-9]+\.[0-9]\.[0-9]+$ ]]; then
|
71
|
+
log "Releasing version ${GEM_VERSION}"
|
72
|
+
else
|
73
|
+
log "Version '${GEM_VERSION}' does not look like a version: X.Y.Z"
|
74
|
+
exit 1
|
75
|
+
fi
|
76
|
+
}
|
77
|
+
|
78
|
+
detect_docker_platform() {
|
79
|
+
|
80
|
+
KERNEL_NAME_FOR_ARCHITECTURE=$(docker info --format '{{.Architecture}}')
|
81
|
+
OSTYPE=$(docker info --format '{{.OSType}}')
|
82
|
+
|
83
|
+
case "$KERNEL_NAME_FOR_ARCHITECTURE" in
|
84
|
+
"aarch64")
|
85
|
+
DOCKER_NAME_FOR_ARCHITECTURE="arm64"
|
86
|
+
;;
|
87
|
+
"x86_64")
|
88
|
+
DOCKER_NAME_FOR_ARCHITECTURE="amd64"
|
89
|
+
;;
|
90
|
+
*)
|
91
|
+
log "Docker reported architecture is $KERNEL_NAME_FOR_ARCHITECTURE - hoping this works"
|
92
|
+
;;
|
93
|
+
esac
|
94
|
+
HOST_PLATFORM=${OSTYPE}/${DOCKER_NAME_FOR_ARCHITECTURE}
|
95
|
+
}
|
96
|
+
|
97
|
+
build_and_maybe_push() {
|
98
|
+
|
99
|
+
# See bin/setup for another use of this page
|
100
|
+
local docker_credentials_source="${SCRIPT_DIR}/../dx/credentials/dockerhub.credentials"
|
101
|
+
setup_docker_buildx
|
102
|
+
|
103
|
+
. "${docker_credentials_source}"
|
104
|
+
log "Loging into DockerHub with credentials from ${docker_credentials_source}"
|
105
|
+
docker login --username "${DOCKERHUB_USERNAME}" --password "${DOCKERHUB_PAT}"
|
106
|
+
|
107
|
+
DOCKER_BUILD_PUSH_OR_LOAD=--push
|
108
|
+
DOCKER_PLATFORMS="linux/amd64,linux/arm64"
|
109
|
+
|
110
|
+
log "Building Docker image and pushing to DockerHub"
|
111
|
+
|
112
|
+
docker buildx build \
|
113
|
+
--platform ${DOCKER_PLATFORMS} \
|
114
|
+
${DOCKER_BUILD_PUSH_OR_LOAD} \
|
115
|
+
--no-cache \
|
116
|
+
--build-arg brut_version="${GEM_VERSION}" \
|
117
|
+
--tag thirdtank/mkbrut:"${GEM_VERSION}" \
|
118
|
+
--tag thirdtank/mkbrut:latest \
|
119
|
+
deploy
|
120
|
+
}
|
121
|
+
|
122
|
+
for arg in "${@}"; do
|
123
|
+
if [ "${arg}" = "-h" ] || [ "${arg}" = "--help" ] || [ "${arg}" = "help" ]; then
|
124
|
+
usage
|
125
|
+
exit 0
|
126
|
+
fi
|
127
|
+
done
|
128
|
+
|
129
|
+
main
|
data/mkbrut/bin/rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' 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
|
+
require "rubygems"
|
14
|
+
require "bundler/setup"
|
15
|
+
|
16
|
+
load Gem.bin_path("rake", "rake")
|
data/mkbrut/bin/setup
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../../bin/bin_kit"
|
4
|
+
require "optparse"
|
5
|
+
require "pathname"
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
def setup(update_gems:)
|
9
|
+
if update_gems
|
10
|
+
log "Updating gems"
|
11
|
+
system! "bundle update"
|
12
|
+
else
|
13
|
+
log "Installing gems"
|
14
|
+
# Only do bundle install if the much-faster
|
15
|
+
# bundle check indicates we need to
|
16
|
+
system! "bundle check --no-color || bundle install --no-color --quiet"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
options = {
|
22
|
+
update_gems: false,
|
23
|
+
}
|
24
|
+
OptionParser.new do |opts|
|
25
|
+
opts.on("--update-gems","Update gems get the latest versions consistent with Gemfile / gemspec.") do
|
26
|
+
options[:update_gems] = true
|
27
|
+
end
|
28
|
+
end.parse!
|
29
|
+
|
30
|
+
setup(**options)
|
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
FROM ruby:3.4
|
2
|
+
|
3
|
+
SHELL [ "/bin/bash", "-o", "pipefail", "-c" ]
|
4
|
+
|
5
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
6
|
+
RUN apt-get -y update
|
7
|
+
|
8
|
+
# Update RubyGems and Bundler
|
9
|
+
RUN echo "gem: --no-document" >> ~/.gemrc && \
|
10
|
+
gem update --system
|
11
|
+
|
12
|
+
ARG brut_version
|
13
|
+
RUN gem install --version ${brut_version} mkbrut
|
14
|
+
|
15
|
+
ARG user_uid=10001
|
16
|
+
ARG user_gid=10002
|
17
|
+
|
18
|
+
# Create the user's group ID if it does not exist
|
19
|
+
RUN getent group ${user_gid} || groupadd --gid ${user_gid} appgroup
|
20
|
+
RUN useradd --uid ${user_uid} --gid ${user_gid} --create-home --home-dir /home/appuser appuser
|
21
|
+
|
22
|
+
# NOT including the group here as that will place the user's environment
|
23
|
+
# ONLY in that group and not in all the groups in which they are a part.
|
24
|
+
USER appuser
|
25
|
+
|
data/mkbrut/exe/mkbrut
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "erb"
|
3
|
+
require "ostruct"
|
4
|
+
|
5
|
+
module MKBrut
|
6
|
+
class App
|
7
|
+
def initialize(current_dir:, app_options:, out:, err:)
|
8
|
+
@out = out
|
9
|
+
@app_options = app_options
|
10
|
+
|
11
|
+
@out.puts "Creating app with these options:\n"
|
12
|
+
@out.puts "App name: #{app_options.app_name}"
|
13
|
+
@out.puts "App ID: #{app_options.app_id}"
|
14
|
+
@out.puts "Prefix: #{app_options.prefix}"
|
15
|
+
@out.puts "Organization: #{app_options.organization}"
|
16
|
+
@out.puts "Include demo? #{app_options.demo}\n"
|
17
|
+
|
18
|
+
if app_options.dry_run?
|
19
|
+
@out.puts "Dry Run"
|
20
|
+
MKBrut::Ops::BaseOp.dry_run = true
|
21
|
+
end
|
22
|
+
|
23
|
+
templates_dir = Pathname(
|
24
|
+
Gem::Specification.find_by_name("mkbrut").gem_dir
|
25
|
+
) / "templates"
|
26
|
+
|
27
|
+
@base = MKBrut::Base.new(
|
28
|
+
app_options:,
|
29
|
+
current_dir:,
|
30
|
+
templates_dir:
|
31
|
+
)
|
32
|
+
@segments = [
|
33
|
+
MKBrut::Segments::BareBones.new(
|
34
|
+
app_options:,
|
35
|
+
current_dir:,
|
36
|
+
templates_dir:,
|
37
|
+
)
|
38
|
+
]
|
39
|
+
if app_options.demo?
|
40
|
+
@segments << MKBrut::Segments::Demo.new(
|
41
|
+
app_options:,
|
42
|
+
current_dir:,
|
43
|
+
templates_dir:
|
44
|
+
)
|
45
|
+
end
|
46
|
+
app_options.segments.each do |segment|
|
47
|
+
case segment
|
48
|
+
when "heroku"
|
49
|
+
@segments << MKBrut::Segments::Heroku.new(
|
50
|
+
app_options:,
|
51
|
+
current_dir:,
|
52
|
+
templates_dir:
|
53
|
+
)
|
54
|
+
else
|
55
|
+
raise "Segment #{segment} is not supported"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def create!
|
61
|
+
@out.puts "Creating Base app"
|
62
|
+
@base.create!
|
63
|
+
@segments.each do |segment|
|
64
|
+
@out.puts "Creating segment: #{segment.class.friendly_name}"
|
65
|
+
segment.add!
|
66
|
+
end
|
67
|
+
@out.puts "#{@app_options.app_name} was created\n\n"
|
68
|
+
@out.puts "Time to get building:"
|
69
|
+
@out.puts "1. cd #{@app_options.app_name}"
|
70
|
+
@out.puts "2. dx/build"
|
71
|
+
@out.puts "3. dx/start"
|
72
|
+
@out.puts "4. [ in another terminal ] dx/exec bash"
|
73
|
+
@out.puts "5. [ inside the Docker container ] bin/setup"
|
74
|
+
@out.puts "6. [ inside the Docker container ] bin/dev"
|
75
|
+
@out.puts "7. Visit http://localhost:6502 in your browser"
|
76
|
+
@out.puts "8. [ inside the Docker container ] bin/setup help # to see more commands"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MKBrut
|
2
|
+
class AppName
|
3
|
+
def initialize(value)
|
4
|
+
identifier = value.to_s
|
5
|
+
if identifier.empty?
|
6
|
+
raise MKBrut::InvalidIdentifier, "app-name is required"
|
7
|
+
end
|
8
|
+
|
9
|
+
if identifier.length > 63
|
10
|
+
raise MKBrut::InvalidIdentifier, "app-name cannot be longer than 63 characters"
|
11
|
+
end
|
12
|
+
|
13
|
+
if identifier.start_with?("-") || identifier.end_with?("-")
|
14
|
+
raise MKBrut::InvalidIdentifier, "app-name cannot start or end with a hyphen"
|
15
|
+
end
|
16
|
+
|
17
|
+
if identifier.match?(/[^a-zA-Z\-_]/)
|
18
|
+
raise MKBrut::InvalidIdentifier, "app-name can only contain letters, hyphens, and underscores"
|
19
|
+
end
|
20
|
+
if identifier.match?(/__/) || identifier.match?(/--/)
|
21
|
+
raise MKBrut::InvalidIdentifier, "app-name can not have repeating underscores or hyphens"
|
22
|
+
end
|
23
|
+
@identifier = identifier.to_s.gsub(/_/,"-")
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s = @identifier
|
27
|
+
alias to_str to_s
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class MKBrut::AppOptions
|
2
|
+
attr_reader :app_name, :app_id, :prefix, :organization, :demo, :versions, :segments
|
3
|
+
|
4
|
+
def initialize(
|
5
|
+
app_name:,
|
6
|
+
app_id: nil,
|
7
|
+
prefix: nil,
|
8
|
+
dry_run: nil,
|
9
|
+
organization: nil,
|
10
|
+
demo: false,
|
11
|
+
versions: nil,
|
12
|
+
**rest
|
13
|
+
)
|
14
|
+
if app_name.nil?
|
15
|
+
raise ArgumentError, "app_name is required"
|
16
|
+
end
|
17
|
+
|
18
|
+
@app_name = app_name
|
19
|
+
@app_id = app_id || MKBrut::AppId.from_app_name(@app_name)
|
20
|
+
@prefix = prefix || MKBrut::Prefix.from_app_id(@app_id)
|
21
|
+
@organization = organization || @app_id
|
22
|
+
@dry_run = !!dry_run
|
23
|
+
@demo = !!demo
|
24
|
+
@versions = versions
|
25
|
+
@segments = rest.map { |key,value|
|
26
|
+
if key =~ /^segment-(.+)$/ && value
|
27
|
+
$1
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
}.compact
|
32
|
+
end
|
33
|
+
|
34
|
+
def dry_run? = @dry_run
|
35
|
+
def demo? = @demo
|
36
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "securerandom"
|
3
|
+
# Constructs the base of any Brut app.
|
4
|
+
class MKBrut::Base
|
5
|
+
include MKBrut
|
6
|
+
|
7
|
+
class ErbBinding < MKBrut::ErbBindingDelegate
|
8
|
+
def session_secret = SecureRandom.hex(64)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(app_options:, current_dir:, templates_dir:)
|
12
|
+
@project_root = current_dir / app_options.app_name
|
13
|
+
@templates_dir = templates_dir / "Base"
|
14
|
+
@erb_binding = ErbBinding.new(app_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create!
|
18
|
+
if @project_root.exist?
|
19
|
+
raise "Project root #{@project_root} already exists"
|
20
|
+
end
|
21
|
+
operations = [ Ops::Mkdir.new(@project_root) ] +
|
22
|
+
copy_files(@templates_dir, @project_root)
|
23
|
+
|
24
|
+
operations.each do |operation|
|
25
|
+
operation.call
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def filenames_to_always_skip = [ "README.md", "mkicons.sh" ]
|
32
|
+
|
33
|
+
def copy_files(source_dir, destination_root)
|
34
|
+
operations = []
|
35
|
+
Dir.glob("#{source_dir}/*", flags: File::FNM_DOTMATCH).each do |template_file|
|
36
|
+
template_file = Pathname(template_file)
|
37
|
+
if [ ".", ".." ].include?(template_file.basename.to_s)
|
38
|
+
next
|
39
|
+
end
|
40
|
+
if template_file.directory?
|
41
|
+
operations << Ops::Mkdir.new(destination_root / template_file.basename)
|
42
|
+
operations += copy_files(template_file, destination_root / template_file.basename)
|
43
|
+
elsif template_file.extname == ".erb"
|
44
|
+
operations << Ops::RenderTemplate.new(
|
45
|
+
template_file,
|
46
|
+
destination_root:,
|
47
|
+
erb_binding: @erb_binding
|
48
|
+
)
|
49
|
+
elsif filenames_to_always_skip.include?(template_file.basename.to_s)
|
50
|
+
operations << Ops::SkipFile.new(template_file)
|
51
|
+
else
|
52
|
+
operations << Ops::CopyFile.new(template_file, destination_root:)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
operations
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
module MKBrut
|
5
|
+
class CLI
|
6
|
+
def initialize(args:, out: $stdout, err: $stderr)
|
7
|
+
@args = args
|
8
|
+
@out = out
|
9
|
+
@err = err
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
|
14
|
+
app_options = parse_options(@args, MKBrut::Versions.new)
|
15
|
+
new_app = MKBrut::App.new(
|
16
|
+
current_dir: Pathname.pwd.expand_path,
|
17
|
+
app_options:,
|
18
|
+
out: PrefixedIO.new(@out, "mkbrut"),
|
19
|
+
err: @err
|
20
|
+
)
|
21
|
+
new_app.create!
|
22
|
+
0
|
23
|
+
rescue => e
|
24
|
+
@err.puts "Error: #{e.message}"
|
25
|
+
if ENV["BRUT_CLI_RAISE_ON_ERROR"] == "true"
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
1
|
29
|
+
end
|
30
|
+
|
31
|
+
def show_help(versions)
|
32
|
+
@out.puts @option_parser
|
33
|
+
@out.puts
|
34
|
+
@out.puts "ARGUMENTS"
|
35
|
+
@out.puts
|
36
|
+
@out.puts " app-name - name for your app, which will be the folder where your app's files are created"
|
37
|
+
@out.puts
|
38
|
+
@out.puts "ENVIRONMENT VARIABLES"
|
39
|
+
@out.puts
|
40
|
+
@out.puts " BRUT_CLI_RAISE_ON_ERROR - if set to 'true', any error will raise an exception instead of printing to stderr"
|
41
|
+
@out.puts
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
|
47
|
+
def parse_options(args, versions)
|
48
|
+
options = {}
|
49
|
+
@option_parser = OptionParser.new do |opts|
|
50
|
+
opts.accept(MKBrut::Prefix) do |prefix|
|
51
|
+
MKBrut::Prefix.new(prefix)
|
52
|
+
end
|
53
|
+
opts.accept(MKBrut::AppId) do |prefix|
|
54
|
+
MKBrut::AppId.new(prefix)
|
55
|
+
end
|
56
|
+
opts.accept(MKBrut::Organization) do |prefix|
|
57
|
+
MKBrut::Organization.new(prefix)
|
58
|
+
end
|
59
|
+
opts.banner = [
|
60
|
+
"Usage: mkbrut [options] app-name",
|
61
|
+
"",
|
62
|
+
" Creates a new Brut-powered app",
|
63
|
+
"",
|
64
|
+
"VERSION",
|
65
|
+
"",
|
66
|
+
" #{MKBrut::VERSION}",
|
67
|
+
"",
|
68
|
+
"OPTIONS",
|
69
|
+
"",
|
70
|
+
].join("\n")
|
71
|
+
|
72
|
+
opts.on("-a", "--app-id=ID", MKBrut::AppId,
|
73
|
+
"App identifier, which must be able to be used as a hostname or other Internet identifier. Derived from your app name, if omitted")
|
74
|
+
|
75
|
+
opts.on("-o", "--organization=ORG",MKBrut::Organization,
|
76
|
+
"Organization name, e.g. what you'd use for GitHub. Defaults to the app-id value")
|
77
|
+
|
78
|
+
opts.on("-e", "--prefix=PREFIX", MKBrut::Prefix,
|
79
|
+
"Two-character prefix for external IDs and autonomous custom elements. Derived from your app-id, if omitted.")
|
80
|
+
|
81
|
+
opts.on("--dry-run", "Only show what would happen, don't actually do anything")
|
82
|
+
opts.on("--[no-]demo", "Include, or not, additional files that demonstrate Brut's features (default is true for now")
|
83
|
+
{
|
84
|
+
"sidekiq" => "Use Sidekiq for background jobs",
|
85
|
+
"heroku" => "Use Heroku for container-based deployment",
|
86
|
+
}.each do |segment,description|
|
87
|
+
opts.on("--segment-#{segment}", description)
|
88
|
+
end
|
89
|
+
opts.on("-h", "--help", "Show this help message") do
|
90
|
+
show_help(versions)
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
@option_parser.parse!(args, into: options)
|
96
|
+
if !options.key?(:demo)
|
97
|
+
options[:demo] = true
|
98
|
+
end
|
99
|
+
|
100
|
+
options[:app_name] = MKBrut::AppName.new(args.first)
|
101
|
+
options[:app_id] = options[:'app-id']
|
102
|
+
options[:dry_run] = !!options[:'dry-run']
|
103
|
+
MKBrut::AppOptions.new(**options.merge(versions:))
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This exists because ERB can't working with a SimpleDelegator or
|
2
|
+
# Delegate.
|
3
|
+
class MKBrut::ErbBindingDelegate
|
4
|
+
def initialize(app_options)
|
5
|
+
@app_options = app_options
|
6
|
+
end
|
7
|
+
|
8
|
+
# Not using Delegate because it won't work with ERB binding
|
9
|
+
def method_missing(syn,*args,&block)
|
10
|
+
if args.empty? && @app_options.respond_to?(syn)
|
11
|
+
@app_options.send(syn)
|
12
|
+
else
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond_to_missing?(syn,include_all)
|
18
|
+
@app_options.respond_to?(syn)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MKBrut
|
2
|
+
class InternetIdentifier
|
3
|
+
def initialize(name, value)
|
4
|
+
@name = name
|
5
|
+
@identifier = value.to_s
|
6
|
+
validate_identifier
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s = @identifier
|
10
|
+
alias to_str to_s
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def validate_identifier
|
15
|
+
if @identifier.empty?
|
16
|
+
raise MKBrut::InvalidIdentifier, "#{@name} cannot be empty"
|
17
|
+
end
|
18
|
+
|
19
|
+
if @identifier.length > 63
|
20
|
+
raise MKBrut::InvalidIdentifier, "#{@name} cannot be longer than 63 characters"
|
21
|
+
end
|
22
|
+
|
23
|
+
if @identifier.start_with?("-") || @identifier.end_with?("-")
|
24
|
+
raise MKBrut::InvalidIdentifier, "#{@name} cannot start or end with a hyphen"
|
25
|
+
end
|
26
|
+
|
27
|
+
if @identifier.match?(/[^a-zA-Z0-9-]/)
|
28
|
+
raise MKBrut::InvalidIdentifier, "#{@name} can only contain letters, numbers, and hyphens"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|