logger)
12 | {
13 | _logger = logger;
14 | }
15 |
16 | public IActionResult Index()
17 | {
18 | return View();
19 | }
20 |
21 | public IActionResult Privacy()
22 | {
23 | return View();
24 | }
25 |
26 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
27 | public IActionResult Error()
28 | {
29 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Models/ErrorViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace app.Models;
2 |
3 | public class ErrorViewModel
4 | {
5 | public string? RequestId { get; set; }
6 |
7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
8 | }
9 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | // Add services to the container.
4 | builder.Services.AddControllersWithViews();
5 |
6 | var app = builder.Build();
7 |
8 | // Configure the HTTP request pipeline.
9 | if (!app.Environment.IsDevelopment())
10 | {
11 | app.UseExceptionHandler("/Home/Error");
12 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
13 | app.UseHsts();
14 | }
15 |
16 | app.UseHttpsRedirection();
17 | app.UseStaticFiles();
18 |
19 | app.UseRouting();
20 |
21 | app.UseAuthorization();
22 |
23 | app.MapControllerRoute(
24 | name: "default",
25 | pattern: "{controller=Home}/{action=Index}/{id?}");
26 |
27 | app.Run();
28 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:33834",
7 | "sslPort": 44314
8 | }
9 | },
10 | "profiles": {
11 | "http": {
12 | "commandName": "Project",
13 | "dotnetRunMessages": true,
14 | "launchBrowser": true,
15 | "applicationUrl": "http://localhost:5299",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "https": {
21 | "commandName": "Project",
22 | "dotnetRunMessages": true,
23 | "launchBrowser": true,
24 | "applicationUrl": "https://localhost:7004;http://localhost:5299",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | },
29 | "IIS Express": {
30 | "commandName": "IISExpress",
31 | "launchBrowser": true,
32 | "environmentVariables": {
33 | "ASPNETCORE_ENVIRONMENT": "Development"
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Home Page";
3 | }
4 |
5 |
9 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/Home/Privacy.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Privacy Policy";
3 | }
4 | @ViewData["Title"]
5 |
6 | Use this page to detail your site's privacy policy.
7 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @model ErrorViewModel
2 | @{
3 | ViewData["Title"] = "Error";
4 | }
5 |
6 | Error.
7 | An error occurred while processing your request.
8 |
9 | @if (Model.ShowRequestId)
10 | {
11 |
12 | Request ID: @Model.RequestId
13 |
14 | }
15 |
16 | Development Mode
17 |
18 | Swapping to Development environment will display more detailed information about the error that occurred.
19 |
20 |
21 | The Development environment shouldn't be enabled for deployed applications.
22 | It can result in displaying sensitive information from exceptions to end users.
23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
24 | and restarting the app.
25 |
26 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - app
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
app
16 |
18 |
19 |
20 |
30 |
31 |
32 |
33 |
34 |
35 | @RenderBody()
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 | @await RenderSectionAsync("Scripts", required: false)
48 |
49 |
50 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/Shared/_Layout.cshtml.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | a {
11 | color: #0077cc;
12 | }
13 |
14 | .btn-primary {
15 | color: #fff;
16 | background-color: #1b6ec2;
17 | border-color: #1861ac;
18 | }
19 |
20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
21 | color: #fff;
22 | background-color: #1b6ec2;
23 | border-color: #1861ac;
24 | }
25 |
26 | .border-top {
27 | border-top: 1px solid #e5e5e5;
28 | }
29 | .border-bottom {
30 | border-bottom: 1px solid #e5e5e5;
31 | }
32 |
33 | .box-shadow {
34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
35 | }
36 |
37 | button.accept-policy {
38 | font-size: 1rem;
39 | line-height: inherit;
40 | }
41 |
42 | .footer {
43 | position: absolute;
44 | bottom: 0;
45 | width: 100%;
46 | white-space: nowrap;
47 | line-height: 60px;
48 | }
49 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using app
2 | @using app.Models
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/app.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | html {
2 | font-size: 14px;
3 | }
4 |
5 | @media (min-width: 768px) {
6 | html {
7 | font-size: 16px;
8 | }
9 | }
10 |
11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
13 | }
14 |
15 | html {
16 | position: relative;
17 | min-height: 100%;
18 | }
19 |
20 | body {
21 | margin-bottom: 60px;
22 | }
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redhat-developer/red-hat-developer-hub-software-templates/25888aa2edffea568ee84871be78b7d111c4cff5/templates/azure/dotnet-frontend/skeleton/app/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your JavaScript code.
5 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2021 Twitter, Inc.
4 | Copyright (c) 2011-2021 The Bootstrap Authors
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) .NET Foundation and Contributors
4 |
5 | All rights reserved.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Unobtrusive validation support library for jQuery and jQuery Validate
4 | * Copyright (c) .NET Foundation. All rights reserved.
5 | * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
6 | * @version v4.0.0
7 | */
8 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(s){var a,o=s.validator,d="unobtrusiveValidation";function l(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function u(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function n(a){return a.substr(0,a.lastIndexOf(".")+1)}function m(a,e){return a=0===a.indexOf("*.")?a.replace("*.",e):a}function f(a){var e=s(this),n="__jquery_unobtrusive_validation_form_reset";if(!e.data(n)){e.data(n,!0);try{e.data("validator").resetForm()}finally{e.removeData(n)}e.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),e.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function p(n){function a(a,e){(a=r[a])&&s.isFunction(a)&&a.apply(n,e)}var e=s(n),t=e.data(d),i=s.proxy(f,n),r=o.unobtrusive.options||{};return t||(t={options:{errorClass:r.errorClass||"input-validation-error",errorElement:r.errorElement||"span",errorPlacement:function(){!function(a,e){var e=s(this).find("[data-valmsg-for='"+u(e[0].name)+"']"),n=(n=e.attr("data-valmsg-replace"))?!1!==s.parseJSON(n):null;e.removeClass("field-validation-valid").addClass("field-validation-error"),a.data("unobtrusiveContainer",e),n?(e.empty(),a.removeClass("input-validation-error").appendTo(e)):a.hide()}.apply(n,arguments),a("errorPlacement",arguments)},invalidHandler:function(){!function(a,e){var n=s(this).find("[data-valmsg-summary=true]"),t=n.find("ul");t&&t.length&&e.errorList.length&&(t.empty(),n.addClass("validation-summary-errors").removeClass("validation-summary-valid"),s.each(e.errorList,function(){s(" ").html(this.message).appendTo(t)}))}.apply(n,arguments),a("invalidHandler",arguments)},messages:{},rules:{},success:function(){!function(a){var e,n=a.data("unobtrusiveContainer");n&&(e=(e=n.attr("data-valmsg-replace"))?s.parseJSON(e):null,n.addClass("field-validation-valid").removeClass("field-validation-error"),a.removeData("unobtrusiveContainer"),e&&n.empty())}.apply(n,arguments),a("success",arguments)}},attachValidation:function(){e.off("reset."+d,i).on("reset."+d,i).validate(this.options)},validate:function(){return e.validate(),e.valid()}},e.data(d,t)),t}return o.unobtrusive={adapters:[],parseElement:function(t,a){var e,i,r,o=s(t),d=o.parents("form")[0];d&&((e=p(d)).options.rules[t.name]=i={},e.options.messages[t.name]=r={},s.each(this.adapters,function(){var a="data-val-"+this.name,e=o.attr(a),n={};void 0!==e&&(a+="-",s.each(this.params,function(){n[this]=o.attr(a+this)}),this.adapt({element:t,form:d,message:e,params:n,rules:i,messages:r}))}),s.extend(i,{__dummy__:!0}),a||e.attachValidation())},parse:function(a){var a=s(a),e=a.parents().addBack().filter("form").add(a.find("form")).has("[data-val=true]");a.find("[data-val=true]").each(function(){o.unobtrusive.parseElement(this,!0)}),e.each(function(){var a=p(this);a&&a.attachValidation()})}},(a=o.unobtrusive.adapters).add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},a.addBool=function(e,n){return this.add(e,function(a){l(a,n||e,!0)})},a.addMinMax=function(a,t,i,r,e,n){return this.add(a,[e||"min",n||"max"],function(a){var e=a.params.min,n=a.params.max;e&&n?l(a,r,[e,n]):e?l(a,t,e):n&&l(a,i,n)})},a.addSingleVal=function(e,n,t){return this.add(e,[n||"val"],function(a){l(a,t||e,a.params[n])})},o.addMethod("__dummy__",function(a,e,n){return!0}),o.addMethod("regex",function(a,e,n){return!!this.optional(e)||(e=new RegExp(n).exec(a))&&0===e.index&&e[0].length===a.length}),o.addMethod("nonalphamin",function(a,e,n){var t;return t=n?(t=a.match(/\W/g))&&t.length>=n:t}),o.methods.extension?(a.addSingleVal("accept","mimtype"),a.addSingleVal("extension","extension")):a.addSingleVal("extension","extension","accept"),a.addSingleVal("regex","pattern"),a.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),a.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),a.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),a.add("equalto",["other"],function(a){var e=n(a.element.name),e=m(a.params.other,e);l(a,"equalTo",s(a.form).find(":input").filter("[name='"+u(e)+"']")[0])}),a.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||l(a,"required",!0)}),a.add("remote",["url","type","additionalfields"],function(t){var i={url:t.params.url,type:t.params.type||"GET",data:{}},r=n(t.element.name);s.each((t.params.additionalfields||t.element.name).replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g),function(a,e){var n=m(e,r);i.data[n]=function(){var a=s(t.form).find(":input").filter("[name='"+u(n)+"']");return a.is(":checkbox")?a.filter(":checked").val()||a.filter(":hidden").val()||"":a.is(":radio")?a.filter(":checked").val()||"":a.val()}}),l(t,"remote",i)}),a.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&l(a,"minlength",a.params.min),a.params.nonalphamin&&l(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&l(a,"regex",a.params.regex)}),a.add("fileextensions",["extensions"],function(a){l(a,"extension",a.params.extensions)}),s(function(){o.unobtrusive.parse(document)}),o.unobtrusive});
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/app/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/skeleton/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Docker
2 | # Build a Docker image
3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker
4 |
5 | trigger:
6 | - main
7 |
8 | resources:
9 | - repo: self
10 |
11 | variables:
12 | tag: "$(Build.BuildId)"
13 |
14 | stages:
15 | - stage: Build
16 | displayName: Build image
17 | jobs:
18 | - job: Build
19 | displayName: Build
20 | pool:
21 | vmImage: ubuntu-latest
22 | steps:
23 | - task: Docker@2
24 | displayName: Build an image
25 | inputs:
26 | command: build
27 | dockerfile: "$(Build.SourcesDirectory)/Dockerfile"
28 | tags: |
29 | $(tag)
30 |
--------------------------------------------------------------------------------
/templates/azure/dotnet-frontend/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: dotnet-frontend-template
5 | title: Create a .NET Frontend application in Azure DevOps with a CI pipeline
6 | description: Create a starter .NET frontend application with a CI pipeline
7 | tags:
8 | - recommended
9 | - dotnet
10 | spec:
11 | owner: janus-authors
12 | system: janus-idp
13 | type: service
14 |
15 | parameters:
16 | - title: Choose a location
17 | required:
18 | - orgName
19 | - projectName
20 | - repoName
21 | properties:
22 | orgName:
23 | title: Organization
24 | type: string
25 | description: The Organization that this repo will belong to
26 | projectName:
27 | title: Project
28 | type: string
29 | description: The Project that this repo will belong to
30 | repoName:
31 | title: Repository
32 | type: string
33 | description: The name of the repository
34 |
35 | - title: Provide information about the new component
36 | required:
37 | - owner
38 | - system
39 | - port
40 | properties:
41 | title:
42 | title: Title
43 | type: string
44 | description: The title of the component
45 | description:
46 | title: Description
47 | type: string
48 | description: Help others understand what this component is for
49 | owner:
50 | title: Owner
51 | type: string
52 | description: The owner of the component
53 | ui:field: EntityPicker
54 | ui:options:
55 | catalogFilter:
56 | kind:
57 | - Group
58 | - User
59 | system:
60 | title: System
61 | type: string
62 | description: The system that the component belongs to
63 | ui:field: EntityPicker
64 | ui:options:
65 | catalogFilter:
66 | kind:
67 | - System
68 | port:
69 | title: Port
70 | type: number
71 | default: 5000
72 | description: Override the port exposed for the application
73 |
74 | steps:
75 | - id: sourceCodeTemplate
76 | name: Generating the Source Code Component
77 | action: fetch:template
78 | input:
79 | url: ./skeleton
80 | values:
81 | # azure devops uses `my-project/my-repo`
82 | orgName: ${{ parameters.projectName }}
83 | repoName: ${{ parameters.repoName }}
84 | owner: ${{ parameters.owner }}
85 | system: ${{ parameters.system }}
86 | title: ${{ parameters.title }}
87 | description: ${{ parameters.description }}
88 | port: ${{ parameters.port }}
89 | applicationType: website
90 | sourceControl: dev.azure.com
91 |
92 | - id: catalogTemplate
93 | name: Generating the Catalog Info Component
94 | action: fetch:template
95 | input:
96 | url: ../../../skeletons/catalog-info/
97 | values:
98 | # azure devops uses `my-project/my-repo`
99 | orgName: ${{ parameters.projectName }}
100 | repoName: ${{ parameters.repoName }}
101 | owner: ${{ parameters.owner }}
102 | system: ${{ parameters.system }}
103 | title: ${{ parameters.title }}
104 | description: ${{ parameters.description }}
105 | port: ${{ parameters.port }}
106 | applicationType: website
107 | sourceControl: dev.azure.com
108 |
109 | - id: publish
110 | name: Publishing to the Source Code Repository
111 | action: publish:azure
112 | input:
113 | allowedHosts: ['dev.azure.com']
114 | description: ${{ parameters.description }}
115 | repoUrl: dev.azure.com?owner=${{ parameters.projectName }}&repo=${{ parameters.repoName }}&organization=${{ parameters.orgName }}
116 | defaultBranch: main
117 |
118 | - id: register
119 | name: Registering the Catalog Info Component
120 | action: catalog:register
121 | input:
122 | repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
123 | catalogInfoPath: /catalog-info.yaml
124 |
125 | output:
126 | links:
127 | - title: Open the Source Code Repository
128 | url: ${{ steps.publish.output.remoteUrl }}
129 | - title: Open the Catalog Info Component
130 | icon: catalog
131 | entityRef: ${{ steps.register.output.entityRef }}
132 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/docs/features/auth_rbac.md:
--------------------------------------------------------------------------------
1 | # Guide to Handle Authentication and Authorization
2 |
3 | This plugin exports two routes: `/health` and `/message`. The route `/health` is configured to have no authentication, and `/message` requires the user to be logged in. By default a route will require authentication, the client will have to add authentication tokens to access it, otherwise the route will respond with `401 Unauthorized`, meaning that the route requires an author (authentication), but was not able to identify it.
4 |
5 | ## Authorization
6 |
7 | There are other cases where Authorization is required. It means that even being authenticated, the user most be part of a role that has access to it.
8 |
9 | Backstage provides a permission framework that can be used to add roles checking to a route. In order to use it you must first create a `permissions.ts` file that will export the required permissions to your route. Here's an example of a permission `read` for `ocm.cluster.read`
10 |
11 | ```ts
12 | import { createPermission } from '@backstage/plugin-permission-common';
13 |
14 | export const ocmClusterReadPermission = createPermission({
15 | name: 'ocm.cluster.read',
16 | attributes: {
17 | action: 'read',
18 | },
19 | });
20 |
21 | export const ocmClusterPermissions = [ocmClusterReadPermission];
22 | ```
23 |
24 | Then make sure that the permission is exported from `index.ts`:
25 |
26 | ```ts
27 | export * from './permissions';
28 | ```
29 |
30 | To check the permission for the route you will need the service `PermissionsService`:
31 |
32 | ```ts
33 | export interface RouterOptions {
34 | logger: Logger;
35 | config: Config;
36 | discovery: PluginEndpointDiscovery;
37 | permissions: PermissionsService; // Permission framework
38 | httpAuth?: HttpAuthService; // Auth Service
39 | }
40 |
41 | export async function createRouter(
42 | options: RouterOptions,
43 | ): Promise {
44 | const { logger } = options;
45 | const { config } = options;
46 | const { permissions } = options; // Added
47 |
48 | const { httpAuth } = createLegacyAuthAdapters(options); // Added
49 |
50 | return buildRouter(config, logger, httpAuth, permissions);
51 | }
52 |
53 | export const ocmPlugin = createBackendPlugin({
54 | pluginId: 'ocm',
55 | register(env) {
56 | env.registerInit({
57 | deps: {
58 | logger: coreServices.logger,
59 | config: coreServices.rootConfig,
60 | http: coreServices.httpRouter,
61 | httpAuth: coreServices.httpAuth, // Added the core services httpAuth
62 | permissions: coreServices.permissions, // Added the core services permissions
63 | },
64 | async init({ config, logger, http, httpAuth, permissions }) { // additions
65 | http.use(
66 | buildRouter(
67 | config,
68 | logger,
69 | httpAuth, // Addition
70 | permissions, // Addition
71 | ),
72 | );
73 | },
74 | });
75 | },
76 | });
77 | ```
78 |
79 | In our `buildRouter` we must integrate permissions with the router using the constant `permissionsIntegrationRouter` with the permissions from our `permissions.ts` file:
80 |
81 | ```ts
82 | const buildRouter = (
83 | config: Config,
84 | logger: Logger,
85 | httpAuth: HttpAuthService,
86 | permissions: PermissionsService,
87 | ) => {
88 | const router = Router();
89 |
90 | const permissionsIntegrationRouter = createPermissionIntegrationRouter({
91 | permissions: ocmEntityPermissions,
92 | }); // Create the permission integration routes and pass in our permissions
93 |
94 | router.use(express.json());
95 | router.use(permissionsIntegrationRouter); // Set the router to use the permissions
96 |
97 |
98 | };
99 | ```
100 |
101 | After the permission integration router has been set, we will need to handle authorization within our Backend plugin. For this we create a method `authorize`, call it and and handle `DENY` results:
102 |
103 | ```ts
104 | const authorize = async (request: Request, permission: BasicPermission) => {
105 | const decision = (
106 | await permissions.authorize([{ permission: permission }], {
107 | credentials: await httpAuth.credentials(request),
108 | })
109 | )[0];
110 | return decision;
111 | }
112 |
113 | router.get('/myRoute', async (request, response) => {
114 | const decision = await authorize(request, ocmEntityReadPermission);
115 | if (decision.result === AuthorizeResult.DENY) {
116 | throw new NotAllowedError('Unauthorized');
117 | }
118 | // Continue here if user is allowed...
119 | }
120 | ```
121 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/docs/features/export_to_rhdh.md:
--------------------------------------------------------------------------------
1 | # Guide to Export Your Plugin to Red Hat Developer Hub
2 |
3 | This plugin is ready to be exported to run on Red Hat Developer Hub (RHDH) 1.2 using the [Dynamic Plugins](https://github.com/redhat-developer/rhdh/blob/main/docs/dynamic-plugins/index.md) mechanism.
4 |
5 | ## Exporting Dynamic Plugins
6 |
7 | The dynamic plugins require the dev dependency `@janus-idp/cli` on the corresponding version for your target RHDH. This dependency will brings the command `janus-cli`, so a new script can be added to `package.json` to export dynamic plugins:
8 |
9 | ```json
10 | "export-dynamic": "janus-cli package export-dynamic-plugin --clean"
11 | ```
12 |
13 | ## Installation
14 |
15 | After running this command a new folder will be created in root dir: `dist-dynamic`. This folder should be copied to RHDH dynamic plugins root directory and renamed to `${plugin-id-as-in-package.json}-dynamic`. The plugin can be mapped on `app-config.yaml` using the dynamic section, for example:
16 |
17 | ```yaml
18 | global:
19 | dynamic:
20 | plugins:
21 | - package: /path/to/plugin/root/dir
22 | disabled: false
23 | ```
24 |
25 | Please bear in mind that this way of installing plugins is a TechPreview and it may change in later RHDH releases.
26 |
27 | For more information check [Dynamic Plugins](https://github.com/redhat-developer/rhdh/blob/main/docs/dynamic-plugins/index.md) documentation.
28 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/docs/features/extend.md:
--------------------------------------------------------------------------------
1 | # Guide to Understand And Extend Your Plugin
2 |
3 | ## Understanding the plugin code
4 |
5 | The plugin is created on file `plugin.ts` and when creating it you can pick what services you want to be used by your plugin. In this case we use services `LoggerService`, `Config`, `DiscoveryService` and `HttpAuthService`. Some service may be used by other APIs, in this plugin Discovery and HttpAuth services are used by the function `createLegacyAuthAdapters` in `router.ts`.
6 |
7 | Talking about `route.ts`, it is where the HTTP routes are created to handle user requests. It creates only two routes, `GET /health`, that simples return a JSON, and `GET /hello`, that retries user information from the request to be returned with a message.
8 |
9 | Later on `plugin.ts` we also free the `/health` route from any authenticatication, meaning that anyone can request the route without being loged in into Backstage.
10 |
11 | ## Extending the plugin capabilities
12 |
13 | When calling `registerInit` in `plugin.ts` it is possible to access other [services](https://backstage.io/docs/backend-system/architecture/services):
14 |
15 | ```ts
16 | env.registerInit({
17 | deps: {
18 | // services to be injected
19 | },
20 | async init({
21 | // services are passed as parameters to init
22 | }) {
23 | // use the services here
24 | };
25 | });
26 | ```
27 |
28 | ## Extending Existing Plugins and Services
29 |
30 | Backstage plugins can be extended by using backend modules. Example of plugins that can be extended are catalog entities and scaffolding actions. Registering a module looks like what is done to plugins, with the difference that we call createBackendModule
31 |
32 | ```ts
33 | import { createBackendModule } from '@backstage/backend-plugin-api';
34 |
35 | export const myCustomPluginIdModuleId = createBackendModule({
36 | pluginId: 'plugin-id', // plugin to be extended
37 | moduleId: 'my-custom-module-id',
38 | register(env) {
39 | env.registerInit({
40 | deps: {
41 | // services or other extension points
42 | },
43 | async init({ catalog }) {
44 | // your code here
45 | },
46 | });
47 | },
48 | });
49 | ```
50 |
51 | So if you are looking to create actions, catalog processors or other extensions that are for a existing plugin, check if a module is not the suitable way of doing that.
52 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/docs/index.md:
--------------------------------------------------------------------------------
1 | # Guide to kickstart backend-end plugin development
2 |
3 | This Software Template guides you to kickstart your back-end plugin development with fewer clicks.
4 |
5 | Note: The template allows only `github.com` as host
6 |
7 | ## Getting started
8 |
9 | This template gathers essential information from the user, such as the plugin ID, repository owner, and the repository name. It then checks if the repository already exists or if the user wants to create a new one. Upon execution, the template generates a folder structure with all the necessary files, dependencies, UI components, and unit tests to help you get started. This same folder structure is also created when you run `yarn new --select backend-plugin` using the [Backstage CLI](https://backstage.io/docs/tooling/cli/commands#new). The template includes plugin two routes examples:
10 |
11 | * /health: A simply unauthenticated route that returns the JSON `{"status" : "ok"}`;
12 | * /message: A route that requires authentication and returns the JSON `{ "message": "Hello User" }`. where User is the logged using user.
13 |
14 | For more details on plugin development, check out the official [Backstage documentation](https://backstage.io/docs/plugins/).
--------------------------------------------------------------------------------
/templates/create-backend-plugin/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: "Create Backend Plugin Template"
2 | site_description: "User documentation for creating a back-end plugin"
3 |
4 | nav:
5 | - Introduction: index.md
6 | - Understand And Extend Your Plugin: features/extend.md
7 | - Handle Authentication and Authorization: features/auth_rbac.md
8 | - Export Your Plugin to Red Hat Developer Hub: features/export_to_rhdh.md
9 | plugins:
10 | - techdocs-core
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
2 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/README.md:
--------------------------------------------------------------------------------
1 | # ${{values.plugin_id}}
2 |
3 | Welcome to the ${{values.plugin_id}} backend plugin!
4 |
5 | _This plugin was created through the Backstage CLI_
6 |
7 | ## Getting started
8 |
9 | Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn
10 | start` in the root directory, wait the server to start and then acessing the plugin endpoints:
11 |
12 | * [/${{values.plugin_id}}/health](http://localhost:7007/api/${{values.plugin_id}}/health): This endpoint will simply return a JSON with content `{"status" : "ok"}` and requires no authentication;
13 | * [/${{values.plugin_id}}/hello](http://localhost:7007/api/${{values.plugin_id}}/hello): This endpoint will thrown a 401 error if not authenticated and can be called setting the `Authorization` header with the proper token. Once authenticated it will return a JSON with content `{"message": "Hello User"}`, where User is the authenticated user. Here's an example to call it using the `curl` utility:
14 |
15 | ```
16 | curl -vH "Authorization: Bearer ${RHDH_TOKEN}" http://localhost:7007/api/${{values.plugin_id}}/hello
17 | ```
18 |
19 | You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
20 | This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
21 | It is only meant for local development, and the setup for it can be found inside the [/dev](/dev) directory.
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/catalog-info.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: Component
3 | metadata:
4 | name: ${{ values.plugin_id }}
5 | {%- if values.description %}
6 | description: ${{ values.description }}
7 | {%- endif %}
8 | annotations:
9 | backstage.io/techdocs-ref: dir:.
10 | github.com/project-slug: ${{ values.orgName }}/${{ values.repoName }}
11 | spec:
12 | type: service
13 | {%- if values.lifecycle %}
14 | lifecycle: ${{ values.lifecycle }}
15 | {%- else %}
16 | lifecycle: production
17 | {%- endif %}
18 | owner: ${{ values.owner }}
19 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/dev/index.ts:
--------------------------------------------------------------------------------
1 | import { createBackend } from '@backstage/backend-defaults';
2 |
3 | const backend = createBackend();
4 |
5 | backend.add(import('@backstage/plugin-auth-backend'));
6 | backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
7 | backend.add(import('../src'));
8 |
9 | backend.start();
10 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@internal/backstage-plugin-${{values.plugin_id}}-backend",
3 | "version": "0.1.1",
4 | "main": "src/index.ts",
5 | "types": "src/index.ts",
6 | "license": "Apache-2.0",
7 | "private": true,
8 | "publishConfig": {
9 | "access": "public",
10 | "main": "dist/index.cjs.js",
11 | "types": "dist/index.d.ts"
12 | },
13 | "backstage": {
14 | "role": "backend-plugin"
15 | },
16 | "scripts": {
17 | "start": "backstage-cli package start",
18 | "build": "backstage-cli package build",
19 | "lint": "backstage-cli package lint",
20 | "test": "backstage-cli package test",
21 | "clean": "backstage-cli package clean",
22 | "prepack": "backstage-cli package prepack",
23 | "postpack": "backstage-cli package postpack",
24 | "export-dynamic": "janus-cli package export-dynamic-plugin --clean"
25 | },
26 | "dependencies": {
27 | "@backstage/backend-common": "^0.23.3",
28 | "@backstage/backend-defaults": "^0.4.0",
29 | "@backstage/backend-plugin-api": "0.7.0",
30 | "@backstage/config": "^1.2.0",
31 | "@types/express": "^4.17.6",
32 | "express": "^4.17.1",
33 | "express-promise-router": "^4.1.0",
34 | "winston": "^3.2.1",
35 | "node-fetch": "^2.6.7",
36 | "yn": "^4.0.0"
37 | },
38 | "devDependencies": {
39 | "@backstage/backend-test-utils": "^0.4.4",
40 | "@backstage/cli": "^0.26.11",
41 | "@backstage/plugin-auth-backend": "^0.22.9",
42 | "@backstage/plugin-auth-backend-module-guest-provider": "^0.1.8",
43 | "@janus-idp/cli": "^1.13.1",
44 | "@types/supertest": "^2.0.12",
45 | "supertest": "^6.2.4",
46 | "msw": "^2.3.1"
47 | },
48 | "files": [
49 | "dist"
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './service/router';
2 | export { plugin as default } from './plugin';
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/src/plugin.ts:
--------------------------------------------------------------------------------
1 | import {
2 | coreServices,
3 | createBackendPlugin,
4 | } from '@backstage/backend-plugin-api';
5 | import { createRouter } from './service/router';
6 |
7 | /**
8 | * ${{values.plugin_id}}Plugin backend plugin
9 | *
10 | * @public
11 | */
12 | export const plugin = createBackendPlugin({
13 | pluginId: '${{values.plugin_id}}',
14 | register(env) {
15 | env.registerInit({
16 | deps: {
17 | httpRouter: coreServices.httpRouter,
18 | logger: coreServices.logger,
19 | config: coreServices.rootConfig,
20 | httpAuth: coreServices.httpAuth,
21 | discovery: coreServices.discovery,
22 | },
23 | async init({ httpRouter, logger, config, httpAuth, discovery }) {
24 | logger.info('${{values.plugin_id}} plugin :: init');
25 | httpRouter.use(
26 | await createRouter({
27 | logger,
28 | config,
29 | httpAuth,
30 | discovery
31 | }),
32 | );
33 | httpRouter.addAuthPolicy({
34 | path: '/health',
35 | allow: 'unauthenticated',
36 | });
37 | },
38 | });
39 | },
40 | });
41 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/src/service/router.test.ts:
--------------------------------------------------------------------------------
1 | import { mockServices } from '@backstage/backend-test-utils';
2 | import express from 'express';
3 | import request from 'supertest';
4 |
5 | import { createRouter } from './router';
6 |
7 | describe('createRouter', () => {
8 | let app: express.Express;
9 |
10 | beforeAll(async () => {
11 | const router = await createRouter({
12 | logger: mockServices.logger.mock(),
13 | config: mockServices.rootConfig(),
14 | discovery: mockServices.discovery(),
15 | httpAuth: mockServices.httpAuth(),
16 | });
17 | app = express().use(router);
18 | });
19 |
20 | beforeEach(() => {
21 | jest.resetAllMocks();
22 | });
23 |
24 | describe('GET /health', () => {
25 | it('returns ok', async () => {
26 | const response = await request(app).get('/health');
27 |
28 | expect(response.status).toEqual(200);
29 | expect(response.body).toEqual({ status: 'ok' });
30 | });
31 | });
32 |
33 | describe('GET /hello', () => {
34 | it('returns 200', async () => {
35 | const response = await request(app).get('/hello');
36 |
37 | expect(response.status).toEqual(200);
38 | expect(response.body).toEqual({ message: 'Hello user:default/mock' });
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/src/service/router.ts:
--------------------------------------------------------------------------------
1 | import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';
2 | import { createLegacyAuthAdapters } from '@backstage/backend-common';
3 | import {
4 | DiscoveryService,
5 | HttpAuthService,
6 | LoggerService,
7 | } from '@backstage/backend-plugin-api';
8 | import { Config } from '@backstage/config';
9 | import express from 'express';
10 | import Router from 'express-promise-router';
11 |
12 | export interface RouterOptions {
13 | logger: LoggerService;
14 | config: Config;
15 | discovery: DiscoveryService;
16 | httpAuth?: HttpAuthService;
17 | }
18 |
19 | export async function createRouter(
20 | options: RouterOptions,
21 | ): Promise {
22 | const { logger, config } = options;
23 | const { httpAuth } = createLegacyAuthAdapters(options);
24 |
25 | const router = Router();
26 | router.use(express.json());
27 | router.get('/health', async (_, res) => res.json({ status: 'ok' }));
28 |
29 | router.get('/hello', async (req, res) => {
30 | const caller = await httpAuth.credentials(req, { allow: ['user'] });
31 | res.json({ message: `Hello ${caller.principal.userEntityRef}` });
32 | });
33 |
34 | const middleware = MiddlewareFactory.create({ logger, config });
35 |
36 | router.use(middleware.error());
37 | return router;
38 | }
39 |
--------------------------------------------------------------------------------
/templates/create-backend-plugin/skeleton/plugins/${{values.plugin_id}}-backend/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | export {};
2 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/docs/features/api.md:
--------------------------------------------------------------------------------
1 | # Guide to Consuming APIs in your UI Components
2 |
3 | The ExampleFetchComponent demonstrates the common task of making an asynchronous request to a public API and displaying the response data in a table using Backstage components.
4 |
5 | You can modify these components, rename them, or replace them entirely.
6 |
7 | To consume APIs from your backend plugin, follow these steps:
8 |
9 | - Create an `api` folder under your `src` directory and add a client file for making API calls. The file name should follow the format `BackendClient.ts`.
10 |
11 | The file structure should be as follows:
12 |
13 | ```ts title="BackendClient.ts"
14 | import {
15 | ConfigApi,
16 | createApiRef,
17 | IdentityApi,
18 | } from '@backstage/core-plugin-api';
19 |
20 | // @public
21 | export type API = {
22 | getUsers: () => Promise<{ status: string } | Response>;
23 | };
24 |
25 | export type Options = {
26 | configApi: ConfigApi;
27 | identityApi: IdentityApi;
28 | };
29 |
30 | // @public
31 | export const ApiRef = createApiRef<API>({
32 | id: 'plugin..service',
33 | });
34 |
35 | export class BackendClient implements API {
36 |
37 | private readonly configApi: ConfigApi;
38 | private readonly identityApi: IdentityApi;
39 |
40 | constructor(options: Options) {
41 | this.configApi = options.configApi;
42 | this.identityApi = options.identityApi;
43 | }
44 |
45 | async getUsers() {
46 | const { token: idToken } = await this.identityApi.getCredentials();
47 | const backendUrl = this.configApi.getString('backend.baseUrl');
48 | const jsonResponse = await fetch(`${backendUrl}/api//`, {
49 | headers: {
50 | ...(idToken && { Authorization: `Bearer ${idToken}` }),
51 | },
52 | });
53 | return jsonResponse.json();
54 | }
55 | }
56 | ```
57 |
58 | - After creating the client, consume the APIs in your components:
59 |
60 | ```ts title="ExampleFetchComponent.tsx"
61 | export const ExampleFetchComponent = () => {
62 | const theme = useTheme();
63 | const chipStyle = getChipStyle(theme);
64 | const pluginApi = useApi(ApiRef); // use the api ref created in the client file
65 | const users = pluginApi.getUsers();
66 | const columns: TableColumn[] = [
67 | { title: 'Column title 1', field: 'column-field-1' },
68 | { title: 'Column title 2', field: 'column-field-2' },
69 | { title: 'Column title 3', field: 'column-field-3' },
70 | ];
71 |
72 | const data = users.map((user: any) => {
73 | // prepare your table data here
74 | });
75 |
76 | return (
77 |
83 | );
84 | };
85 | ```
86 |
87 | You may customize the components as needed to fit your requirements.
88 |
89 | ## References
90 |
91 | - [RBAC frontend plugin](https://github.com/backstage/community-plugins/tree/main/workspaces/rbac/plugins/rbac)
92 | - [Orchestrator frontend plugin](https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator)
93 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/docs/features/dynamic-plugin.md:
--------------------------------------------------------------------------------
1 | # Guide to Dynamic Plugin Enablement
2 |
3 | To be able to run your frontend plugin as a dynamic plugin on Red Hat Developer Hub, follow the steps below:
4 |
5 | - To build the plugin and the dynamic entrypoint:
6 |
7 | `yarn install`
8 |
9 | `yarn tsc`
10 |
11 | `yarn build`
12 |
13 | `yarn export-dynamic`
14 |
15 | - To install the dynamic plugin from a local build and run it in a local instance of backstage-showcase:
16 |
17 | ```bash
18 | cd dist-scalprum
19 | npm pack .
20 | archive=$(npm pack $pkg)
21 | tar -xzf "$archive" && rm "$archive"
22 | mv package $(echo $archive | sed -e 's:\.tgz$::')
23 | ```
24 |
25 | - Move the resulting directory (red-hat-developer-hub.backstage-plugin--) into the `dynamic-plugins-root` folder of your backstage-showcase clone, then run yarn start to start the app.
26 |
27 | - This configuration will then enable the plugin to be visible in the UI:
28 |
29 | ```yaml
30 | dynamicPlugins:
31 | frontend:
32 | red-hat-developer-hub.backstage-plugin-:
33 | appIcons:
34 | - name: PluginIcon
35 | importName: PluginIcon
36 | dynamicRoutes:
37 | - path: /
38 | importName: PluginPage
39 | menuItem:
40 | icon: PluginIcon
41 | text:
42 | ```
43 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/docs/features/theme.md:
--------------------------------------------------------------------------------
1 | # Guide to Integrating Theme in your UI Components
2 |
3 | You can customzie your application's response to light and dark modes using themes. Additionally, you can make use of theme to change the color palatte, typography size, font, and more.
4 |
5 | Backstage upstream ships with a “unified theme interface” that acts as a thin layer over Material theming, adding additional Backstage specific components and concerns to the underlying Material theming framework. This interface supports two versions of Material theming: v4 and v5.
6 |
7 | The theme set on the development backstage app isn’t set or available for any of the individual development setups, for example running the development setup for a plugin in the default light or dark upstream theme. Ideally, each of these development environments could pull in the same theme file so that regardless of how a given plugin UI is developed the developer is able to work with a consistent theme where UI components lay out and behave as expected. Fortunately, the `createDevApp` API that these environments rely on can also accept new themes.
8 |
9 | ```ts
10 | createDevApp()
11 | .addThemes([
12 | {
13 | id: "my-theme",
14 | title: "My Custom Theme",
15 | variant: "light",
16 | icon: ,
17 | Provider: ({ children }) => (
18 |
19 | ),
20 | },
21 | ])
22 | .registerApi({
23 | // Additional code
24 | });
25 | ```
26 |
27 | `myTheme` would look like this:
28 |
29 | ```ts title="myTheme.ts"
30 | import {
31 | createBaseThemeOptions,
32 | createUnifiedTheme,
33 | palettes,
34 | } from "@backstage/theme";
35 |
36 | export const myTheme = createUnifiedTheme({
37 | ...createBaseThemeOptions({
38 | palette: {
39 | ...palettes.light,
40 | background: {
41 | default: "#d5d6db",
42 | paper: "#d5d6db",
43 | },
44 | banner: {
45 | info: "#34548a",
46 | error: "#8c4351",
47 | text: "#343b58",
48 | link: "#565a6e",
49 | },
50 | navigation: {
51 | background: "#343b58",
52 | indicator: "#8f5e15",
53 | color: "#d5d6db",
54 | selectedColor: "#ffffff",
55 | },
56 | },
57 | }),
58 | fontFamily: "Comic Sans MS",
59 | });
60 | ```
61 |
62 | The `ExampleFetchComponent` leverages themes to alter the chip styles accordingly:
63 |
64 | ```ts title="ExampleFetchComponent.tsx"
65 | import { Theme } from "@material-ui/core";
66 | import { useTheme } from "@material-ui/core/styles";
67 |
68 | export const getChipStyle = (theme: Theme) => {
69 | return {
70 | backgroundColor: theme.palette.type === "dark" ? "#3d5061" : "#e7f1fa",
71 | };
72 | };
73 |
74 | export const DenseTable = ({ users }: any) => {
75 | const theme = useTheme();
76 | const chipStyle = getChipStyle(theme);
77 |
78 | const data = users.map((user: any) => {
79 | return {
80 | id: user.login,
81 | githubId: (
82 | }
85 | label={user.login}
86 | variant="outlined"
87 | />
88 | ),
89 | repoUrl: user.html_url,
90 | type: user.type,
91 | };
92 | });
93 |
94 | // Additional code
95 | };
96 | ```
97 |
98 | For more details on theming, refer to the [official documentation](https://backstage.io/docs/getting-started/app-custom-theme)
99 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/docs/index.md:
--------------------------------------------------------------------------------
1 | # Guide to kickstart frontend plugin development
2 |
3 | This Software Template guides you to kickstart your frontend plugin development with fewer clicks.
4 |
5 | Note: The template allows only `github.com` as host
6 |
7 | ## Getting started
8 |
9 | This template gathers essential information from the user, such as the plugin ID, repository owner, and the repository name. It then checks if the repository already exists or if the user wants to create a new one. Upon execution, the template generates a folder structure with all the necessary files, dependencies, UI components, and unit tests to help you get started. This same folder structure is also created when you run `yarn new --select plugin` using the [Backstage CLI](https://backstage.io/docs/tooling/cli/commands#new). The template includes examples of how to fetch data from external sources, utilizing [Backstage components](https://backstage.io/storybook/), [Material UI](https://mui.com/material-ui/) and [Backstage Theme](https://backstage.io/docs/getting-started/app-custom-theme/).
10 |
11 | For more details on plugin development, check out the official [Backstage documentation](https://backstage.io/docs/plugins/).
12 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: "Create Frontend Plugin Template"
2 | site_description: "User documentation for creating a frontend plugin"
3 |
4 | nav:
5 | - Introduction: index.md
6 | - Consuming APIs in your UI Components: features/api.md
7 | - Enforcing Access Controls in your Frontend Plugin: features/rbac.md
8 | - Integrating Theme in your UI Components: features/theme.md
9 | - Dynamic Plugin Enablement: features/dynamic-plugin.md
10 |
11 | plugins:
12 | - techdocs-core
13 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
2 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/README.md:
--------------------------------------------------------------------------------
1 | # ${{values.plugin_id}}
2 |
3 | Welcome to the ${{values.plugin_id}} plugin!
4 |
5 | _This plugin was created through the Software Template. Please ensure you run it within your Backstage plugin's workspace._
6 |
7 |
8 | ## Getting started
9 |
10 | 1. Go to the plugin directory and run `yarn install`
11 |
12 |
13 | ### To access the plugin in isolation:
14 |
15 | 1. Go to the plugin directory
16 |
17 | 2. Run `yarn start`
18 |
19 | This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
20 | It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
21 |
22 |
23 | ### To access the plugin from your Backstage plugin's workspace:
24 |
25 |
26 | 1. Add the package in the `packages/app/package.json`
27 |
28 | ```
29 | "@red-hat-developer-hub/backstage-plugin-${{values.plugin_id}}": "^0.1.0",
30 | ```
31 |
32 |
33 | 2. Add Route in `packages/app/src/App.tsx`:
34 |
35 | ```tsx title="packages/app/src/App.tsx"
36 | /* highlight-add-next-line */
37 | import { PluginPage } from '@red-hat-developer-hub/backstage-plugin-${{values.plugin_id}}';
38 |
39 | } />
40 | ```
41 |
42 | 3. Add your plugin as a Sidebar Item in `packages/app/src/components/Root/Root.tsx`:
43 |
44 | ```tsx title="packages/app/src/components/Root/Root.tsx"
45 | /* highlight-add-next-line */
46 | import { PluginIcon } from '@red-hat-developer-hub/backstage-plugin-${{values.plugin_id}}';
47 |
48 | export const Root = ({ children }: PropsWithChildren<{}>) => (
49 |
50 |
51 | ...
52 |
53 | ...
54 |
55 |
56 | );
57 | ```
58 |
59 | 4. Set-up the Backstage Proxy. Follow https://backstage.io/docs/integrations/github/locations#token-scopes for creating personal access token
60 |
61 | ```yaml title="app-config.yaml"
62 | proxy:
63 | ...
64 | '/github':
65 | target: 'https://api.github.com'
66 | headers:
67 | Authorization: 'token ${GITHUB_TOKEN}'
68 | ```
69 |
70 | 5. Start your application from `workspaces/`, and then navigate to [/${{values.plugin_id}}](http://localhost:3000/${{values.plugin_id}}).
71 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/catalog-info.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: Component
3 | metadata:
4 | name: ${{ values.plugin_id }}
5 | {%- if values.description %}
6 | description: ${{ values.description }}
7 | {%- endif %}
8 | annotations:
9 | backstage.io/techdocs-ref: dir:.
10 | github.com/project-slug: ${{ values.orgName }}/${{ values.repoName }}
11 | spec:
12 | type: website
13 | {%- if values.lifecycle %}
14 | lifecycle: ${{ values.lifecycle }}
15 | {%- else %}
16 | lifecycle: production
17 | {%- endif %}
18 | owner: ${{ values.owner }}
19 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/dev/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { discoveryApiRef } from "@backstage/core-plugin-api";
3 | import { createDevApp } from "@backstage/dev-utils";
4 | import { TestApiProvider } from "@backstage/test-utils";
5 | import PermIdentityOutlinedIcon from "@mui/icons-material/PermIdentityOutlined";
6 | import { plugin, PluginPage } from "../src/plugin";
7 |
8 | const mockedDiscoveryApi = {
9 | getBaseUrl: async (_param: any) => {
10 | return "http://localhost:7007/api/proxy";
11 | },
12 | };
13 |
14 | createDevApp()
15 | .registerPlugin(plugin)
16 | .addPage({
17 | element: (
18 |
19 |
20 |
21 | ),
22 | title: "${{values.plugin_id}}",
23 | path: "/${{values.plugin_id}}",
24 | icon: () => ,
25 | })
26 | .render();
27 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@red-hat-developer-hub/backstage-plugin-${{values.plugin_id}}",
3 | "version": "0.1.0",
4 | "main": "src/index.ts",
5 | "types": "src/index.ts",
6 | "license": "Apache-2.0",
7 | "private": true,
8 | "publishConfig": {
9 | "access": "public",
10 | "main": "dist/index.esm.js",
11 | "types": "dist/index.d.ts"
12 | },
13 | "backstage": {
14 | "role": "frontend-plugin"
15 | },
16 | "sideEffects": false,
17 | "scripts": {
18 | "build": "backstage-cli package build",
19 | "clean": "backstage-cli package clean",
20 | "lint:check": "backstage-cli package lint",
21 | "lint:fix": "backstage-cli package lint --fix",
22 | "postpack": "backstage-cli package postpack",
23 | "prepack": "backstage-cli package prepack",
24 | "start": "backstage-cli package start",
25 | "test": "backstage-cli package test --passWithNoTests --coverage",
26 | "tsc": "tsc",
27 | "prettier:check": "prettier --ignore-unknown --check .",
28 | "prettier:fix": "prettier --ignore-unknown --write .",
29 | "ui-test": "start-server-and-test start localhost:3000 'playwright test'"
30 | },
31 | "dependencies": {
32 | "@backstage/core-components": "^0.14.9",
33 | "@backstage/core-plugin-api": "^1.9.3",
34 | "@backstage/theme": "^0.5.6",
35 | "@material-ui/core": "^4.9.13",
36 | "@material-ui/icons": "^4.9.1",
37 | "@material-ui/lab": "^4.0.0-alpha.61",
38 | "@mui/icons-material": "^5.16.7",
39 | "react-use": "^17.2.4"
40 | },
41 | "peerDependencies": {
42 | "react": "16.13.1 || ^17.0.0 || ^18.0.0",
43 | "react-router-dom": "^6.0.0"
44 | },
45 | "devDependencies": {
46 | "@backstage/cli": "0.26.11",
47 | "@backstage/core-app-api": "1.14.0",
48 | "@backstage/dev-utils": "1.0.35",
49 | "@backstage/test-utils": "1.5.8",
50 | "@testing-library/jest-dom": "6.0.0",
51 | "@testing-library/react": "14.0.0",
52 | "@testing-library/user-event": "14.0.0",
53 | "msw": "1.0.0"
54 | },
55 | "files": [
56 | "dist",
57 | "dist-scalprum",
58 | "app-config.yaml"
59 | ],
60 | "repository": {
61 | "type": "git",
62 | "url": "${{values.repoUrl}}",
63 | "directory": "${{values.plugin_id}}"
64 | },
65 | "keywords": [
66 | "backstage",
67 | "plugin"
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleComponent/ExampleComponent.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ExampleComponent } from './ExampleComponent';
3 | import { rest } from 'msw';
4 | import { setupServer } from 'msw/node';
5 | import { screen } from '@testing-library/react';
6 | import {
7 | setupRequestMockHandlers,
8 | renderInTestApp,
9 | } from "@backstage/test-utils";
10 |
11 | describe('ExampleComponent', () => {
12 | const server = setupServer();
13 | // Enable sane handlers for network requests
14 | setupRequestMockHandlers(server);
15 |
16 | // setup mock response
17 | beforeEach(() => {
18 | server.use(
19 | rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))),
20 | );
21 | });
22 |
23 | it('should render', async () => {
24 | await renderInTestApp( );
25 | expect(screen.getByText('Welcome to ${{values.plugin_id}}!')).toBeInTheDocument();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleComponent/ExampleComponent.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Typography, Grid, makeStyles } from "@material-ui/core";
3 | import {
4 | InfoCard,
5 | Header,
6 | Page,
7 | Content,
8 | ContentHeader,
9 | HeaderLabel,
10 | SupportButton,
11 | } from "@backstage/core-components";
12 | import { ExampleFetchComponent } from "../ExampleFetchComponent";
13 |
14 | const usePaperStyles = makeStyles((theme) => ({
15 | body: {
16 | backgroundColor: theme.palette.background.paper,
17 | },
18 | }));
19 |
20 | export const ExampleComponent = () => {
21 | const classes = usePaperStyles();
22 | return (
23 |
24 |
31 |
32 |
33 | A description of your plugin goes here.
34 |
35 |
36 |
37 |
38 |
39 | All content should be wrapped in a card like this.
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleComponent/index.ts:
--------------------------------------------------------------------------------
1 | export { ExampleComponent } from './ExampleComponent';
2 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleComponentIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { SidebarItem } from '@backstage/core-components';
4 | import PermIdentityOutlinedIcon from '@mui/icons-material/PermIdentityOutlined';
5 | import { IconComponent } from '@backstage/core-plugin-api';
6 |
7 |
8 | export const ExampleComponentIcon = () => {
9 |
10 | return (
11 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import { ExampleFetchComponent } from './ExampleFetchComponent';
4 |
5 | describe('ExampleFetchComponent', () => {
6 | it('renders the user table', async () => {
7 | render( );
8 |
9 | // Wait for the table to render
10 | const table = await screen.findByRole('table');
11 | const nationality = screen.getAllByText("GB")
12 | // Assert that the table contains the expected user data
13 | expect(table).toBeInTheDocument();
14 | expect(screen.getByAltText('Carolyn')).toBeInTheDocument();
15 | expect(screen.getByText('Carolyn Moore')).toBeInTheDocument();
16 | expect(screen.getByText('carolyn.moore@example.com')).toBeInTheDocument();
17 | expect(nationality[0]).toBeInTheDocument();
18 | });
19 | });
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import useAsync from "react-use/lib/useAsync";
3 | import {
4 | Table,
5 | TableColumn,
6 | Progress,
7 | ResponseErrorPanel,
8 | } from "@backstage/core-components";
9 | import { discoveryApiRef, fetchApiRef, useApi } from "@backstage/core-plugin-api";
10 | import { Avatar, Chip } from "@material-ui/core";
11 | import { useTheme } from "@material-ui/core/styles";
12 | import { getChipStyle } from "../../utils/getChipStyle";
13 |
14 | type User = {
15 | repoUrl: string;
16 | githubId: string;
17 | type: string;
18 | };
19 |
20 | export const DenseTable = ({ users }: any) => {
21 | const theme = useTheme();
22 | const chipStyle = getChipStyle(theme);
23 | const columns: TableColumn[] = [
24 | { title: "GithubId", field: "githubId" },
25 | { title: "Repository URL", field: "repoUrl" },
26 | { title: "Type", field: "type" },
27 | ];
28 |
29 | const data = users.map((user: any) => {
30 | return {
31 | id: user.login,
32 | githubId: (
33 | }
36 | label={user.login}
37 | variant="outlined"
38 | />
39 | ),
40 | repoUrl: user.html_url,
41 | type: user.type,
42 | };
43 | });
44 |
45 | return (
46 |
52 | );
53 | };
54 |
55 | export const ExampleFetchComponent = () => {
56 | const discoveryApi = useApi(discoveryApiRef);
57 | const proxyURL = discoveryApi.getBaseUrl("proxy");
58 | const fetchApi = useApi(fetchApiRef);
59 |
60 | const { value, loading, error } = useAsync(async (): Promise => {
61 | const res = await fetchApi.fetch(`${await proxyURL}/github/users`);
62 | if (!res.ok) throw new Error(res.statusText || "Error occured");
63 | const users = await res.json();
64 | return users;
65 | }, []);
66 |
67 | if (loading) {
68 | return ;
69 | } else if (error) {
70 | return ;
71 | }
72 |
73 | return ;
74 | };
75 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/ExampleFetchComponent/index.ts:
--------------------------------------------------------------------------------
1 | export { ExampleFetchComponent } from './ExampleFetchComponent';
2 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/Router.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, Routes } from 'react-router-dom';
3 |
4 | import { ExampleComponent } from './ExampleComponent';
5 |
6 | /**
7 | *
8 | * @public
9 | */
10 | export const Router = () => (
11 |
12 | } />
13 |
14 | );
15 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export { Router } from './Router';
2 | export * from './ExampleComponent';
3 | export { ExampleComponentIcon } from './ExampleComponentIcon';
4 |
5 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/index.ts:
--------------------------------------------------------------------------------
1 | export { plugin, PluginPage, PluginIcon } from './plugin';
2 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/plugin.test.ts:
--------------------------------------------------------------------------------
1 | import { plugin } from './plugin';
2 |
3 | describe('${{values.plugin_id}}', () => {
4 | it('should export plugin', () => {
5 | expect(plugin).toBeDefined();
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/plugin.ts:
--------------------------------------------------------------------------------
1 | import {
2 | createComponentExtension,
3 | createPlugin,
4 | createRoutableExtension,
5 | } from '@backstage/core-plugin-api';
6 |
7 | import { rootRouteRef } from './routes';
8 |
9 | export const plugin = createPlugin({
10 | id: '${{values.plugin_id}}',
11 | routes: {
12 | root: rootRouteRef,
13 | },
14 | });
15 |
16 | export const PluginPage = plugin.provide(
17 | createRoutableExtension({
18 | name: 'PluginPage',
19 | component: () =>
20 | import('./components').then(m => m.Router),
21 | mountPoint: rootRouteRef,
22 | }),
23 | );
24 |
25 | export const PluginIcon = plugin.provide(
26 | createComponentExtension({
27 | name: 'PluginIcon',
28 | component: {
29 | lazy: () => import('./components').then(m => m.ExampleComponentIcon),
30 | },
31 | }),
32 | );
33 |
34 |
35 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/routes.ts:
--------------------------------------------------------------------------------
1 | import { createRouteRef } from '@backstage/core-plugin-api';
2 |
3 | export const rootRouteRef = createRouteRef({
4 | id: '${{values.plugin_id}}',
5 | });
6 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 |
--------------------------------------------------------------------------------
/templates/create-frontend-plugin/skeleton/plugins/${{values.plugin_id}}/src/utils/getChipStyle.ts:
--------------------------------------------------------------------------------
1 | import { Theme } from "@material-ui/core";
2 |
3 | export const getChipStyle = (theme: Theme) => {
4 | return {
5 | backgroundColor: theme.palette.type === "dark" ? "#3d5061" : "#e7f1fa",
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/templates/github/argocd/README.md:
--------------------------------------------------------------------------------
1 | # Add ArgoCD to an existing project
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/backstage-system/skeleton/all.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: Location
3 | metadata:
4 | name: ${{ values.repoName }}-entities
5 | description: A collection of all the ${{ values.repoName }} entities
6 | spec:
7 | targets:
8 | - ./systems.yaml
9 |
--------------------------------------------------------------------------------
/templates/github/backstage-system/skeleton/systems.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: Location
3 | metadata:
4 | name: ${{ values.repoName }}-systems
5 | description: A collection of all ${{ values.repoName }} systems
6 | spec:
7 | targets:
8 | - ./systems/${{ values.systemName }}.yaml
9 |
--------------------------------------------------------------------------------
/templates/github/backstage-system/skeleton/systems/${{ values.systemName }}.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: System
3 | metadata:
4 | name: ${{ values.systemName }}
5 | title: ${{ values.systemTitle }}
6 | spec:
7 | owner: ${{ values.owner }}
8 |
--------------------------------------------------------------------------------
/templates/github/backstage-system/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: backstage-system-template
5 | title: Create a Backstage System entity
6 | description: Create a Backstage System entity
7 | tags:
8 | - backstage
9 | - system
10 | spec:
11 | owner: janus-authors
12 | system: janus-idp
13 | type: service
14 |
15 | parameters:
16 | - title: Provide information about the new component
17 | required:
18 | - orgName
19 | - repoName
20 | - owner
21 | - systemName
22 | - systemTitle
23 | properties:
24 | orgName:
25 | title: GitHub Organization
26 | type: string
27 | repoName:
28 | title: Repository Name
29 | type: string
30 | owner:
31 | title: Owner
32 | type: string
33 | ui:field: EntityPicker
34 | ui:options:
35 | catalogFilter:
36 | kind:
37 | - Group
38 | - User
39 | systemName:
40 | title: System Name
41 | type: string
42 | systemTitle:
43 | title: System Title
44 | type: string
45 | steps:
46 | - id: sourceCodeTemplate
47 | name: Generating the Source Code Component
48 | action: fetch:template
49 | input:
50 | url: ./skeleton
51 | values:
52 | orgName: ${{ parameters.orgName }}
53 | repoName: ${{ parameters.repoName }}
54 | owner: ${{ parameters.owner }}
55 | systemName: ${{ parameters.systemName }}
56 | systemTitle: ${{ parameters.systemTitle }}
57 |
58 | - id: publish
59 | name: Publishing to the Source Code Repository
60 | action: publish:github
61 | input:
62 | allowedHosts: ['github.com']
63 | repoUrl: github.com?owner=${{ parameters.orgName }}&repo=${{ parameters.repoName }}
64 | defaultBranch: main
65 |
66 | - id: register
67 | name: Registering the Catalog Info Component
68 | action: catalog:register
69 | input:
70 | repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
71 | catalogInfoPath: /all.yaml
72 |
73 | output:
74 | links:
75 | - title: Open the Source Code Repository
76 | url: ${{ steps.publish.output.remoteUrl }}
77 | - title: Open the Catalog Info Component
78 | icon: catalog
79 | entityRef: ${{ steps.register.output.entityRef }}
80 |
--------------------------------------------------------------------------------
/templates/github/define-ansible-job/README.md:
--------------------------------------------------------------------------------
1 | # Launch an Ansible Automation Platform Job Template
2 | This template requires a secret to be defined that provides the URL for Ansible Automation Platform as well as a token to interact with Ansible Automation Platform.
3 |
4 | * Generate a Write token within AAP https://docs.ansible.com/automation-controller/4.1.0/html/userguide/applications_auth.html#add-tokens
5 | * Manually create a Kubernetes Secret or create a secret using a secure secret solution such as Vault
6 |
7 | Provide the value of token and host as it relates to your environment.
8 | ```
9 | kubectl create secret generic aapaccess -n aap --from-literal=token=$TOKEN --from-literal=host=$AAP_URL
10 | ```
11 |
12 | Once this secret has been generated on the cluster it is now possible to define an Ansible Job template.
13 |
--------------------------------------------------------------------------------
/templates/github/define-ansible-job/skeleton/${{values.component_id}}-job-template.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: tower.ansible.com/v1alpha1
3 | kind: JobTemplate
4 | metadata:
5 | name: ${{ values.name }}-job-template
6 | namespace: ${{ values.namespace }}
7 | spec:
8 | tower_auth_secret: ${{ values.connection_secret }}
9 | job_template_name: ${{ values.name }}
10 | job_template_project: ${{ values.project }}
11 | ask_variables_on_launch: ${{ values.ask_vars_on_launch }}
12 | job_template_playbook: ${{ values.playbook }}
13 | job_template_inventory: ${{ values.inventory }}
14 | job_template_credentials: ${{ values.credential }}
15 | job_template_extra_vars:
16 | ${{ values.extra_vars }}
--------------------------------------------------------------------------------
/templates/github/define-ansible-job/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: define-ansible-job-template
5 | title: Ansible Job Template
6 | description: Define an Ansible Job Template within Ansible Automation Platform
7 | tags:
8 | - recommended
9 | - aap
10 | spec:
11 | owner: janus-authors
12 | system: janus-idp
13 | type: service
14 | parameters:
15 | - title: Provide information about the GitHub location
16 | required:
17 | - githubOrg
18 | - repoName
19 | - owner
20 | - system
21 | properties:
22 | githubOrg:
23 | title: GitHub Organization
24 | type: string
25 | owner:
26 | title: Owner
27 | type: string
28 | description: Owner of the component
29 | repoName:
30 | title: Repository Name
31 | type: string
32 | system:
33 | title: System
34 | type: string
35 | ui:field: EntityPicker
36 | ui:options:
37 | catalogFilter:
38 | kind:
39 | - System
40 | - title: Ansible Job Definition
41 | required:
42 | - name
43 | - description
44 | - namespace
45 | - inventory
46 | - project
47 | - playbook
48 | - ask_vars_on_launch
49 | properties:
50 | name:
51 | title: Name of the Ansible Job Template
52 | type: string
53 | description: A unique name for the Ansible Job Template
54 | playbook:
55 | title: Ansible Playbook
56 | type: string
57 | description: Specify an Ansible Playbook to run
58 | description:
59 | title: Description
60 | type: string
61 | description: Provide a description of the Job Template to be defined
62 | namespace:
63 | title: Namespace
64 | type: string
65 | description: Specify the namespace to launch the job
66 | default: aap
67 | inventory:
68 | title: Inventory
69 | type: string
70 | description: Specify the inventory to use for the job
71 | default: aap
72 | project:
73 | title: Project
74 | type: string
75 | description: Specify the Ansible Project to use for the job
76 | default: aap
77 | credential:
78 | title: Credential
79 | type: string
80 | description: Specify the credential to use for the job
81 | default: aap
82 | connection_secret:
83 | title: Connection Secret
84 | type: string
85 | description: Specify the connection secret to use for the job
86 | default: aapaccess
87 | extra_vars:
88 | title: Extra Vars
89 | type: string
90 | description: Specify any extra vars to use for the job template
91 | ui:widget: textarea
92 | ui:options:
93 | rows: 15
94 | ask_vars_on_launch:
95 | title: Ask Vars on Launch
96 | type: boolean
97 | description: Specify whether to ask for extra vars on launch
98 | default: false
99 | steps:
100 | - id: template
101 | name: Generating the source code component
102 | action: fetch:template
103 | input:
104 | url: ./skeleton
105 | targetPath: argo/ansibleJobTemplates/
106 | values:
107 | component_id: ${{ parameters.name }}
108 | name: ${{ parameters.name }}
109 | namespace: ${{ parameters.namespace }}
110 | inventory: ${{ parameters.inventory }}
111 | credential: ${{ parameters.credential }}
112 | project: ${{ parameters.project }}
113 | playbook: ${{ parameters.playbook }}
114 | connection_secret: ${{ parameters.connection_secret }}
115 | extra_vars: ${{ parameters.extra_vars }}
116 | ask_vars_on_launch: ${{ parameters.ask_vars_on_launch }}
117 |
118 | - id: catalogTemplate
119 | name: Generating the Catalog Info Component
120 | action: fetch:template
121 | input:
122 | url: ../../../skeletons/catalog-info/
123 | values:
124 | githubOrg: ${{ parameters.githubOrg }}
125 | repoName: ${{ parameters.repoName }}
126 | owner: ${{ parameters.owner }}
127 | applicationType: api
128 | description: ${{ parameters.description }}
129 |
130 | - id: publish
131 | name: Publishing to Source Code Repository
132 | action: publish:github:pull-request
133 | input:
134 | allowedHosts: ['github.com']
135 | title: ${{ parameters.name }}-job-tmp
136 | description: ${{ parameters.name }}-job-tmp
137 | repoUrl: github.com?owner=${{ parameters.githubOrg }}&repo=${{ parameters.repoName }}
138 | branchName: ${{ parameters.name }}-job-tmp
139 |
140 | - id: register
141 | name: Registering the Catalog Info Component
142 | action: catalog:register
143 | input:
144 | repoContentsUrl: https://github.com/${{ parameters.githubOrg }}/${{ parameters.repoName }}/blob/${{ steps.publish.output.targetBranchName }}
145 | catalogInfoPath: /catalog-info.yaml
146 | optional: true
147 |
148 | output:
149 | links:
150 | - title: Source Code Repository
151 | url: ${{ steps.publish.output.remoteUrl }}
152 | - title: Open the Catalog Info Component
153 | icon: catalog
154 | entityRef: ${{ steps.register.output.entityRef }}
155 |
--------------------------------------------------------------------------------
/templates/github/go-backend/README.md:
--------------------------------------------------------------------------------
1 | # Create a Go Backend application with a CI pipeline
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/go-backend/skeleton/.dockerignore:
--------------------------------------------------------------------------------
1 | README.md
2 | .git
3 | .env.local
4 |
--------------------------------------------------------------------------------
/templates/github/go-backend/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | # build
2 | main*
3 | !main.go
4 |
--------------------------------------------------------------------------------
/templates/github/go-backend/skeleton/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.access.redhat.com/ubi9/go-toolset:latest as runner
2 |
3 | COPY go.mod ./
4 | RUN go mod download
5 |
6 | COPY *.go ./
7 |
8 | RUN go build -o ./main
9 |
10 | ENV PORT ${{ values.port }}
11 | EXPOSE ${{ values.port }}
12 |
13 | CMD [ "./main" , "-p=8080"]
14 |
--------------------------------------------------------------------------------
/templates/github/go-backend/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # ${{ values.repoName }}
2 |
3 | ${{ values.description }}
4 |
5 | More information on the chosen CI method can be found [here](https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}/blob/main/CI.md).
6 |
--------------------------------------------------------------------------------
/templates/github/go-backend/skeleton/go.mod:
--------------------------------------------------------------------------------
1 | module ${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}
2 |
3 | go 1.16
4 |
--------------------------------------------------------------------------------
/templates/github/go-backend/skeleton/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "os"
7 | )
8 |
9 | func main() {
10 | port := os.Getenv("PORT")
11 |
12 | if port == "" {
13 | port = "${{ values.port }}"
14 | }
15 |
16 | http.HandleFunc("/", HelloServer)
17 | http.ListenAndServe(fmt.Sprintf("0.0.0.0:%s", port), nil)
18 | }
19 |
20 | func HelloServer(w http.ResponseWriter, r *http.Request) {
21 | fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
22 | }
23 |
--------------------------------------------------------------------------------
/templates/github/launch-ansible-job/README.md:
--------------------------------------------------------------------------------
1 | # Launch an Ansible Automation Platform Job
2 | This template requires a secret to be defined that provides the URL for Ansible Automation Platform as well as a token to interact with Ansible Automation Platform.
3 |
4 | * Generate a Write token within AAP https://docs.ansible.com/automation-controller/4.1.0/html/userguide/applications_auth.html#add-tokens
5 | * Manually create a Kubernetes Secret or create a secret using a secure secret solution such as Vault
6 |
7 | Provide the value of token and host as it relates to your environment.
8 | ```
9 | kubectl create secret generic aapaccess -n aap --from-literal=token=$TOKEN --from-literal=host=$AAP_URL
10 | ```
11 |
12 | Once this secret has been generated on the cluster it is now possible to use the Ansible Job template.
--------------------------------------------------------------------------------
/templates/github/launch-ansible-job/skeleton/${{values.component_id}}-job.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: tower.ansible.com/v1alpha1
3 | kind: AnsibleJob
4 | metadata:
5 | name: ${{ values.component_id }}-job
6 | namespace: ${{ values.namespace }}
7 | spec:
8 | connection_secret: ${{ values.connection_secret }}
9 | job_template_name: ${{ values.jobTemplate }}
10 | extra_vars: ${{ values.extra_vars }}
--------------------------------------------------------------------------------
/templates/github/launch-ansible-job/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: launch-ansible-job-template
5 | title: Ansible Job
6 | description: Launch an Ansible Job within Ansible Automation Platform
7 | tags:
8 | - recommended
9 | - aap
10 | spec:
11 | owner: janus-authors
12 | system: janus-idp
13 | type: service
14 | parameters:
15 | - title: Provide information about the GitHub location
16 | required:
17 | - orgName
18 | - repoName
19 | - owner
20 | - system
21 | properties:
22 | orgName:
23 | title: Organization Name
24 | type: string
25 | owner:
26 | title: Owner
27 | type: string
28 | description: Owner of the component
29 | repoName:
30 | title: Repository Name
31 | type: string
32 | system:
33 | title: System
34 | type: string
35 | ui:field: EntityPicker
36 | ui:options:
37 | catalogFilter:
38 | kind:
39 | - System
40 | - title: Ansible Job Definition
41 | required:
42 | - name
43 | - jobTemplate
44 | - description
45 | - namespace
46 | properties:
47 | name:
48 | title: Name of the Ansible Job
49 | type: string
50 | description: A unique name for the Ansible Job
51 | jobTemplate:
52 | title: Name of the Job Template to launch
53 | type: string
54 | description: Specify a job template to launch
55 | description:
56 | title: Description
57 | type: string
58 | description: Provide a description of the Job to be launched
59 | namespace:
60 | title: Namespace
61 | type: string
62 | description: Specify the namespace to launch the job
63 | default: aap
64 | connection_secret:
65 | title: Connection Secret
66 | type: string
67 | description: Specify the connection secret to use for the job
68 | default: aapaccess
69 | extra_vars:
70 | title: Extra Vars
71 | type: string
72 | description: Specify any extra vars to pass to the job
73 | default: {}
74 | ui:widget: textarea
75 | ui:options:
76 | rows: 15
77 | steps:
78 | - id: template
79 | name: Generating the source code component
80 | action: fetch:template
81 | input:
82 | url: ./skeleton
83 | targetPath: argo/ansibleJobs/
84 | values:
85 | component_id: ${{ parameters.name }}
86 | jobTemplate: ${{ parameters.jobTemplate }}
87 | name: ${{ parameters.name }}
88 | namespace: ${{ parameters.namespace }}
89 | connection_secret: ${{ parameters.connection_secret }}
90 | extra_vars: ${{ parameters.extra_vars }}
91 |
92 | - id: catalogTemplate
93 | name: Generating the Catalog Info Component
94 | action: fetch:template
95 | input:
96 | url: ../../../skeletons/catalog-info/
97 | values:
98 | orgName: ${{ parameters.orgName }}
99 | repoName: ${{ parameters.repoName }}
100 | owner: ${{ parameters.owner }}
101 | applicationType: api
102 | description: ${{ parameters.description }}
103 | sourceControl: github.com
104 |
105 | - id: publish
106 | name: Publishing to Source Code Repository
107 | action: publish:github:pull-request
108 | input:
109 | allowedHosts: ['github.com']
110 | title: ${{ parameters.name }}-job
111 | description: ${{ parameters.name }}-job
112 | repoUrl: github.com?owner=${{ parameters.orgName }}&repo=${{ parameters.repoName }}
113 | branchName: ${{ parameters.name }}-job
114 |
115 | - id: register
116 | name: Registering the Catalog Info Component
117 | action: catalog:register
118 | input:
119 | repoContentsUrl: https://github.com/${{ parameters.githubOrg }}/${{ parameters.repoName }}/blob/${{ steps.publish.output.targetBranchName }}
120 | catalogInfoPath: /catalog-info.yaml
121 | optional: true
122 |
123 | output:
124 | links:
125 | - title: Source Code Repository
126 | url: ${{ steps.publish.output.remoteUrl }}
127 | - title: Open the Catalog Info Component
128 | icon: catalog
129 | entityRef: ${{ steps.register.output.entityRef }}
130 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/README.md:
--------------------------------------------------------------------------------
1 | # Create a NodeJS Backend application with a CI pipeline
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/skeleton/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | README.md
4 | .git
5 | .env.local
6 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Diagnostic reports (https://nodejs.org/api/report.html)
6 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
7 |
8 | # Dependency directories
9 | node_modules/
10 |
11 | # dotenv environment variable files
12 | .env*
13 |
14 | # build
15 | dist/
16 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/skeleton/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1 - Install dependencies
2 | FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:latest AS deps
3 |
4 | COPY package.json package-lock.json ./
5 | RUN npm ci
6 |
7 | # Stage 2 - Build the source code
8 | FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:latest AS builder
9 |
10 | COPY . .
11 | COPY --from=deps /opt/app-root/src/node_modules ./node_modules
12 |
13 | USER root
14 | RUN npm run build
15 |
16 | # Stage 3 - Production image, copy all the files and start NodeJS
17 | FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:latest AS runner
18 |
19 | COPY --from=deps --chown=1001:1001 /opt/app-root/src .
20 | COPY --from=builder --chown=1001:1001 /opt/app-root/src/dist ./dist
21 |
22 | ENV NODE_ENV production
23 |
24 | # Switch to nodejs user
25 | USER 1001
26 |
27 | # Install production dependencies
28 | RUN npm ci
29 |
30 | ENV PORT ${{ values.port }}
31 | EXPOSE ${{ values.port }}
32 |
33 | CMD ["npm", "run", "start"]
34 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # ${{ values.repoName }}
2 |
3 | ${{ values.description }}
4 |
5 | More information on the chosen CI method can be found [here](https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}/blob/main/CI.md).
6 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/skeleton/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "${{ values.repoName }}",
3 | "version": "1.0.0",
4 | "description": "${{ values.description }}",
5 | "scripts": {
6 | "build": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js",
7 | "start": "node dist/index.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "express": "~4.19.2"
14 | },
15 | "devDependencies": {
16 | "@types/node": "^18.11.9",
17 | "esbuild": "^0.17.11"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/templates/github/nodejs-backend/skeleton/src/index.ts:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const app = express()
3 | const router = express.Router()
4 |
5 | app.use(express.json())
6 | app.use(express.urlencoded({ extended: false }))
7 |
8 | router.get('/', function (req, res) {
9 | res.send('Hello World!')
10 | })
11 |
12 | app.use('/', router)
13 |
14 | const listenPort = process.env.PORT || ${{ values.port }};
15 |
16 | app.listen(listenPort)
17 | console.log(`Running at port ${listenPort}`)
18 |
--------------------------------------------------------------------------------
/templates/github/obc/README.md:
--------------------------------------------------------------------------------
1 | # Add OBC to an existing project
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/obc/skeleton/manifests/base/obc.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: objectbucket.io/v1alpha1
2 | kind: ObjectBucketClaim
3 | metadata:
4 | name: ${{ values.repoName }}-bucket-claim
5 | spec:
6 | generateBucketName: ${{ values.repoName }}-bucket-claim-
7 | storageClassName: ${{ values.storageClassName }}
8 |
--------------------------------------------------------------------------------
/templates/github/obc/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: obc-template
5 | title: Add OBC to an existing project
6 | description: Add OBC to an existing project
7 | tags:
8 | - obc
9 | spec:
10 | owner: janus-authors
11 | system: janus-idp
12 | type: service
13 |
14 | parameters:
15 | - title: Provide information about the existing component
16 | required:
17 | - orgName
18 | - repoName
19 | properties:
20 | orgName:
21 | title: Organization Name
22 | type: string
23 | repoName:
24 | title: Repository Name
25 | type: string
26 | - title: Provide information about the new component
27 | required:
28 | - owner
29 | - system
30 | - storageClassName
31 | properties:
32 | owner:
33 | title: Owner
34 | type: string
35 | ui:field: EntityPicker
36 | ui:options:
37 | catalogFilter:
38 | kind:
39 | - Group
40 | - User
41 | system:
42 | title: System
43 | type: string
44 | ui:field: EntityPicker
45 | ui:options:
46 | catalogFilter:
47 | kind:
48 | - System
49 | storageClassName:
50 | title: Storage Class Name
51 | type: string
52 | description: Storage Class Name of the OBC
53 | steps:
54 | - id: catalogTemplate
55 | name: Generating the Catalog Info Component
56 | action: fetch:template
57 | input:
58 | url: ../../../skeletons/catalog-info/
59 | values:
60 | # Gitops specific values
61 | entityKind: Resource
62 |
63 | # Normal values
64 | orgName: ${{ parameters.orgName }}
65 | repoName: ${{ parameters.repoName }}-gitops
66 | owner: ${{ parameters.owner }}
67 | system: ${{ parameters.system }}
68 | applicationType: gitops
69 | description: Contains the OBC manifests for ${{ parameters.repoName }}
70 | sourceControl: github.com
71 |
72 | - id: manifestsTemplate
73 | name: Generating the Manifests Component
74 | action: fetch:template
75 | input:
76 | url: ./template
77 | values:
78 | orgName: ${{ parameters.orgName }}
79 | repoName: ${{ parameters.repoName }}-gitops
80 | owner: ${{ parameters.owner }}
81 | system: ${{ parameters.system }}
82 | applicationType: gitops
83 | description: Contains the OBC manifests for ${{ parameters.repoName }}
84 | sourceControl: github.com
85 |
86 | - id: publish
87 | name: Publishing to the Source Code Repository
88 | action: publish:github
89 | input:
90 | allowedHosts: ['github.com']
91 | description: ${{ parameters.description }}
92 | repoUrl: github.com?owner=${{ parameters.orgName }}&repo=${{ parameters.repoName }}-gitops
93 | defaultBranch: main
94 |
95 | - id: register
96 | name: Registering the Catalog Info Component
97 | action: catalog:register
98 | input:
99 | repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
100 | catalogInfoPath: /catalog-info.yaml
101 |
102 | output:
103 | links:
104 | - title: Open the Source Code Repository
105 | url: ${{ steps.publish.output.remoteUrl }}
106 | - title: Open the Catalog Info Component
107 | icon: catalog
108 | entityRef: ${{ steps.register.output.entityRef }}
109 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/README.md:
--------------------------------------------------------------------------------
1 | # Create a Quarkus Backend application with a CI pipeline
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/.dockerignore:
--------------------------------------------------------------------------------
1 | !target/*-runner
2 | !target/*-runner.jar
3 | !target/lib/*
4 | !target/quarkus-app/*
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/.gitattributes:
--------------------------------------------------------------------------------
1 | * eol=lf
2 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | #Maven
2 | target/
3 | pom.xml.tag
4 | pom.xml.releaseBackup
5 | pom.xml.versionsBackup
6 | release.properties
7 |
8 | # Eclipse
9 | .project
10 | .classpath
11 | .settings/
12 | bin/
13 |
14 | # IntelliJ
15 | .idea
16 | *.ipr
17 | *.iml
18 | *.iws
19 |
20 | # NetBeans
21 | nb-configuration.xml
22 |
23 | # Visual Studio Code
24 | .vscode
25 | .factorypath
26 |
27 | # OSX
28 | .DS_Store
29 |
30 | # Vim
31 | *.swp
32 | *.swo
33 |
34 | # patch
35 | *.orig
36 | *.rej
37 |
38 | # Local environment
39 | .env
40 |
41 | .odo/env
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/Dockerfile:
--------------------------------------------------------------------------------
1 | ####
2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
3 | #
4 | # Before building the container image run:
5 | #
6 | # ./mvnw package
7 | #
8 | # Then, build the image with:
9 | #
10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/${{ values.artifactId }}-jvm .
11 | #
12 | # Then run the container using:
13 | #
14 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}-jvm
15 | #
16 | # If you want to include the debug port into your docker image
17 | # you will have to expose the debug port (default 5005 being the default) like this : EXPOSE ${{ values.port }} 5005.
18 | # Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
19 | # when running the container
20 | #
21 | # Then run the container using :
22 | #
23 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}-jvm
24 | #
25 | # This image uses the `run-java.sh` script to run the application.
26 | # This scripts computes the command line to execute your Java application, and
27 | # includes memory/GC tuning.
28 | # You can configure the behavior using the following environment properties:
29 | # - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
30 | # - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
31 | # in JAVA_OPTS (example: "-Dsome.property=foo")
32 | # - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
33 | # used to calculate a default maximal heap memory based on a containers restriction.
34 | # If used in a container without any memory constraints for the container then this
35 | # option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
36 | # of the container available memory as set here. The default is `50` which means 50%
37 | # of the available memory is used as an upper boundary. You can skip this mechanism by
38 | # setting this value to `0` in which case no `-Xmx` option is added.
39 | # - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
40 | # is used to calculate a default initial heap memory based on the maximum heap memory.
41 | # If used in a container without any memory constraints for the container then this
42 | # option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
43 | # of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
44 | # is used as the initial heap size. You can skip this mechanism by setting this value
45 | # to `0` in which case no `-Xms` option is added (example: "25")
46 | # - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
47 | # This is used to calculate the maximum value of the initial heap memory. If used in
48 | # a container without any memory constraints for the container then this option has
49 | # no effect. If there is a memory constraint then `-Xms` is limited to the value set
50 | # here. The default is 4096MB which means the calculated value of `-Xms` never will
51 | # be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
52 | # - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
53 | # when things are happening. This option, if set to true, will set
54 | # `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
55 | # - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
56 | # true").
57 | # - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
58 | # - CONTAINER_CORE_LIMIT: A calculated core limit as described in
59 | # https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
60 | # - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
61 | # - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
62 | # (example: "20")
63 | # - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
64 | # (example: "40")
65 | # - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
66 | # (example: "4")
67 | # - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
68 | # previous GC times. (example: "90")
69 | # - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
70 | # - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
71 | # - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
72 | # contain the necessary JRE command-line options to specify the required GC, which
73 | # will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
74 | # - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:${{ values.port }}")
75 | # - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:${{ values.port }}")
76 | # - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
77 | # accessed directly. (example: "foo.example.com,bar.example.com")
78 | #
79 | ###
80 | FROM registry.access.redhat.com/ubi8/openjdk-17:1.16
81 |
82 | ENV LANGUAGE='en_US:en'
83 |
84 |
85 | # We make four distinct layers so if there are application changes the library layers can be re-used
86 | COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
87 | COPY --chown=185 target/quarkus-app/*.jar /deployments/
88 | COPY --chown=185 target/quarkus-app/app/ /deployments/app/
89 | COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
90 |
91 | EXPOSE ${{ values.port }}
92 | USER 185
93 | ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
94 | ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
95 |
96 | ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
97 |
98 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # ${{ values.artifactId }}
2 |
3 | ${{ values.description }}
4 |
5 | More information on the chosen CI method can be found [here](https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}/blob/main/CI.md).
6 |
7 | If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
8 |
9 | ## Running the application in dev mode
10 |
11 | You can run your application in dev mode that enables live coding using:
12 | ```shell script
13 | ./mvnw compile quarkus:dev
14 | ```
15 |
16 | > **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/.
17 |
18 | ## Packaging and running the application
19 |
20 | The application can be packaged using:
21 | ```shell script
22 | ./mvnw package
23 | ```
24 | It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
25 | Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
26 |
27 | The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
28 |
29 | If you want to build an _über-jar_, execute the following command:
30 | ```shell script
31 | ./mvnw package -Dquarkus.package.type=uber-jar
32 | ```
33 |
34 | The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`.
35 |
36 | ## Creating a native executable
37 |
38 | You can create a native executable using:
39 | ```shell script
40 | ./mvnw package -Dnative
41 | ```
42 |
43 | Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
44 | ```shell script
45 | ./mvnw package -Dnative -Dquarkus.native.container-build=true
46 | ```
47 |
48 | You can then execute your native executable with: `./target/${{ values.artifactId }}-${{ values.version }}-runner`
49 |
50 | If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.
51 |
52 | ## Provided Code
53 |
54 | ### RESTEasy Reactive
55 |
56 | Easily start your Reactive RESTful Web Services
57 |
58 | [Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources)
59 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | ${{ values.groupId }}
6 | ${{ values.artifactId }}
7 | ${{ values.version }}
8 | ${{ values.description }}
9 |
10 | 3.11.0
11 | 17
12 | UTF-8
13 | UTF-8
14 | quarkus-bom
15 | io.quarkus.platform
16 | 3.5.0
17 | true
18 | 3.1.2
19 |
20 |
21 |
22 |
23 | ${quarkus.platform.group-id}
24 | ${quarkus.platform.artifact-id}
25 | ${quarkus.platform.version}
26 | pom
27 | import
28 |
29 |
30 |
31 |
32 |
33 | io.quarkus
34 | quarkus-arc
35 |
36 |
37 | io.quarkus
38 | quarkus-resteasy-reactive
39 |
40 |
41 | io.quarkus
42 | quarkus-micrometer
43 |
44 |
45 | io.quarkus
46 | quarkus-smallrye-health
47 |
48 |
49 | io.quarkus
50 | quarkus-openshift
51 |
52 |
53 | io.quarkus
54 | quarkus-junit5
55 | test
56 |
57 |
58 | io.rest-assured
59 | rest-assured
60 | test
61 |
62 |
63 |
64 |
65 |
66 | ${quarkus.platform.group-id}
67 | quarkus-maven-plugin
68 | ${quarkus.platform.version}
69 | true
70 |
71 |
72 |
73 | build
74 | generate-code
75 | generate-code-tests
76 |
77 |
78 |
79 |
80 |
81 | maven-compiler-plugin
82 | ${compiler-plugin.version}
83 |
84 |
85 | -parameters
86 |
87 |
88 |
89 |
90 | maven-surefire-plugin
91 | ${surefire-plugin.version}
92 |
93 |
94 | org.jboss.logmanager.LogManager
95 | ${maven.home}
96 |
97 |
98 |
99 |
100 | maven-failsafe-plugin
101 | ${surefire-plugin.version}
102 |
103 |
104 |
105 | integration-test
106 | verify
107 |
108 |
109 |
110 | ${project.build.directory}/${project.build.finalName}-runner
111 | org.jboss.logmanager.LogManager
112 | ${maven.home}
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | native
123 |
124 |
125 | native
126 |
127 |
128 |
129 | false
130 | native
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/main/docker/Dockerfile.jvm:
--------------------------------------------------------------------------------
1 | ####
2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
3 | #
4 | # Before building the container image run:
5 | #
6 | # ./mvnw package
7 | #
8 | # Then, build the image with:
9 | #
10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/${{ values.artifactId }}-jvm .
11 | #
12 | # Then run the container using:
13 | #
14 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}-jvm
15 | #
16 | # If you want to include the debug port into your docker image
17 | # you will have to expose the debug port (default 5005 being the default) like this : EXPOSE ${{ values.port }} 5005.
18 | # Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
19 | # when running the container
20 | #
21 | # Then run the container using :
22 | #
23 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}-jvm
24 | #
25 | # This image uses the `run-java.sh` script to run the application.
26 | # This scripts computes the command line to execute your Java application, and
27 | # includes memory/GC tuning.
28 | # You can configure the behavior using the following environment properties:
29 | # - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
30 | # - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
31 | # in JAVA_OPTS (example: "-Dsome.property=foo")
32 | # - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
33 | # used to calculate a default maximal heap memory based on a containers restriction.
34 | # If used in a container without any memory constraints for the container then this
35 | # option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
36 | # of the container available memory as set here. The default is `50` which means 50%
37 | # of the available memory is used as an upper boundary. You can skip this mechanism by
38 | # setting this value to `0` in which case no `-Xmx` option is added.
39 | # - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
40 | # is used to calculate a default initial heap memory based on the maximum heap memory.
41 | # If used in a container without any memory constraints for the container then this
42 | # option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
43 | # of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
44 | # is used as the initial heap size. You can skip this mechanism by setting this value
45 | # to `0` in which case no `-Xms` option is added (example: "25")
46 | # - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
47 | # This is used to calculate the maximum value of the initial heap memory. If used in
48 | # a container without any memory constraints for the container then this option has
49 | # no effect. If there is a memory constraint then `-Xms` is limited to the value set
50 | # here. The default is 4096MB which means the calculated value of `-Xms` never will
51 | # be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
52 | # - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
53 | # when things are happening. This option, if set to true, will set
54 | # `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
55 | # - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
56 | # true").
57 | # - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
58 | # - CONTAINER_CORE_LIMIT: A calculated core limit as described in
59 | # https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
60 | # - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
61 | # - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
62 | # (example: "20")
63 | # - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
64 | # (example: "40")
65 | # - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
66 | # (example: "4")
67 | # - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
68 | # previous GC times. (example: "90")
69 | # - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
70 | # - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
71 | # - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
72 | # contain the necessary JRE command-line options to specify the required GC, which
73 | # will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
74 | # - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:${{ values.port }}")
75 | # - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:${{ values.port }}")
76 | # - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
77 | # accessed directly. (example: "foo.example.com,bar.example.com")
78 | #
79 | ###
80 | FROM registry.access.redhat.com/ubi8/openjdk-17:1.16
81 |
82 | ENV LANGUAGE='en_US:en'
83 |
84 |
85 | # We make four distinct layers so if there are application changes the library layers can be re-used
86 | COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
87 | COPY --chown=185 target/quarkus-app/*.jar /deployments/
88 | COPY --chown=185 target/quarkus-app/app/ /deployments/app/
89 | COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
90 |
91 | EXPOSE ${{ values.port }}
92 | USER 185
93 | ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
94 | ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
95 |
96 | ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
97 |
98 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/main/docker/Dockerfile.legacy-jar:
--------------------------------------------------------------------------------
1 | ####
2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
3 | #
4 | # Before building the container image run:
5 | #
6 | # ./mvnw package -Dquarkus.package.type=legacy-jar
7 | #
8 | # Then, build the image with:
9 | #
10 | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/${{ values.artifactId }}-legacy-jar .
11 | #
12 | # Then run the container using:
13 | #
14 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}-legacy-jar
15 | #
16 | # If you want to include the debug port into your docker image
17 | # you will have to expose the debug port (default 5005 being the default) like this : EXPOSE ${{ values.port }} 5005.
18 | # Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
19 | # when running the container
20 | #
21 | # Then run the container using :
22 | #
23 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}-legacy-jar
24 | #
25 | # This image uses the `run-java.sh` script to run the application.
26 | # This scripts computes the command line to execute your Java application, and
27 | # includes memory/GC tuning.
28 | # You can configure the behavior using the following environment properties:
29 | # - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
30 | # - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
31 | # in JAVA_OPTS (example: "-Dsome.property=foo")
32 | # - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
33 | # used to calculate a default maximal heap memory based on a containers restriction.
34 | # If used in a container without any memory constraints for the container then this
35 | # option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
36 | # of the container available memory as set here. The default is `50` which means 50%
37 | # of the available memory is used as an upper boundary. You can skip this mechanism by
38 | # setting this value to `0` in which case no `-Xmx` option is added.
39 | # - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
40 | # is used to calculate a default initial heap memory based on the maximum heap memory.
41 | # If used in a container without any memory constraints for the container then this
42 | # option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
43 | # of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
44 | # is used as the initial heap size. You can skip this mechanism by setting this value
45 | # to `0` in which case no `-Xms` option is added (example: "25")
46 | # - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
47 | # This is used to calculate the maximum value of the initial heap memory. If used in
48 | # a container without any memory constraints for the container then this option has
49 | # no effect. If there is a memory constraint then `-Xms` is limited to the value set
50 | # here. The default is 4096MB which means the calculated value of `-Xms` never will
51 | # be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
52 | # - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
53 | # when things are happening. This option, if set to true, will set
54 | # `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
55 | # - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
56 | # true").
57 | # - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
58 | # - CONTAINER_CORE_LIMIT: A calculated core limit as described in
59 | # https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
60 | # - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
61 | # - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
62 | # (example: "20")
63 | # - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
64 | # (example: "40")
65 | # - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
66 | # (example: "4")
67 | # - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
68 | # previous GC times. (example: "90")
69 | # - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
70 | # - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
71 | # - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
72 | # contain the necessary JRE command-line options to specify the required GC, which
73 | # will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
74 | # - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:${{ values.port }}")
75 | # - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:${{ values.port }}")
76 | # - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
77 | # accessed directly. (example: "foo.example.com,bar.example.com")
78 | #
79 | ###
80 | FROM registry.access.redhat.com/ubi8/openjdk-17:1.16
81 |
82 | ENV LANGUAGE='en_US:en'
83 |
84 |
85 | COPY target/lib/* /deployments/lib/
86 | COPY target/*-runner.jar /deployments/quarkus-run.jar
87 |
88 | EXPOSE ${{ values.port }}
89 | USER 185
90 | ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
91 | ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
92 |
93 | ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
94 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/main/docker/Dockerfile.native:
--------------------------------------------------------------------------------
1 | ####
2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
3 | #
4 | # Before building the container image run:
5 | #
6 | # ./mvnw package -Dnative
7 | #
8 | # Then, build the image with:
9 | #
10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/${{ values.artifactId }} .
11 | #
12 | # Then run the container using:
13 | #
14 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}
15 | #
16 | ###
17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
18 | WORKDIR /work/
19 | RUN chown 1001 /work \
20 | && chmod "g+rwX" /work \
21 | && chown 1001:root /work
22 | COPY --chown=1001:root target/*-runner /work/application
23 |
24 | EXPOSE ${{ values.port }}
25 | USER 1001
26 |
27 | ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
28 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/main/docker/Dockerfile.native-micro:
--------------------------------------------------------------------------------
1 | ####
2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
3 | # It uses a micro base image, tuned for Quarkus native executables.
4 | # It reduces the size of the resulting container image.
5 | # Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
6 | #
7 | # Before building the container image run:
8 | #
9 | # ./mvnw package -Dnative
10 | #
11 | # Then, build the image with:
12 | #
13 | # docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/${{ values.artifactId }} .
14 | #
15 | # Then run the container using:
16 | #
17 | # docker run -i --rm -p ${{ values.port }}:${{ values.port }} quarkus/${{ values.artifactId }}
18 | #
19 | ###
20 | FROM quay.io/quarkus/quarkus-micro-image:2.0
21 | WORKDIR /work/
22 | RUN chown 1001 /work \
23 | && chmod "g+rwX" /work \
24 | && chown 1001:root /work
25 | COPY --chown=1001:root target/*-runner /work/application
26 |
27 | EXPOSE ${{ values.port }}
28 | USER 1001
29 |
30 | ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
31 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/main/java/${{values.javaPackageName}}/GreetingResource.java:
--------------------------------------------------------------------------------
1 | package ${{ values.javaPackageName}};
2 |
3 | import jakarta.ws.rs.GET;
4 | import jakarta.ws.rs.Path;
5 | import jakarta.ws.rs.Produces;
6 | import jakarta.ws.rs.core.MediaType;
7 |
8 | @Path("/hello")
9 | public class GreetingResource {
10 |
11 | @GET
12 | @Produces(MediaType.TEXT_PLAIN)
13 | public String hello() {
14 | return "Hello from RESTEasy Reactive";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | quarkus.http.port=${{ values.port }}
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/test/java/${{values.javaPackageName}}/GreetingResourceIT.java:
--------------------------------------------------------------------------------
1 | package ${{values.javaPackageName}};
2 |
3 | import io.quarkus.test.junit.QuarkusIntegrationTest;
4 |
5 | @QuarkusIntegrationTest
6 | public class GreetingResourceIT extends GreetingResourceTest {
7 | // Execute the same tests but in packaged mode.
8 | }
9 |
--------------------------------------------------------------------------------
/templates/github/quarkus-backend/skeleton/src/test/java/${{values.javaPackageName}}/GreetingResourceTest.java:
--------------------------------------------------------------------------------
1 | package ${{values.javaPackageName}};
2 |
3 | import io.quarkus.test.junit.QuarkusTest;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static io.restassured.RestAssured.given;
7 | import static org.hamcrest.CoreMatchers.is;
8 |
9 | @QuarkusTest
10 | public class GreetingResourceTest {
11 |
12 | @Test
13 | public void testHelloEndpoint() {
14 | given()
15 | .when().get("/hello")
16 | .then()
17 | .statusCode(200)
18 | .body(is("Hello from RESTEasy Reactive"));
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/templates/github/register-component/README.md:
--------------------------------------------------------------------------------
1 | # Register existing component to Service Catalog
2 |
3 | This template is intended to be used as a starting point for registering an existing repository to the Service Catalog.
4 |
5 | Currently, it only supports repositories hosted on GitHub (both github.com and GitHub Enterprise are supported).
6 |
7 | ## Required GitHub permissions
8 |
9 | The GitHub application or access token needs to have the following permissions:
10 |
11 | - **Repository permissions**
12 | - **Contents**: **_Read & write_** - To be able to create a new branch and push files new `catalog-info.yaml` file into it.
13 | - **Pull requests**: **_Read & write_** - To be able to create pull requests with generated `catalog-info.yaml`.
14 | - **Commit statuses**: **_Read-only_** - To be able to clone private repositories.
--------------------------------------------------------------------------------
/templates/github/register-component/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: register-component
5 | title: Register existing component to Software Catalog
6 | description: Registers existing component (GitHub repository) to Software Catalog
7 | tags:
8 | - import
9 | - catalog
10 | - register
11 | spec:
12 | owner: janus-authors
13 | system: janus-idp
14 | type: service
15 |
16 | parameters:
17 | - title: Provide information about the GitHub location
18 | required:
19 | - githubHost
20 | - githubOrganization
21 | - repositoryName
22 | properties:
23 | githubHost:
24 | title: GitHub hostname
25 | type: string
26 | description: Use github.com for GitHub Free, Pro, & Team or specify a hostname of your GitHub Enterprise instance.
27 | default: github.com
28 | githubOrganization:
29 | title: GitHub Organization
30 | type: string
31 | repositoryName:
32 | title: Repository name
33 | type: string
34 |
35 | - title: Provide information about the new component
36 | required:
37 | - componentOwner
38 | - componentType
39 | - componentLifecycle
40 | properties:
41 | componentName:
42 | title: Component Name
43 | type: string
44 | description: Name of the created component. If leaved empty the name of the repository will be used.
45 | componentOwner:
46 | title: Owner
47 | description: Select an owner from the list or enter a reference to a Group or a User
48 | type: string
49 | ui:field: EntityPicker
50 | ui:options:
51 | catalogFilter:
52 | kind:
53 | - Group
54 | - User
55 | componentType:
56 | title: Type
57 | type: string
58 | description: 'The type of component. Well-known and common values: service, website, library.'
59 | default: other
60 | componentLifecycle:
61 | title: Lifecycle
62 | type: string
63 | description: 'The lifecycle state of the component. Well-known and common values: experimental, production, deprecated.'
64 | default: unknown
65 |
66 | steps:
67 | - id: fetchRepository
68 | name: Fetch repository
69 | action: fetch:plain
70 | input:
71 | url: https://${{ parameters.githubHost }}/${{ parameters.githubOrganization }}/${{ parameters.repositoryName }}
72 |
73 | - id: catalogTemplate
74 | name: Create catalog-info.yaml file
75 | action: fetch:template
76 | input:
77 | url: ../../../skeletons/catalog-info/
78 | values:
79 | componentName: ${{ parameters.componentName }}
80 | orgName: ${{ parameters.githubOrganization }}
81 | sourceControl: github.com
82 | repoName: ${{ parameters.repositoryName }}
83 | componentLifecycle: ${{ parameters.componentLifecycle }}
84 | applicationType: ${{ parameters.componentType }}
85 | owner: ${{ parameters.componentOwner }}
86 |
87 | - id: publishPR
88 | name: Open PR with catalog-info.yaml
89 | action: publish:github:pull-request
90 | input:
91 | repoUrl: ${{ parameters.githubHost }}?owner=${{ parameters.githubOrganization }}&repo=${{ parameters.repositoryName }}
92 | branchName: add-catalog-info
93 | title: add catalog-info.yaml
94 | description: |
95 | This pull request adds a **Backstage entity metadata file** to this repository.
96 |
97 | After this pull request is merged, the component will become available.
98 |
99 | For more information, read an [overview of the Backstage software catalog](https://backstage.io/docs/features/software-catalog/).
100 |
101 | - id: register
102 | name: Register component
103 | action: catalog:register
104 | input:
105 | repoContentsUrl: https://${{ parameters.githubHost }}/${{ parameters.githubOrganization }}/${{ parameters.repositoryName }}/blob/${{ steps.publishPR.output.targetBranchName }}/
106 | catalogInfoPath: /catalog-info.yaml
107 | optional: true
108 |
109 | output:
110 | links:
111 | - title: 'Open PR #${{ steps.publishPR.output.pullRequestNumber }}'
112 | url: ${{ steps.publishPR.output.remoteUrl }}
113 |
--------------------------------------------------------------------------------
/templates/github/sdlc-app/skeleton/argoapps/${{values.application_id}}-root-argoapp.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: Application
3 | metadata:
4 | name: ${{values.application_id}}-root-application
5 | namespace: ${{values.application_id}}-build
6 | finalizers:
7 | - resources-finalizer.argocd.argoproj.io
8 | spec:
9 | project: default
10 | source:
11 | repoURL: https://github.com/${{values.organization}}/${{values.application_id}}-gitops.git
12 | path: components
13 | directory:
14 | include: "*.yaml"
15 | destination:
16 | server: https://kubernetes.default.svc
17 | namespace: ${{values.application_id}}-build
18 | syncPolicy:
19 | automated:
20 | prune: true
21 | selfHeal: true
22 | allowEmpty: true
23 | syncOptions:
24 | - CreateNamespace=false
25 | retry:
26 | limit: 0 # number of failed sync attempt retries; unlimited number of attempts if less than 0
27 | backoff:
28 | duration: 5s # the amount to back off. Default unit is seconds, but could also be a duration (e.g. "2m", "1h")
29 | factor: 2 # a factor to multiply the base duration after each failed retry
30 | maxDuration: 10m # the maximum amount of time allowed for the backoff strategy
31 |
--------------------------------------------------------------------------------
/templates/github/sdlc-app/skeleton/namespaces/${{values.application_id}}-namespaces.yaml:
--------------------------------------------------------------------------------
1 | {% for environment in values.environments.split(",") %}
2 | ---
3 | apiVersion: v1
4 | kind: Namespace
5 | metadata:
6 | name: ${{values.application_id}}-${{environment}}
7 | labels:
8 | app : ${{values.application_id}}
9 | team: ${{values.owner}}
10 | build-namespace: ${{values.application_id}}-build
11 | size: ${{values.size}}
12 | environment: ${{environment}}
13 | goldilocks.fairwinds.com/enabled: "true"
14 | argocd.argoproj.io/managed-by: ${{values.application_id}}-build
15 | {% endfor %}
--------------------------------------------------------------------------------
/templates/github/sdlc-app/skeleton/systems/${{values.application_id}}-system.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: System
3 | metadata:
4 | name: ${{values.application_id}}
5 | description: ${{values.description}}
6 | labels:
7 | size: ${{values.size}}
8 | environments: ${{values.environments.replaceAll(',','-')}}
9 | spec:
10 | owner: ${{values.owner}}
--------------------------------------------------------------------------------
/templates/github/sdlc-app/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: sdlc-app-template
5 | title: Application Template
6 | description: An application is a set of components that will run together in the same SDLC environments
7 | tags:
8 | - application
9 | spec:
10 | owner: service@example.com
11 | type: system
12 |
13 | parameters:
14 | - title: Provide information on this application
15 | required:
16 | - application_id
17 | - owner
18 | - organization
19 | - size
20 | - environments
21 | - description
22 | properties:
23 | application_id:
24 | title: Name
25 | type: string
26 | description: Unique name of this application
27 | description:
28 | title: Description
29 | type: string
30 | description: Help others understand what this application is for.
31 | owner:
32 | title: Owner
33 | type: string
34 | description: Owner of this applications
35 | ui:field: OwnerPicker
36 | ui:options:
37 | allowedKinds:
38 | - Group
39 | organization:
40 | title: Organization
41 | type: string
42 | description: Organization of this application
43 | ui:field: OrganizationPicker
44 | ui:options:
45 | allowedKinds:
46 | - Group
47 | size:
48 | title: Size
49 | type: string
50 | description: Desired size of the environments in which this application will run
51 | enum: ['small', 'medium', 'large']
52 | environments:
53 | title: Environments
54 | type: string
55 | description: Environments needed by this application
56 | enum: ['build,dev,qa,prod']
57 |
58 | steps:
59 | - id: template-namespaces
60 | name: Fetch Skeleton + Template
61 | action: fetch:template
62 | input:
63 | url: ./skeleton
64 | copyWithoutTemplating: []
65 | values:
66 | application_id: ${{ parameters.application_id }}
67 | description: ${{ parameters.description }}
68 | size: ${{ parameters.size }}
69 | owner: ${{ parameters.owner }}
70 | organization: ${{ parameters.organization }}
71 | environments: ${{ parameters.environments }}
72 |
73 | - id: pull-request
74 | name: make a pr with the new namespaces
75 | action: publish:github:pull-request
76 | input:
77 | repoUrl: github.com?repo=approved-namespaces&owner=${{ parameters.organization }}
78 | branchName: ${{ parameters.application_id }}
79 | title: namespaces for ${{ parameters.application_id }}
80 | description: namespaces for ${{ parameters.application_id }}
81 |
82 | - id: template-gitops
83 | name: Fetch Skeleton + Template
84 | action: fetch:template
85 | input:
86 | url: ./app-gitops
87 | copyWithoutTemplating: []
88 | values: {}
89 | targetPath: ./app-gitops
90 |
91 | - id: publish
92 | name: Publish
93 | action: publish:github
94 | input:
95 | allowedHosts: ['github.com']
96 | description: This is ${{ parameters.application_id }}
97 | repoUrl: github.com?repo=${{ parameters.application_id }}-gitops&owner=${{ parameters.organization }}
98 | repoVisibility: public
99 | sourcePath: ./app-gitops
100 | deleteBranchOnMerge: true
101 | access: ${{ parameters.application_id }}/${{ parameters.owner }}
102 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/README.md:
--------------------------------------------------------------------------------
1 | # Create a Spring Boot Backend application with a CI pipeline
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/.gitattributes:
--------------------------------------------------------------------------------
1 | * eol=lf
2 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redhat-developer/red-hat-developer-hub-software-templates/25888aa2edffea568ee84871be78b7d111c4cff5/templates/github/spring-boot-backend/skeleton/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.access.redhat.com/ubi8/openjdk-11:1.11
2 |
3 | WORKDIR /app
4 |
5 | COPY .mvn/ .mvn
6 | COPY mvnw pom.xml ./
7 | RUN ./mvnw dependency:resolve
8 |
9 | COPY src ./src
10 |
11 | ENV PORT ${{ values.port }}
12 | EXPOSE ${{ values.port }}
13 |
14 | CMD ["./mvnw", "spring-boot:run"]
15 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # ${{ values.repoName }}
2 |
3 | ${{ values.description }}
4 |
5 | More information on the chosen CI method can be found [here](https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}/blob/main/CI.md).
6 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.7.9
9 |
10 |
11 | ${{ values.groupId }}
12 | ${{ values.artifactId }}
13 | 0.0.1-SNAPSHOT
14 | ${{ values.repoName }}
15 | ${{ values.description }}
16 |
17 | 11
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-test
28 | test
29 |
30 |
31 |
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-maven-plugin
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/src/main/java/${{values.java_package_name}}/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package ${{ values.groupId }}.${{ values.artifactId }}
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | @RestController
9 | @SpringBootApplication
10 | public class DemoApplication {
11 |
12 | @RequestMapping("/")
13 | String home() {
14 | return "Hello World";
15 | }
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(DemoApplication.class, args);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/templates/github/spring-boot-backend/skeleton/src/test/java/${{values.java_package_name}}/DemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package ${{ values.groupId }}.${{ values.artifactId }}
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class DemoApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/templates/github/techdocs/README.md:
--------------------------------------------------------------------------------
1 | # Create a Techdocs sample
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/github/techdocs/skeleton/.github/workflows/techdocs.yaml:
--------------------------------------------------------------------------------
1 | name: Publish TechDocs Site
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - 'docs/**'
9 | - 'mkdocs.yaml'
10 |
11 | jobs:
12 | publish-techdocs-site:
13 | name: Publish techdocs site
14 | runs-on: ubuntu-latest
15 |
16 | env:
17 | TECHDOCS_S3_BUCKET_NAME: ${{ secrets.BUCKET_NAME }}
18 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
19 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
20 | AWS_REGION: ${{ secrets.AWS_REGION }}
21 | AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
22 | ENTITY_NAMESPACE: default
23 | ENTITY_KIND: Component
24 | ENTITY_NAME: ${{ github.event.repository.name }}
25 |
26 | steps:
27 | - name: Checkout code
28 | uses: actions/checkout@v3
29 |
30 | - uses: actions/setup-node@v3
31 | - uses: actions/setup-python@v4
32 | with:
33 | python-version: '3.9'
34 |
35 | - name: Install techdocs-cli
36 | run: sudo npm install -g @techdocs/cli
37 |
38 | - name: Install mkdocs and mkdocs plugins
39 | run: python -m pip install mkdocs-techdocs-core==1.*
40 |
41 | - name: Generate docs site
42 | run: techdocs-cli generate --no-docker --verbose
43 |
44 | - name: Publish docs site
45 | run: techdocs-cli publish --publisher-type awsS3 --storage-name $TECHDOCS_S3_BUCKET_NAME --awsEndpoint $AWS_ENDPOINT --awsS3ForcePathStyle --entity $ENTITY_NAMESPACE/$ENTITY_KIND/$ENTITY_NAME
46 |
--------------------------------------------------------------------------------
/templates/github/techdocs/skeleton/CI.md:
--------------------------------------------------------------------------------
1 | # GitHub Actions CI Method
2 |
3 | ## Requirements
4 |
5 | The GitHub Actions CI Method will require repository secrets setup before GitHub Actions can run
6 |
7 | SECRETS
8 | AWS Secrets
9 |
10 | - `AWS_ACCESS_KEY_ID` - The AWS access key ID
11 | - `AWS_SECRET_ACCESS_KEY` - The AWS secret access key
12 | - `AWS_REGION` - The AWS region
13 | - `AWS_ENDPOINT` - The AWS endpoint
14 |
15 | CI Secrets
16 |
17 | - `BUCKET_NAME` - The techdocs S3 bucket name
18 |
--------------------------------------------------------------------------------
/templates/github/techdocs/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # ${{ values.repoName }}
2 |
3 | ${{ values.description }}
4 |
5 | More information on the chosen CI method can be found [here](https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}/blob/main/CI.md).
6 |
--------------------------------------------------------------------------------
/templates/github/techdocs/skeleton/docs/index.md:
--------------------------------------------------------------------------------
1 | # ${{ values.repoName }} Documentation
2 |
3 | This section is coming soon!
4 |
--------------------------------------------------------------------------------
/templates/github/techdocs/skeleton/mkdocs.yaml:
--------------------------------------------------------------------------------
1 | site_name: ${{ values.repoName }}
2 | site_description: ${{ values.description }}
3 | repo_url: https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}
4 | edit_uri: edit/main/docs
5 |
6 | plugins:
7 | - techdocs-core
8 |
9 | # Note for content editors, edit only the section below
10 | nav:
11 | - ${{ values.repoName }} Documentation: index.md
12 |
--------------------------------------------------------------------------------
/templates/github/techdocs/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: techdocs-template
5 | title: Create a techdocs sample
6 | description: Create a techdocs sample
7 | tags:
8 | - documentation
9 | - techdocs
10 | spec:
11 | owner: janus-authors
12 | system: janus-idp
13 | type: service
14 |
15 | parameters:
16 | - title: Provide information about the existing component
17 | required:
18 | - orgName
19 | - repoName
20 | - componentName
21 | properties:
22 | orgName:
23 | title: Organization Name
24 | type: string
25 | repoName:
26 | title: Repository Name
27 | type: string
28 | componentName:
29 | title: Component Name
30 | type: string
31 | description: Attach the techdocs to an existing component
32 | ui:field: EntityPicker
33 | ui:options:
34 | catalogFilter:
35 | kind:
36 | - Component
37 | - title: Provide information about the new component
38 | required:
39 | - owner
40 | - system
41 | properties:
42 | owner:
43 | title: Owner
44 | type: string
45 | ui:field: EntityPicker
46 | ui:options:
47 | catalogFilter:
48 | kind:
49 | - Group
50 | - User
51 | system:
52 | title: System
53 | type: string
54 | ui:field: EntityPicker
55 | ui:options:
56 | catalogFilter:
57 | kind:
58 | - System
59 |
60 | steps:
61 | - id: sourceCodeTemplate
62 | name: Generating the Source Code Component
63 | action: fetch:template
64 | input:
65 | url: ./skeleton
66 | copyWithoutTemplating:
67 | - .github/workflows/
68 | values:
69 | orgName: ${{ parameters.orgName }}
70 | repoName: ${{ parameters.repoName }}-techdocs
71 | owner: ${{ parameters.owner }}
72 | system: ${{ parameters.system }}
73 | applicationType: documentation
74 | description: Contains the techdocs for ${{ parameters.repoName }}
75 | sourceControl: github.com
76 |
77 | - id: catalogTemplate
78 | name: Generating the Catalog Info Component
79 | action: fetch:template
80 | input:
81 | url: ../../../skeletons/catalog-info/
82 | values:
83 | # Gitops specific values
84 | partOf: ${{ parameters.componentName }}
85 |
86 | orgName: ${{ parameters.orgName }}
87 | repoName: ${{ parameters.repoName }}-techdocs
88 | owner: ${{ parameters.owner }}
89 | system: ${{ parameters.system }}
90 | applicationType: documentation
91 | description: Contains the techdocs for ${{ parameters.repoName }}
92 | sourceControl: github.com
93 |
94 | - id: publish
95 | name: Publishing to the Source Code Repository
96 | action: publish:github
97 | input:
98 | allowedHosts: ['github.com']
99 | description: Contains the techdocs for ${{ parameters.repoName }}
100 | repoUrl: github.com?owner=${{ parameters.orgName }}&repo=${{ parameters.repoName }}-techdocs
101 | defaultBranch: main
102 |
103 | - id: register
104 | name: Registering the Catalog Info Component
105 | action: catalog:register
106 | input:
107 | repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
108 | catalogInfoPath: /catalog-info.yaml
109 |
110 | output:
111 | links:
112 | - title: Open the Source Code Repository
113 | url: ${{ steps.publish.output.remoteUrl }}
114 | - title: Open the Catalog Info Component
115 | icon: catalog
116 | entityRef: ${{ steps.register.output.entityRef }}
117 |
--------------------------------------------------------------------------------
/templates/github/tekton/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: tekton-template
5 | title: Create a tekton CI Pipeline
6 | description: Create a tekton CI Pipeline
7 | tags:
8 | - ci
9 | - tekton
10 | spec:
11 | owner: janus-authors
12 | system: janus-idp
13 | type: service
14 |
15 | parameters:
16 | - title: Provide information about the existing component
17 | required:
18 | - orgName
19 | - repoName
20 | - prBranch
21 | - catalogInfoPath
22 | properties:
23 | orgName:
24 | title: Organization
25 | type: string
26 | repoName:
27 | title: Repository
28 | type: string
29 | prBranch:
30 | title: Pull Request Branch
31 | type: string
32 | default: add-tekton
33 | catalogInfoPath:
34 | title: Catalog Info Path
35 | type: string
36 | default: catalog-info.yaml
37 |
38 | - title: Provide information about the CI method
39 | required:
40 | - imageBuilder
41 | - imageRepository
42 | - imageUrl
43 | - namespace
44 | - port
45 | properties:
46 | imageBuilder:
47 | title: Image Builder
48 | type: string
49 | description: The Source-To-Image (S2I) builder to use
50 | imageRepository:
51 | title: Select a registry
52 | type: string
53 | default: quay.io
54 | enum:
55 | - quay.io
56 | - image-registry.openshift-image-registry.svc:5000
57 | enumNames:
58 | - Quay
59 | - Internal OpenShift Registry
60 | imageUrl:
61 | title: Image URL
62 | type: string
63 | description: The Quay.io or OpenShift Image URL //
64 | namespace:
65 | title: Namespace
66 | type: string
67 | description: The namespace for deploying resources
68 | port:
69 | title: Port
70 | type: number
71 | description: The port exposed for the application
72 |
73 | steps:
74 | - id: fetchRepo
75 | name: Fetch Repo
76 | action: fetch:plain
77 | input:
78 | url: 'https://github.com/${{ parameters.orgName }}/${{ parameters.repoName }}'
79 |
80 | - id: merge
81 | name: Merge YAML
82 | action: roadiehq:utils:merge
83 | input:
84 | path: ${{ parameters.catalogInfoPath }}
85 | content:
86 | metadata:
87 | annotations:
88 | tektonci/build-namespace: ${{ parameters.namespace }}
89 |
90 | - id: ciTemplate
91 | name: Generating the CI Component
92 | action: fetch:template
93 | input:
94 | url: ../../../skeletons/tekton/
95 | values:
96 | orgName: ${{ parameters.orgName }}
97 | repoName: ${{ parameters.repoName }}
98 | imageBuilder: ${{ parameters.imageBuilder }}
99 | imageUrl: ${{ parameters.imageUrl }}
100 | imageRepository: ${{ parameters.imageRepository }}
101 | namespace: ${{ parameters.namespace }}
102 | port: ${{ parameters.port }}
103 | sourceControl: github.com
104 |
105 | - id: publishPR
106 | name: Publish PR
107 | action: publish:github:pull-request
108 | input:
109 | repoUrl: github.com?repo=${{ parameters.repoName }}&owner=${{ parameters.orgName }}
110 | branchName: ${{ parameters.prBranch }}
111 | title: Add Tekton
112 | description: This PR was created by a Backstage scaffolder task to add Tekton to the project.
113 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/README.md:
--------------------------------------------------------------------------------
1 | # Create a Python Backend application with a CI pipeline
2 |
3 | Currently WIP
4 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/.dockerignore:
--------------------------------------------------------------------------------
1 | README.md
2 | .git
3 | .env.local
4 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | .odo/env
2 | .odo/odo-file-index.json
3 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | image: docker:git
2 | services:
3 | - name: docker:dind
4 |
5 | stages:
6 | - build
7 | - release
8 |
9 | variables:
10 | DOCKER_HOST: tcp://docker:2376/
11 | DOCKER_TLS_CERTDIR: '/certs'
12 | IMAGE_TAGS: latest $CI_COMMIT_SHA
13 |
14 | build:
15 | stage: build
16 | script:
17 | - docker build -t $CI_PROJECT_NAME .
18 | - |
19 | for t in $IMAGE_TAGS; do
20 | docker tag $CI_PROJECT_NAME $REGISTRY/$REGISTRY_NAMESPACE/$CI_PROJECT_NAME:$t
21 | done
22 |
23 | release-image:
24 | stage: release
25 | script:
26 | - docker login -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD $REGISTRY
27 | - docker build -t $CI_PROJECT_NAME .
28 | - |
29 | for t in $IMAGE_TAGS; do
30 | docker tag $CI_PROJECT_NAME $REGISTRY/$REGISTRY_NAMESPACE/$CI_PROJECT_NAME:$t
31 | done
32 | - |
33 | for t in $IMAGE_TAGS; do
34 | docker push $REGISTRY/$REGISTRY_NAMESPACE/$CI_PROJECT_NAME:$t
35 | done
36 | only:
37 | - main
38 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/CI.md:
--------------------------------------------------------------------------------
1 | # GitLab Pipelines CI Method
2 |
3 | ## Requirements
4 |
5 | The GitLab Pipelines CI Method will require repository secrets setup before GitLab Pipelines can run
6 |
7 | SECRETS
8 | CI Secrets
9 |
10 | - `REGISTRY` - The registry server to connect to e.g. `quay.io`
11 | - `REGISTRY_USERNAME` - The registry username
12 | - `REGISTRY_PASSWORD` - The registry password
13 | - `REGISTRY_NAMESPACE` - The image namespace
14 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.access.redhat.com/ubi9/python-39:latest
2 |
3 | # Set the working directory in the container
4 | WORKDIR /projects
5 |
6 | # Copy the dependencies file to the working directory
7 | COPY requirements.txt .
8 |
9 | # Install any dependencies
10 | RUN pip install -r requirements.txt
11 |
12 | # Copy the content of the local src directory to the working directory
13 | COPY . .
14 |
15 | ENV PORT ${{ values.port }}
16 | EXPOSE ${{ values.port }}
17 |
18 | # Specify the command to run on container start
19 | CMD [ "python", "./src/app.py" ]
20 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/README.md:
--------------------------------------------------------------------------------
1 | # ${{ values.repoName }}
2 |
3 | ${{ values.description }}
4 |
5 | More information on the chosen CI method can be found [here](https://${{ values.sourceControl }}/${{ values.orgName }}/${{ values.repoName }}/blob/main/CI.md).
6 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==2.2.5
2 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/skeleton/src/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | import os
3 |
4 | app = Flask(__name__)
5 |
6 |
7 | @app.route("/")
8 | def hello():
9 | return "Hello World!"
10 |
11 |
12 | if __name__ == "__main__":
13 | port = os.environ.get("PORT") or ${{ values.port }}
14 | port = int(port)
15 |
16 | app.run(port=port, host="0.0.0.0")
17 |
--------------------------------------------------------------------------------
/templates/gitlab/python-backend/template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scaffolder.backstage.io/v1beta3
2 | kind: Template
3 | metadata:
4 | name: python-backend-template
5 | title: Create a Python application in GitLab with a CI pipeline
6 | description: Create a starter Python backend application in GitLab with a CI pipeline
7 | tags:
8 | - recommended
9 | - python
10 | - flask
11 | - gitlab
12 | spec:
13 | owner: janus-authors
14 | system: janus-idp
15 | type: service
16 |
17 | parameters:
18 | - title: Provide information about the new component
19 | required:
20 | - orgName
21 | - repoName
22 | - owner
23 | - system
24 | - port
25 | properties:
26 | orgName:
27 | title: Organization Name
28 | type: string
29 | repoName:
30 | title: Repository Name
31 | type: string
32 | description:
33 | title: Description
34 | type: string
35 | description: Help others understand what this component is for
36 | owner:
37 | title: Owner
38 | type: string
39 | ui:field: EntityPicker
40 | ui:options:
41 | catalogFilter:
42 | kind:
43 | - Group
44 | - User
45 | system:
46 | title: System
47 | type: string
48 | ui:field: EntityPicker
49 | ui:options:
50 | catalogFilter:
51 | kind:
52 | - System
53 | port:
54 | title: Port
55 | type: number
56 | default: 5000
57 | description: Override the port exposed for the application
58 |
59 | steps:
60 | - id: sourceCodeTemplate
61 | name: Generating the Source Code Component
62 | action: fetch:template
63 | input:
64 | url: ./skeleton
65 | values:
66 | orgName: ${{ parameters.orgName }}
67 | repoName: ${{ parameters.repoName }}
68 | owner: ${{ parameters.owner }}
69 | system: ${{ parameters.system }}
70 | applicationType: api
71 | description: ${{ parameters.description }}
72 | port: ${{ parameters.port }}
73 | sourceControl: gitlab.com
74 |
75 | - id: catalogTemplate
76 | name: Generating the Catalog Info Component
77 | action: fetch:template
78 | input:
79 | url: ../../../skeletons/catalog-info/
80 | values:
81 | orgName: ${{ parameters.orgName }}
82 | repoName: ${{ parameters.repoName }}
83 | owner: ${{ parameters.owner }}
84 | system: ${{ parameters.system }}
85 | applicationType: api
86 | description: ${{ parameters.description }}
87 | port: ${{ parameters.port }}
88 | sourceControl: gitlab.com
89 |
90 | - id: publish
91 | name: Publishing to the Source Code Repository
92 | action: publish:gitlab
93 | input:
94 | allowedHosts: ['gitlab.com']
95 | description: ${{ parameters.description }}
96 | repoUrl: gitlab.com?owner=${{ parameters.orgName }}&repo=${{ parameters.repoName }}
97 | defaultBranch: main
98 |
99 | - id: register
100 | name: Registering the Catalog Info Component
101 | action: catalog:register
102 | input:
103 | repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
104 | catalogInfoPath: /catalog-info.yaml
105 |
106 | output:
107 | links:
108 | - title: Open the Source Code Repository
109 | url: ${{ steps.publish.output.remoteUrl }}
110 | - title: Open the Catalog Info Component
111 | icon: catalog
112 | entityRef: ${{ steps.register.output.entityRef }}
113 |
--------------------------------------------------------------------------------