├── .gitignore ├── .prettierignore ├── .roadierc ├── README.md ├── examples ├── azure-actions │ ├── skeleton │ │ └── fileA.txt │ └── template.yaml ├── update-json-file │ ├── my-file.json │ └── template.yaml └── update-yaml-file │ ├── my-file.yaml │ └── template.yaml └── scaffolder-templates ├── add-branch-protection └── template.yaml ├── add-codeowners ├── skeleton │ └── CODEOWNERS.njk └── template.yaml ├── add-security-tools-yaml ├── skeleton │ └── security-tools.yml.njk └── template.yaml ├── add-tenant-to-alerts └── template.yaml ├── create-aws-serverless-backend ├── skeleton │ ├── .env │ ├── .github │ │ └── workflows │ │ │ ├── merge.yaml │ │ │ └── pull-request.yaml │ ├── .gitignore │ ├── README.md │ ├── catalog-info.yaml │ ├── mkdocs.yml │ ├── package.json │ ├── src │ │ └── lambda.ts │ ├── sst.json │ ├── stacks │ │ ├── MyStack.ts │ │ └── index.ts │ ├── test │ │ └── MyStack.test.ts │ └── tsconfig.json └── template.yaml ├── create-aws-serverless-frontend-and-backend ├── skeleton │ ├── .github │ │ └── workflows │ │ │ ├── merge.yaml │ │ │ └── pull-request.yaml │ ├── .gitignore │ ├── README.md │ ├── catalog-info.yaml │ ├── frontend │ │ ├── .env │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── logo192.png │ │ │ ├── logo512.png │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ └── src │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── index.css │ │ │ ├── index.js │ │ │ ├── logo.svg │ │ │ ├── reportWebVitals.js │ │ │ └── setupTests.js │ ├── mkdocs.yml │ ├── package.json │ ├── src │ │ └── lambda.js │ ├── sst.json │ ├── stacks │ │ ├── MyStack.js │ │ └── index.js │ └── test │ │ └── MyStack.test.js └── template.yaml ├── create-empty-project ├── skeleton │ ├── .github │ │ └── workflows │ │ │ └── pull-request.yaml │ ├── README.md │ └── catalog-info.yaml └── template.yaml ├── create-readme ├── skeleton │ └── README.md.njk └── template.yaml ├── create-rfc ├── skeleton │ └── template.md.njk └── template.yaml ├── create-tenant └── template.yaml ├── debug-template ├── skeleton │ └── template.md.njk └── template.yaml ├── delete-entities └── template.yaml ├── delete-tenant └── template.yaml ├── github-pages-site ├── README.md ├── skeleton │ ├── .github │ │ └── workflows │ │ │ └── test.yaml │ ├── .gitignore │ ├── README.md │ ├── catalog-info.yaml │ ├── cypress.json │ ├── cypress │ │ ├── integration │ │ │ └── sample_spec.js │ │ ├── plugins │ │ │ └── index.js │ │ └── support │ │ │ ├── commands.js │ │ │ └── index.js │ ├── docs │ │ └── index.md │ ├── index.html │ ├── mkdocs.yml │ ├── package.json │ ├── package.json.tpl │ └── yarn.lock └── template.yaml ├── oneof-example └── oneof-example.yaml ├── pr-with-catalog-entry ├── skeleton │ └── catalog-info.yaml.njk └── template.yaml ├── pull-request-test ├── skeleton │ └── new-change.yaml └── template.yaml ├── roadie-agent-entity-provider ├── skeleton │ ├── Dockerfile │ ├── README.md │ ├── config │ │ └── accept.json │ ├── package.json │ └── src │ │ ├── index.js │ │ └── myEntityHandler.js └── template.yaml ├── roadie-agent-scaffolder-action ├── skeleton │ ├── Dockerfile │ ├── README.md │ ├── config │ │ └── accept.json │ ├── package.json │ └── src │ │ ├── helloWorldScaffolderActionHandler.js │ │ └── index.js └── template.yaml └── roadie-plugin ├── skeleton ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── README.md ├── package-lock.json ├── package.json └── plugins │ └── my-plugin │ ├── .eslintrc.js │ ├── README.md │ ├── app-config.yaml │ ├── dev │ └── index.tsx │ ├── package.json │ ├── src │ ├── components │ │ ├── EntityComponentExample │ │ │ ├── EntityContentComponent.tsx │ │ │ └── index.ts │ │ ├── ExampleComponent │ │ │ ├── ExampleComponent.test.tsx │ │ │ ├── ExampleComponent.tsx │ │ │ └── index.ts │ │ └── ExampleFetchComponent │ │ │ ├── ExampleFetchComponent.test.tsx │ │ │ ├── ExampleFetchComponent.tsx │ │ │ └── index.ts │ ├── index.ts │ ├── plugin.test.ts │ ├── plugin.ts │ ├── routes.ts │ └── setupTests.ts │ └── tsconfig.json └── template.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Prettier changes double curly braces and makes files like catalog-info.yaml invalid 2 | scaffolder-templates 3 | -------------------------------------------------------------------------------- /.roadierc: -------------------------------------------------------------------------------- 1 | validator: 2 | exclude: 3 | - 'scaffolder-templates/*/skeleton/catalog-info.yaml' 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # software-templates 2 | 3 | This repository is a collection of software and documentation templates for the RoadieHQ team. The templates are organized into the folder: `scaffolder-templates` for Software Templates. -------------------------------------------------------------------------------- /examples/azure-actions/skeleton/fileA.txt: -------------------------------------------------------------------------------- 1 | name: ${{ values.name }} 2 | -------------------------------------------------------------------------------- /examples/azure-actions/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: azure-repo-demo 5 | title: Azure Repository Test 6 | description: Clone and push to an Azure repository example. 7 | spec: 8 | owner: roadie 9 | type: service 10 | 11 | parameters: 12 | - title: Fill in some steps 13 | required: 14 | - name 15 | properties: 16 | name: 17 | title: Project name 18 | type: string 19 | description: Choose a unique project name. 20 | ui:field: EntityNamePicker 21 | ui:autofocus: true 22 | sourceBranch: 23 | title: Source Branch 24 | type: string 25 | default: master 26 | remoteBranch: 27 | title: Remote Branch 28 | type: string 29 | default: scaffolder 30 | steps: 31 | - id: cloneAzureRepo 32 | name: Clone Azure Repo 33 | action: azure:repo:clone 34 | input: 35 | remoteUrl: "https://roadie-demo@dev.azure.com/roadie-demo/Sample-Services/_git/sample-service" 36 | branch: ${{ parameters.sourceBranch }} 37 | targetPath: ./sub-directory 38 | 39 | - id: fetch 40 | name: Template Skeleton 41 | action: fetch:template 42 | input: 43 | url: ./skeleton 44 | targetPath: ./sub-directory 45 | values: 46 | name: ${{ parameters.name }} 47 | 48 | - id: pushAzureRepo 49 | name: Push to Remote Azure Repo 50 | action: azure:repo:push 51 | input: 52 | branch: ${{ parameters.remoteBranch }} 53 | sourcePath: ./sub-directory 54 | gitCommitMessage: Add ${{ parameters.name }} project files 55 | 56 | - id: pullRequestAzureRepo 57 | name: Create a Pull Request to Azure Repo 58 | action: azure:repo:pr 59 | input: 60 | sourceBranch: ${{ parameters.remoteBranch }} 61 | targetBranch: "master" 62 | repoId: sample-service 63 | title: ${{ parameters.name }} 64 | project: Sample-Services 65 | organization: roadie-demo 66 | supportsIterations: false 67 | 68 | output: 69 | links: 70 | - title: Pull Request 71 | url: "https://dev.azure.com/roadie-demo/Sample-Services/_git/sample-service/pullrequest/${{ outputs.pullRequestAzureRepo.pullRequestId}}" 72 | -------------------------------------------------------------------------------- /examples/update-json-file/my-file.json: -------------------------------------------------------------------------------- 1 | { "my-key": "" } -------------------------------------------------------------------------------- /examples/update-json-file/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: update-json-file 5 | title: Update a json file 6 | description: Opens a PR with updates to a json file. 7 | 8 | spec: 9 | owner: engineering 10 | type: example 11 | parameters: 12 | - title: Provide some simple information 13 | required: ['myValue'] 14 | properties: 15 | myValue: 16 | title: My Value 17 | type: string 18 | description: Value to assign to my-key 19 | 20 | steps: 21 | - id: fetch 22 | name: Fetch repo 23 | action: fetch:plain 24 | input: 25 | # Path to the root of the repo of interest. You can also use the RepoUrlPicker to choose one. 26 | url: ./ 27 | 28 | - id: update 29 | name: Update 30 | action: roadiehq:utils:merge 31 | input: 32 | # This file must exist at this path in the repo referenced above 33 | path: my-file.json 34 | content: 35 | my-key: ${{ parameters.myValue }} 36 | 37 | - id: publish 38 | name: Publish 39 | action: publish:github:pull-request 40 | input: 41 | repoUrl: github.com?repo=software-templates&owner=RoadieHQ 42 | title: Update my-file.json 43 | description: update description 44 | branchName: update-my-file # TODO parameterise? 45 | targetPath: examples/update-json-file 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/update-yaml-file/my-file.yaml: -------------------------------------------------------------------------------- 1 | myKey: 2 | subKey: asdfasdf 3 | -------------------------------------------------------------------------------- /examples/update-yaml-file/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: update-yaml-file 5 | title: Update a yaml file 6 | description: Opens a PR with updates to a yaml file. 7 | 8 | spec: 9 | owner: engineering 10 | type: example 11 | parameters: 12 | - title: Provide some simple information 13 | required: ['value'] 14 | properties: 15 | value: 16 | title: The new value 17 | type: string 18 | description: Update myKey.subKey in the yaml file 19 | 20 | steps: 21 | - id: fetchPlain 22 | name: Fetch the file 23 | action: fetch:plain 24 | input: 25 | url: ./ 26 | 27 | - id: update 28 | name: Update 29 | action: roadiehq:utils:merge 30 | input: 31 | # This file must exist at this path in the repo referenced above 32 | path: my-file.yaml 33 | content: 34 | myKey: 35 | subKey: ${{ parameters.value }} 36 | 37 | - id: publish 38 | name: Publish 39 | action: publish:github:pull-request 40 | input: 41 | repoUrl: github.com?repo=software-templates&owner=RoadieHQ 42 | title: Update my-file.yaml 43 | description: update description 44 | targetPath: examples/update-yaml-file 45 | branchName: update-my-file # TODO parameterise? 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /scaffolder-templates/add-branch-protection/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: add-branch-protection 5 | title: Add Branch Protection 6 | description: Turn on branch protection with some sensible defaults. 7 | 8 | spec: 9 | owner: group:roadiehq/engineering 10 | type: file 11 | 12 | parameters: 13 | - title: Where is your codebase? 14 | required: 15 | - repoName 16 | properties: 17 | repoHost: 18 | type: string 19 | default: github.com 20 | ui:widget: hidden 21 | repoOrg: 22 | type: string 23 | default: roadiehq # Change this to match the name of your GitHub org 24 | ui:widget: hidden 25 | repoName: 26 | title: Repository name 27 | type: string 28 | branch: 29 | title: Default branch 30 | type: string 31 | default: main 32 | 33 | - title: Branch protection settings 34 | properties: 35 | allowForcePushes: 36 | title: Allow force pushes 37 | type: boolean 38 | default: false 39 | requiredApprovingRevewCount: 40 | title: Approving reviews required to merge 41 | type: number 42 | default: 1 43 | 44 | 45 | steps: 46 | - id: callGitHubApi 47 | name: Turn on branch protection 48 | action: http:backstage:request 49 | input: 50 | method: 'PUT' 51 | path: /proxy/mygithub/api/repos/${{ parameters.repoOrg }}/${{ parameters.repoName }}/branches/${{ parameters.branch }}/protection 52 | headers: 53 | content-type: 'application/json' 54 | body: 55 | required_status_checks: null 56 | enforce_admins: true 57 | required_pull_request_reviews: 58 | dismiss_stale_reviews: true 59 | required_approving_review_count: ${{ parameters.requiredApprovingRevewCount }} 60 | require_last_push_approval: true 61 | restrictions: null 62 | required_linear_history: false 63 | allow_force_pushes: ${{ parameters.allowForcePushes }} 64 | allow_deletions: true 65 | block_creations: false 66 | required_conversation_resolution: false 67 | lock_branch: false 68 | allow_fork_syncing: true 69 | 70 | output: 71 | links: 72 | - title: Go to branch protection settings 73 | icon: github 74 | url: https://github.com/${{ parameters.repoOrg }}/${{ parameters.repoName }}/settings/branches 75 | -------------------------------------------------------------------------------- /scaffolder-templates/add-codeowners/skeleton/CODEOWNERS.njk: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in 5 | # the repo. Unless a later match takes precedence, 6 | # @global-owner1 and @global-owner2 will be requested for 7 | # review when someone opens a pull request. 8 | * @global-owner1 @global-owner2 9 | 10 | # Order is important; the last matching pattern takes the most 11 | # precedence. When someone opens a pull request that only 12 | # modifies JS files, only @js-owner and not the global 13 | # owner(s) will be requested for a review. 14 | *.js @js-owner #This is an inline comment. 15 | 16 | # You can also use email addresses if you prefer. They'll be 17 | # used to look up users just like we do for commit author 18 | # emails. 19 | *.go docs@example.com 20 | 21 | # Teams can be specified as code owners as well. Teams should 22 | # be identified in the format @org/team-name. Teams must have 23 | # explicit write access to the repository. In this example, 24 | # the octocats team in the octo-org organization owns all .txt files. 25 | *.txt @octo-org/octocats 26 | 27 | # In this example, @doctocat owns any files in the build/logs 28 | # directory at the root of the repository and any of its 29 | # subdirectories. 30 | /build/logs/ @doctocat 31 | 32 | # The `docs/*` pattern will match files like 33 | # `docs/getting-started.md` but not further nested files like 34 | # `docs/build-app/troubleshooting.md`. 35 | docs/* docs@example.com 36 | 37 | # In this example, @octocat owns any file in an apps directory 38 | # anywhere in your repository. 39 | apps/ @octocat 40 | 41 | # In this example, @doctocat owns any file in the `/docs` 42 | # directory in the root of your repository and any of its 43 | # subdirectories. 44 | /docs/ @doctocat 45 | 46 | # In this example, any change inside the `/scripts` directory 47 | # will require approval from @doctocat or @octocat. 48 | /scripts/ @doctocat @octocat 49 | 50 | # In this example, @octocat owns any file in a `/logs` directory such as 51 | # `/build/logs`, `/scripts/logs`, and `/deeply/nested/logs`. Any changes 52 | # in a `/logs` directory will require approval from @octocat. 53 | **/logs @octocat 54 | 55 | # In this example, @octocat owns any file in the `/apps` 56 | # directory in the root of your repository except for the `/apps/github` 57 | # subdirectory, as its owners are left empty. 58 | /apps/ @octocat 59 | /apps/github 60 | 61 | # In this example, @octocat owns any file in the `/apps` 62 | # directory in the root of your repository except for the `/apps/github` 63 | # subdirectory, as this subdirectory has its own owner @doctocat 64 | /apps/ @octocat 65 | /apps/github @doctocat 66 | -------------------------------------------------------------------------------- /scaffolder-templates/add-codeowners/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-codeowners-in-repo 5 | title: Create a CODEOWNERS file 6 | description: Create a new PR with a basic CODEOWNERS file. 7 | spec: 8 | owner: group:roadiehq/engineering 9 | type: file 10 | 11 | parameters: 12 | - title: Basic info 13 | required: 14 | - repoName 15 | properties: 16 | repoHost: 17 | type: string 18 | default: github.com 19 | ui:widget: hidden 20 | repoOrg: 21 | type: string 22 | default: roadiehq # Change this to match the name of your GitHub org 23 | ui:widget: hidden 24 | repoName: 25 | title: Repository name 26 | type: string 27 | 28 | steps: 29 | - id: fetchTemplate 30 | action: fetch:template 31 | input: 32 | url: ./skeleton 33 | templateFileExtension: .njk 34 | 35 | - id: createPullRequest 36 | name: create-pull-request 37 | action: publish:github:pull-request 38 | input: 39 | repoUrl: ${{ parameters.repoHost }}?owner=${{ parameters.repoOrg }}&repo=${{ parameters.repoName }} 40 | branchName: add-codeowners-${{ '' | now }} 41 | title: Add a CODEOWENERS file 42 | description: | 43 | This PR adds a basic CODEOWNERS file to this repository. It must be edited to be correct. 44 | 45 | [Learn about CODEOWNERS on GitHub](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners) 46 | 47 | It was created via a [scaffolder template on Roadie](https://example.com). 48 | 49 | output: 50 | links: 51 | - title: View the pull request on GitHub 52 | icon: github 53 | url: ${{ steps['createPullRequest'].output.remoteUrl }} 54 | - title: Learn about CODEOWNERS 55 | icon: help 56 | url: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 57 | -------------------------------------------------------------------------------- /scaffolder-templates/add-security-tools-yaml/skeleton/security-tools.yml.njk: -------------------------------------------------------------------------------- 1 | # Tribe and Squad identification 2 | tribe: ${{ values.tribe }} 3 | squad: ${{ values.squad }} 4 | 5 | security_tools: 6 | 7 | # Secrets Detection 8 | secrets_detection: 9 | enabled: ${{ 1 if values.secretsDetectionEnabled else 0 }} 10 | secrets_scanning: ${{ 1 if values.secretsDetectionScanning else 0 }} 11 | pr_based: 12 | enabled: ${{ 1 if values.secretsDetectionPRs else 0 }} 13 | 14 | # Static Application Security Testing (SAST) 15 | sast: 16 | enabled: ${{ 1 if values.sastEnabled else 0 }} 17 | tools: 18 | codeQL: 19 | enabled: ${{ 1 if values.codeQLEnabled else 0 }} 20 | config_file_path: ${{ values.codeQLConfigFilePath }} 21 | veracode: 22 | enabled: ${{ 1 if values.veracodeEnabled else 0 }} 23 | sonarcloud: 24 | enabled: ${{ 1 if values.sonarcloudEnabled else 0 }} 25 | sobelow: 26 | enabled: ${{ 1 if values.sobelowEnabled else 0 }} 27 | credo: 28 | enabled: ${{ 1 if values.credoEnabled else 0 }} 29 | klocwork: 30 | enabled: ${{ 1 if values.klocworkEnabled else 0 }} 31 | -------------------------------------------------------------------------------- /scaffolder-templates/add-security-tools-yaml/template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: scaffolder.backstage.io/v1beta3 3 | kind: Template 4 | metadata: 5 | name: add-security-tools-yaml 6 | title: Add security tools YAML 7 | description: The security tools YAML helps InfoSec to understand which security tools your project is using. This template is an easy way to create the file. 8 | spec: 9 | owner: group:roadiehq/engineering 10 | type: file 11 | 12 | parameters: 13 | - title: Where is your codebase? 14 | required: 15 | - repoName 16 | properties: 17 | repoHost: 18 | type: string 19 | default: github.com 20 | ui:widget: hidden 21 | repoOrg: 22 | type: string 23 | default: roadiehq # Change this to match the name of your GitHub org 24 | ui:widget: hidden 25 | repoName: 26 | title: Repository name 27 | type: string 28 | 29 | - title: Who owns the codebase? 30 | required: 31 | - tribe 32 | - squad 33 | properties: 34 | tribe: 35 | title: Tribe Name 36 | type: string 37 | squad: 38 | title: Squad Name 39 | type: string 40 | 41 | 42 | - title: Secrets Detection 43 | properties: 44 | secretsDetectionEnabled: 45 | title: Is secrets detection enabled on the repo? 46 | type: boolean 47 | secretsDetectionScanning: 48 | title: Is secrets detection scanning enabled on the repo? 49 | type: boolean 50 | secretsDetectionPRs: 51 | title: Are automated PRs opened against scanned repos? 52 | type: boolean 53 | 54 | - title: Static Application Security Testing (SAST) 55 | properties: 56 | sastEnabled: 57 | title: Is SAST enabled on your repo? 58 | type: boolean 59 | codeQLEnabled: 60 | title: Is CodeQL enabled on the repo? 61 | type: boolean 62 | codeQLConfigFilePath: 63 | title: CodeQL file path 64 | type: string 65 | default: '.github/workflows/codeql.yml' 66 | veracodeEnabled: 67 | title: Is Veracode enabled on the repo? 68 | type: boolean 69 | sonarcloudEnabled: 70 | title: Is SonarCloud enabled on the repo? 71 | type: boolean 72 | sobelowEnabled: 73 | title: Is Sobelow enabled on the repo? 74 | type: boolean 75 | credoEnabled: 76 | title: Is Credo enabled on the repo? 77 | type: boolean 78 | klocworkEnabled: 79 | title: Is klocwork enabled on the repo? 80 | type: boolean 81 | 82 | steps: 83 | - id: fetchTemplate 84 | name: Fetch a skeleton security tools file. 85 | action: fetch:template 86 | input: 87 | url: ./skeleton 88 | templateFileExtension: .njk 89 | values: 90 | repoOrg: ${{ parameters.repoOrg }} 91 | repoSlug: ${{ parameters.repoSlug }} 92 | tribe: ${{ parameters.tribe }} 93 | squad: ${{ parameters.squad }} 94 | secretsDetectionEnabled: ${{ parameters.secretsDetectionEnabled }} 95 | secretsDetectionScanning: ${{ parameters.secretsDetectionScanning }} 96 | secretsDetectionPRs: ${{ parameters.secretsDetectionPRs }} 97 | sastEnabled: ${{ parameters.sastEnabled }} 98 | codeQLEnabled: ${{ parameters.codeQLEnabled }} 99 | codeQLConfigFilePath: ${{ parameters.codeQLConfigFilePath }} 100 | veracodeEnabled: ${{ parameters.veracodeEnabled }} 101 | sonarcloudEnabled: ${{ parameters.sonarcloudEnabled }} 102 | sobelowEnabled: ${{ parameters.sobelowEnabled }} 103 | credoEnabled: ${{ parameters.credoEnabled }} 104 | klocworkEnabled: ${{ parameters.klocworkEnabled }} 105 | 106 | - id: createPullRequest 107 | name: Open a PR 108 | action: publish:github:pull-request 109 | input: 110 | repoUrl: ${{ parameters.repoHost }}?owner=${{ parameters.repoOrg }}&repo=${{ parameters.repoName }} 111 | # We append 'now' to the branch name to make the branch name unique. Otherwise the step will fail 112 | # if we run it against the same repo twice. 113 | branchName: add-security-tools-yaml-${{ '' | now }} 114 | title: Add security tools YAML file 115 | # This shows up in the body of the PR. You can use markdown. 116 | description: | 117 | The security tools YAML helps InfoSec to understand which security tools your project is using. 118 | It's created via a [scaffolder template on Roadie](https://example.com). 119 | 120 | output: 121 | links: 122 | - title: View the pull request on GitHub 123 | icon: github 124 | url: ${{ steps['createPullRequest'].output.remoteUrl }} 125 | - title: Read the Security Tools Documentation 126 | icon: help 127 | url: https://example.com 128 | -------------------------------------------------------------------------------- /scaffolder-templates/add-tenant-to-alerts/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: finalize-new-customer 5 | title: Finalize a new customer 6 | description: Adds the new customer to the PagerDuty alerts and tags them in Intercome with "customer" 7 | 8 | spec: 9 | owner: user:ianlink 10 | type: service 11 | 12 | parameters: 13 | - title: Provide some simple information 14 | required: 15 | - tenant_name 16 | properties: 17 | tenant_name: 18 | title: Name 19 | type: string 20 | description: Must be tenant slug 21 | ui:autofocus: true 22 | 23 | steps: 24 | - id: fetch-alerts-file 25 | name: Fetch alerts file 26 | action: fetch:plain 27 | input: 28 | url: "https://github.com/RoadieHQ/roadie-infrastructure/blob/main/terraform/account-resources-tf/deployments/prod/" 29 | targetPath: 'fetch-folder' 30 | - id: move-alerts-file-to-workbench 31 | name: Move alerts file to a standalone location 32 | action: fs:rename 33 | input: 34 | files: 35 | - from: 'fetch-folder/alertable_tenants.json' 36 | to: './alerts-folder/alertable_tenants.json' 37 | - id: parse-alerts 38 | name: Parse retrieved alerts file 39 | action: roadiehq:utils:fs:parse 40 | input: 41 | path: './alerts-folder/alertable_tenants.json' 42 | - id: log-result 43 | name: "Parse Alerts Output" 44 | action: debug:log 45 | input: 46 | message: 'Alerts content: ${{ steps["parse-alerts"].output.content }}' 47 | - id: add-tenant-to-list 48 | name: Add tenant 49 | action: roadiehq:utils:jsonata:json:transform 50 | input: 51 | path: './alerts-folder/alertable_tenants.json' 52 | loadAll: true 53 | expression: '$.tenant_slugs ~> $append("${{parameters.tenant_name}}") ~> $sort()' 54 | - id: write-alerts-to-file 55 | name: Overwrite the existing alerts file with new contents 56 | action: roadiehq:utils:fs:write 57 | input: 58 | path: './alerts-folder/alertable_tenants.json' 59 | content: '{ "tenant_slugs": ${{ steps["add-tenant-to-list"].output.result }} }' 60 | - id: parse-alerts 61 | name: Parse modified Alerts file 62 | action: roadiehq:utils:fs:parse 63 | input: 64 | path: './alerts-folder/alertable_tenants.json' 65 | - id: log-result 66 | name: Display modified alerts file 67 | action: debug:log 68 | input: 69 | message: 'alertable_tenants.json content: ${{ steps["parse-alerts"].output.content }}' 70 | - id: add-customer-tag 71 | name: Add Customer Tag 72 | action: http:backstage:request 73 | input: 74 | method: POST 75 | path: /proxy/intercom/tags 76 | body: | 77 | { 78 | "name": "Customer", 79 | "companies": [ 80 | { 81 | "company_id": "${{parameters.tenant_name}}" 82 | } 83 | ] 84 | } 85 | - id: log-result 86 | name: Display modified alerts file 87 | action: debug:log 88 | input: 89 | message: '${{ steps["add-customer-tag"].output.content }}' 90 | - id: createPullRequest 91 | name: Create a pull request 92 | action: publish:github:pull-request 93 | input: 94 | sourcePath: ./alerts-folder/ 95 | targetPath: ./terraform/account-resources-tf/deployments/prod/ 96 | repoUrl: github.com?repo=roadie-infrastructure&owner=RoadieHQ 97 | branchName: add-tenant-${{parameters.tenant_name}}-${{ '' | now }} 98 | title: A tenant ${{parameters.tenant_name}} to alerts tenant list 99 | description: "This PR updates the alertable_tenants.json file with the ${{parameters.tenant_name}} tenant slug." 100 | output: 101 | links: 102 | - title: View the pull request on GitHub 103 | icon: github 104 | url: ${{ steps['createPullRequest'].output.remoteUrl }} -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/.env: -------------------------------------------------------------------------------- 1 | # These variables are only available in your SST code. 2 | # To apply them to your Lambda functions, checkout this doc - https://docs.serverless-stack.com/environment-variables#environment-variables-in-lambda-functions 3 | 4 | MY_ENV_VAR=i-am-an-environment-variable 5 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/.github/workflows/merge.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: {} 9 | 10 | jobs: 11 | deploy-dev: 12 | strategy: 13 | matrix: 14 | node-version: [14.x] 15 | 16 | env: 17 | AWS_PROFILE: default 18 | 19 | runs-on: ubuntu-latest 20 | name: Deploy 21 | steps: 22 | - uses: Fooji/create-aws-profile-action@v1 23 | with: 24 | profile: default 25 | key: ${{ secrets.AWS_ACCESS_KEY_ID }} 26 | secret: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 27 | region: eu-west-1 28 | 29 | - uses: actions/checkout@v2 30 | - name: Use Node.js 14.x 31 | uses: actions/setup-node@v1 32 | with: 33 | node-version: 14.x 34 | - run: yarn install 35 | - run: yarn deploy --stage prod -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/.github/workflows/pull-request.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pre Merge Tests 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | tests: 11 | strategy: 12 | matrix: 13 | node-version: [12.x] 14 | 15 | runs-on: ubuntu-latest 16 | name: Run Tests 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Use Node.js 14.x 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: 12.x 23 | - run: yarn install 24 | - run: yarn prettier:check 25 | - run: yarn test 26 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # typescript 13 | *.js 14 | *.d.ts 15 | 16 | # misc 17 | .DS_Store 18 | 19 | # sst build output 20 | .build 21 | .sst 22 | 23 | # environments 24 | .env*.local 25 | 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Serverless Stack (SST) 2 | 3 | This project was bootstrapped with [Create Serverless Stack](https://docs.serverless-stack.com/packages/create-serverless-stack). 4 | 5 | Start by installing the dependencies. 6 | 7 | ```bash 8 | $ npm install 9 | ``` 10 | 11 | ## Commands 12 | 13 | ### `npm run start` 14 | 15 | Starts the local Lambda development environment. 16 | 17 | ### `npm run build` 18 | 19 | Build your app and synthesize your stacks. 20 | 21 | Generates a `.build/` directory with the compiled files and a `.build/cdk.out/` directory with the synthesized CloudFormation stacks. 22 | 23 | ### `npm run deploy [stack]` 24 | 25 | Deploy all your stacks to AWS. Or optionally deploy a specific stack. 26 | 27 | ### `npm run remove [stack]` 28 | 29 | Remove all your stacks and all of their resources from AWS. Or optionally remove a specific stack. 30 | 31 | ### `npm run test` 32 | 33 | Runs your tests using Jest. Takes all the [Jest CLI options](https://jestjs.io/docs/en/cli). 34 | 35 | ## Documentation 36 | 37 | Learn more about the Serverless Stack. 38 | 39 | - [Docs](https://docs.serverless-stack.com) 40 | - [@serverless-stack/cli](https://docs.serverless-stack.com/packages/cli) 41 | - [@serverless-stack/resources](https://docs.serverless-stack.com/packages/resources) 42 | 43 | ## Community 44 | 45 | [Follow us on Twitter](https://twitter.com/ServerlessStack) or [post on our forums](https://discourse.serverless-stack.com). 46 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: ${{values.component_id | dump}} 5 | description: ${{values.description | dump}} 6 | annotations: 7 | github.com/project-slug: ${{values.destination.owner + "/" + values.destination.repo}} 8 | backstage.io/techdocs-ref: dir:. 9 | spec: 10 | type: website 11 | lifecycle: experimental 12 | owner: ${{values.owner | dump}} 13 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: ${{values.component_id | dump}} 2 | site_description: ${{values.description | dump}} 3 | 4 | nav: 5 | - Introduction: index.md 6 | 7 | plugins: 8 | - techdocs-core 9 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{values.component_id}}", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "sst test", 7 | "start": "sst start", 8 | "build": "sst build", 9 | "deploy": "sst deploy", 10 | "remove": "sst remove" 11 | }, 12 | "eslintConfig": { 13 | "extends": ["serverless-stack"] 14 | }, 15 | "devDependencies": { 16 | "@aws-cdk/assert": "1.126.0", 17 | "@types/aws-lambda": "^8.10.70" 18 | }, 19 | "dependencies": { 20 | "@serverless-stack/cli": "0.49.0", 21 | "@serverless-stack/resources": "0.49.0", 22 | "@aws-cdk/core": "1.126.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/src/lambda.ts: -------------------------------------------------------------------------------- 1 | import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from "aws-lambda"; 2 | 3 | export const handler: APIGatewayProxyHandlerV2 = async ( 4 | event: APIGatewayProxyEventV2 5 | ) => { 6 | return { 7 | statusCode: 200, 8 | headers: { "Content-Type": "text/plain" }, 9 | body: `Hello, World! Your request was received at ${event.requestContext.time}.`, 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/sst.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{values.component_id}}", 3 | "region": "us-east-1", 4 | "main": "stacks/index.ts" 5 | } 6 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/stacks/MyStack.ts: -------------------------------------------------------------------------------- 1 | import * as sst from "@serverless-stack/resources"; 2 | 3 | export default class MyStack extends sst.Stack { 4 | constructor(scope: sst.App, id: string, props?: sst.StackProps) { 5 | super(scope, id, props); 6 | 7 | // Create a HTTP API 8 | const api = new sst.Api(this, "Api", { 9 | routes: { 10 | "GET /": "src/lambda.handler", 11 | }, 12 | }); 13 | 14 | // Show the endpoint in the output 15 | this.addOutputs({ 16 | "ApiEndpoint": api.url, 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/stacks/index.ts: -------------------------------------------------------------------------------- 1 | import MyStack from "./MyStack"; 2 | import * as sst from "@serverless-stack/resources"; 3 | 4 | export default function main(app: sst.App): void { 5 | // Set default runtime for all functions 6 | app.setDefaultFunctionProps({ 7 | runtime: "nodejs12.x" 8 | }); 9 | 10 | new MyStack(app, "my-stack"); 11 | 12 | // Add more stacks 13 | } 14 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/test/MyStack.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, haveResource } from "@aws-cdk/assert"; 2 | import * as sst from "@serverless-stack/resources"; 3 | import MyStack from "../stacks/MyStack"; 4 | 5 | test("Test Stack", () => { 6 | const app = new sst.App(); 7 | // WHEN 8 | const stack = new MyStack(app, "test-stack"); 9 | // THEN 10 | expect(stack).to(haveResource("AWS::Lambda::Function")); 11 | }); 12 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/skeleton/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2018"], 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noUnusedLocals": false, 13 | "noUnusedParameters": false, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": false, 16 | "inlineSourceMap": true, 17 | "inlineSources": true, 18 | "experimentalDecorators": true, 19 | "strictPropertyInitialization": false, 20 | "typeRoots": ["./node_modules/@types"] 21 | }, 22 | "include": ["stacks", "src"] 23 | } -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-backend/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1beta2 2 | kind: Template 3 | metadata: 4 | name: create-aws-serverless-backend 5 | title: Create AWS Serverless Backend 6 | description: Create AWS Serverless Backend 7 | tags: 8 | - aws 9 | 10 | spec: 11 | owner: info@roadie.io 12 | type: api 13 | parameters: 14 | - title: Provide some simple information 15 | required: 16 | - component_id 17 | - owner 18 | - region 19 | properties: 20 | component_id: 21 | title: Name 22 | type: string 23 | description: Unique name of the component 24 | region: 25 | title: Region 26 | type: string 27 | description: AWS region to deploy this Serverless stack 28 | description: 29 | title: Description 30 | type: string 31 | description: Help others understand what this website is for. 32 | owner: 33 | title: Owner 34 | type: string 35 | description: Owner of the component 36 | ui:field: OwnerPicker 37 | ui:options: 38 | allowedKinds: 39 | - Group 40 | - title: Choose a location 41 | required: 42 | - repoUrl 43 | properties: 44 | repoUrl: 45 | title: Repository Location 46 | type: string 47 | ui:field: RepoUrlPicker 48 | ui:options: 49 | allowedHosts: 50 | - github.com 51 | steps: 52 | - id: template 53 | name: Fetch Skeleton + Template 54 | action: fetch:template 55 | input: 56 | url: ./skeleton 57 | copyWithoutRender: 58 | - .github/workflows/* 59 | values: 60 | component_id: '{{ parameters.component_id }}' 61 | description: '{{ parameters.description }}' 62 | destination: '{{ parseRepoUrl parameters.repoUrl }}' 63 | owner: '{{ parameters.owner }}' 64 | 65 | - id: publish 66 | name: Publish 67 | action: publish:github 68 | input: 69 | allowedHosts: ['github.com'] 70 | description: 'This is {{ parameters.component_id }}' 71 | repoUrl: '{{ parameters.repoUrl }}' 72 | defaultBranch: main 73 | 74 | output: 75 | remoteUrl: '{{ steps.publish.output.remoteUrl }}' -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/.github/workflows/merge.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: {} 9 | 10 | jobs: 11 | deploy-dev: 12 | strategy: 13 | matrix: 14 | node-version: [14.x] 15 | 16 | env: 17 | AWS_PROFILE: default 18 | 19 | runs-on: ubuntu-latest 20 | name: Deploy 21 | steps: 22 | - uses: Fooji/create-aws-profile-action@v1 23 | with: 24 | profile: default 25 | key: ${{ secrets.AWS_ACCESS_KEY_ID }} 26 | secret: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 27 | region: eu-west-1 28 | 29 | - uses: actions/checkout@v2 30 | - name: Use Node.js 14.x 31 | uses: actions/setup-node@v1 32 | with: 33 | node-version: 14.x 34 | - run: yarn install 35 | - run: cd frontend && yarn install && cd .. 36 | - run: yarn build --stage prod 37 | - run: yarn deploy --stage prod -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/.github/workflows/pull-request.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pre Merge Tests 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | tests: 11 | strategy: 12 | matrix: 13 | node-version: [12.x] 14 | 15 | runs-on: ubuntu-latest 16 | name: Run Tests 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Use Node.js 14.x 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: 12.x 23 | - run: yarn install 24 | - run: yarn prettier:check 25 | - run: yarn test 26 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | 15 | # sst build output 16 | .build 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # How to create a React.js app 2 | 3 | An example full-stack serverless React.js app created with SST. 4 | 5 | ## Getting Started 6 | 7 | [**Read the tutorial**](https://serverless-stack.com/examples/how-to-create-a-reactjs-app-with-serverless.html) 8 | 9 | Install the example. 10 | 11 | ```bash 12 | $ npm init serverless-stack --example react-app 13 | # Or with Yarn 14 | $ yarn create serverless-stack --example react-app 15 | ``` 16 | 17 | ## Commands 18 | 19 | ### `npm run start` 20 | 21 | Starts the Live Lambda Development environment. 22 | 23 | ### `npm run build` 24 | 25 | Build your app and synthesize your stacks. 26 | 27 | ### `npm run deploy [stack]` 28 | 29 | Deploy all your stacks to AWS. Or optionally deploy, a specific stack. 30 | 31 | ### `npm run remove [stack]` 32 | 33 | Remove all your stacks and all of their resources from AWS. Or optionally removes, a specific stack. 34 | 35 | ### `npm run test` 36 | 37 | Runs your tests using Jest. Takes all the [Jest CLI options](https://jestjs.io/docs/en/cli). 38 | 39 | ## Documentation 40 | 41 | Learn more about the SST. 42 | 43 | - [Docs](https://docs.serverless-stack.com/) 44 | - [@serverless-stack/cli](https://docs.serverless-stack.com/packages/cli) 45 | - [@serverless-stack/resources](https://docs.serverless-stack.com/packages/resources) 46 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: ${{values.component_id | dump}} 5 | description: ${{values.description | dump}} 6 | annotations: 7 | github.com/project-slug: ${{values.destination.owner + "/" + values.destination.repo}} 8 | backstage.io/techdocs-ref: dir:. 9 | spec: 10 | type: website 11 | lifecycle: experimental 12 | owner: ${{values.owner | dump}} 13 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true 2 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `yarn start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `yarn build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `yarn eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `yarn build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "react": "^17.0.2", 10 | "react-dom": "^17.0.2", 11 | "react-scripts": "4.0.3", 12 | "web-vitals": "^1.0.1" 13 | }, 14 | "scripts": { 15 | "start": "sst-env -- react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | }, 38 | "devDependencies": { 39 | "@serverless-stack/static-site-env": "^0.33.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RoadieHQ/software-templates/c830d43d36df4a2aac60a020902d46e5b7f31902/scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/favicon.ico -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RoadieHQ/software-templates/c830d43d36df4a2aac60a020902d46e5b7f31902/scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/logo192.png -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RoadieHQ/software-templates/c830d43d36df4a2aac60a020902d46e5b7f31902/scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/logo512.png -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/App.css: -------------------------------------------------------------------------------- 1 | body, 2 | html { 3 | height: 100%; 4 | display: grid; 5 | } 6 | #root { 7 | margin: auto; 8 | } 9 | .App { 10 | text-align: center; 11 | } 12 | p { 13 | margin-top: 0; 14 | font-size: 20px; 15 | } 16 | button { 17 | font-size: 48px; 18 | } 19 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./App.css"; 3 | 4 | export default function App() { 5 | const [count, setCount] = useState(null); 6 | 7 | function onClick() { 8 | fetch(process.env.REACT_APP_API_URL, { 9 | method: "POST", 10 | }) 11 | .then((response) => response.text()) 12 | .then(setCount); 13 | } 14 | 15 | return ( 16 |
17 | {count &&

You clicked me {count} times.

} 18 | 19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import App from "./App"; 3 | 4 | test("renders learn react link", () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById("root") 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/frontend/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import "@testing-library/jest-dom"; 6 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: ${{values.component_id | dump}} 2 | site_description: ${{values.description | dump}} 3 | 4 | nav: 5 | - Introduction: index.md 6 | 7 | plugins: 8 | - techdocs-core 9 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{values.component_id}}", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "sst test", 7 | "start": "sst start", 8 | "build": "sst build", 9 | "deploy": "sst deploy", 10 | "remove": "sst remove" 11 | }, 12 | "eslintConfig": { 13 | "extends": [ 14 | "serverless-stack" 15 | ] 16 | }, 17 | "dependencies": { 18 | "@serverless-stack/cli": "0.48.0", 19 | "@serverless-stack/resources": "0.48.0", 20 | "aws-sdk": "^2.931.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/src/lambda.js: -------------------------------------------------------------------------------- 1 | import AWS from "aws-sdk"; 2 | 3 | const dynamoDb = new AWS.DynamoDB.DocumentClient(); 4 | 5 | export async function main() { 6 | const getParams = { 7 | // Get the table name from the environment variable 8 | TableName: process.env.tableName, 9 | // Get the row where the counter is called "clicks" 10 | Key: { 11 | counter: "clicks", 12 | }, 13 | }; 14 | const results = await dynamoDb.get(getParams).promise(); 15 | 16 | // If there is a row, then get the value of the 17 | // column called "tally" 18 | let count = results.Item ? results.Item.tally : 0; 19 | 20 | const putParams = { 21 | TableName: process.env.tableName, 22 | Key: { 23 | counter: "clicks", 24 | }, 25 | // Update the "tally" column 26 | UpdateExpression: "SET tally = :count", 27 | ExpressionAttributeValues: { 28 | // Increase the count 29 | ":count": ++count, 30 | }, 31 | }; 32 | await dynamoDb.update(putParams).promise(); 33 | 34 | return { 35 | statusCode: 200, 36 | body: count, 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/sst.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{values.component_id}}", 3 | "region": "us-east-1", 4 | "main": "stacks/index.js" 5 | } 6 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/stacks/MyStack.js: -------------------------------------------------------------------------------- 1 | import * as sst from "@serverless-stack/resources"; 2 | 3 | export default class MyStack extends sst.Stack { 4 | constructor(scope, id, props) { 5 | super(scope, id, props); 6 | 7 | // Create the table 8 | const table = new sst.Table(this, "Counter", { 9 | fields: { 10 | counter: sst.TableFieldType.STRING, 11 | }, 12 | primaryIndex: { partitionKey: "counter" }, 13 | }); 14 | 15 | // Create the HTTP API 16 | const api = new sst.Api(this, "Api", { 17 | defaultFunctionProps: { 18 | // Pass in the table name to our API 19 | environment: { 20 | tableName: table.dynamodbTable.tableName, 21 | }, 22 | }, 23 | routes: { 24 | "POST /": "src/lambda.main", 25 | }, 26 | }); 27 | 28 | // Allow the API to access the table 29 | api.attachPermissions([table]); 30 | 31 | // Deploy our React app 32 | const site = new sst.ReactStaticSite(this, "ReactSite", { 33 | path: "frontend", 34 | environment: { 35 | REACT_APP_API_URL: api.url, 36 | }, 37 | }); 38 | 39 | // Show the URLs in the output 40 | this.addOutputs({ 41 | SiteUrl: site.url, 42 | ApiEndpoint: api.url, 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/stacks/index.js: -------------------------------------------------------------------------------- 1 | import MyStack from "./MyStack"; 2 | 3 | export default function main(app) { 4 | // Set default runtime for all functions 5 | app.setDefaultFunctionProps({ 6 | runtime: "nodejs12.x", 7 | }); 8 | 9 | new MyStack(app, "my-stack"); 10 | 11 | // Add more stacks 12 | } 13 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/skeleton/test/MyStack.test.js: -------------------------------------------------------------------------------- 1 | import { expect, haveResource } from "@aws-cdk/assert"; 2 | import * as sst from "@serverless-stack/resources"; 3 | import MyStack from "../stacks/MyStack"; 4 | 5 | test("Test Stack", () => { 6 | const app = new sst.App(); 7 | // WHEN 8 | const stack = new MyStack(app, "test-stack"); 9 | // THEN 10 | expect(stack).to(haveResource("AWS::Lambda::Function")); 11 | }); 12 | -------------------------------------------------------------------------------- /scaffolder-templates/create-aws-serverless-frontend-and-backend/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1beta2 2 | kind: Template 3 | metadata: 4 | name: create-aws-serverless-frontend-and-backend 5 | title: Create AWS Serverless Frontend and Backend 6 | description: Create AWS Serverless Frontend and Backend 7 | tags: 8 | - aws 9 | 10 | spec: 11 | owner: info@roadie.io 12 | type: service 13 | parameters: 14 | - title: Provide some simple information 15 | required: 16 | - component_id 17 | - owner 18 | - region 19 | properties: 20 | component_id: 21 | title: Name 22 | type: string 23 | description: Unique name of the component 24 | region: 25 | title: Region 26 | type: string 27 | description: AWS region to deploy this Serverless stack 28 | description: 29 | title: Description 30 | type: string 31 | description: Help others understand what this website is for. 32 | owner: 33 | title: Owner 34 | type: string 35 | description: Owner of the component 36 | ui:field: OwnerPicker 37 | ui:options: 38 | allowedKinds: 39 | - Group 40 | - title: Choose a location 41 | required: 42 | - repoUrl 43 | properties: 44 | repoUrl: 45 | title: Repository Location 46 | type: string 47 | ui:field: RepoUrlPicker 48 | ui:options: 49 | allowedHosts: 50 | - github.com 51 | steps: 52 | - id: template 53 | name: Fetch Skeleton + Template 54 | action: fetch:template 55 | input: 56 | url: ./skeleton 57 | copyWithoutRender: 58 | - .github/workflows/* 59 | values: 60 | component_id: '{{ parameters.component_id }}' 61 | description: '{{ parameters.description }}' 62 | destination: '{{ parseRepoUrl parameters.repoUrl }}' 63 | owner: '{{ parameters.owner }}' 64 | 65 | - id: publish 66 | name: Publish 67 | action: publish:github 68 | input: 69 | allowedHosts: ['github.com'] 70 | description: 'This is {{ parameters.component_id }}' 71 | repoUrl: '{{ parameters.repoUrl }}' 72 | defaultBranch: main 73 | 74 | output: 75 | remoteUrl: '{{ steps.publish.output.remoteUrl }}' 76 | -------------------------------------------------------------------------------- /scaffolder-templates/create-empty-project/skeleton/.github/workflows/pull-request.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pre Merge Tests 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | tests: 11 | runs-on: ubuntu-latest 12 | name: Run Tests 13 | steps: 14 | - uses: actions/checkout@v2 15 | - run: true 16 | -------------------------------------------------------------------------------- /scaffolder-templates/create-empty-project/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # ${{values.component_id}} 2 | 3 | ${{values.description}} 4 | 5 | ## Local Development 6 | 7 | ### Building 8 | 9 | ### Running 10 | 11 | ### Testing 12 | 13 | ## Deployment 14 | 15 | -------------------------------------------------------------------------------- /scaffolder-templates/create-empty-project/skeleton/catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: ${{values.component_id | dump}} 5 | description: ${{values.description | dump}} 6 | annotations: 7 | github.com/project-slug: ${{values.destination.owner + "/" + values.destination.repo}} 8 | backstage.io/techdocs-ref: dir:. 9 | spec: 10 | type: ${{values.type}} 11 | lifecycle: experimental 12 | owner: ${{values.owner | dump}} 13 | -------------------------------------------------------------------------------- /scaffolder-templates/create-empty-project/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-empty-project 5 | title: Create Empty Project 6 | description: Create Empty Project 7 | 8 | spec: 9 | owner: info@roadie.io 10 | type: service 11 | parameters: 12 | - title: Provide some simple information 13 | required: 14 | - component_id 15 | - owner 16 | - description 17 | - type 18 | properties: 19 | component_id: 20 | title: Name 21 | type: string 22 | description: Unique name of the component 23 | description: 24 | title: Description 25 | type: string 26 | description: Help others understand what this project is for. 27 | type: 28 | title: Type of Component 29 | type: string 30 | description: service, library, etc. 31 | enum: ["service", "library", "website", "other"] 32 | owner: 33 | title: Owner 34 | type: string 35 | description: Owner of the component 36 | ui:field: OwnerPicker 37 | ui:options: 38 | allowedKinds: 39 | - Group 40 | - title: Choose a location 41 | description: | 42 | This section will ask for details about the Owner and Repository name which will then be used 43 | to create a repository in that location using your GitHub credentials. 44 | required: 45 | - repoUrl 46 | properties: 47 | repoUrl: 48 | title: Enter an Owner and Repository Name 49 | description: | 50 | The Owner should be your GitHub username. The Repository name should be a name that is not one that exists already in your GitHub account. 51 | type: string 52 | ui:field: RepoUrlPicker 53 | ui:options: 54 | requestUserCredentials: 55 | secretsKey: USER_OAUTH_TOKEN 56 | additionalScopes: 57 | github: 58 | - workflow 59 | allowedHosts: 60 | - github.com 61 | - bitbucket.org 62 | steps: 63 | - id: template 64 | name: Fetch Skeleton + Template 65 | action: fetch:template 66 | input: 67 | url: ./skeleton 68 | copyWithoutRender: 69 | - .github/workflows/* 70 | values: 71 | component_id: ${{ parameters.component_id }} 72 | description: ${{ parameters.description }} 73 | destination: ${{ parameters.repoUrl | parseRepoUrl }} 74 | owner: ${{ parameters.owner }} 75 | type: ${{ parameters.type }} 76 | 77 | - id: publish 78 | name: Publish 79 | action: publish:github 80 | input: 81 | allowedHosts: ['github.com'] 82 | description: 'This is ${{ parameters.component_id }}' 83 | repoUrl: ${{ parameters.repoUrl }} 84 | defaultBranch: main 85 | requireCodeOwnerReviews: true 86 | deleteBranchOnMerge: true 87 | 88 | 89 | output: 90 | remoteUrl: '{{ steps.publish.output.remoteUrl }}' 91 | links: 92 | - title: Repository 93 | url: ${{ steps.publish.output.remoteUrl }} 94 | 95 | 96 | -------------------------------------------------------------------------------- /scaffolder-templates/create-readme/skeleton/README.md.njk: -------------------------------------------------------------------------------- 1 | # ${{ values.name }} 2 | 3 | ## Why write a README? 4 | 5 | - It is the first file a person will see when they encounter your project, so it should be fairly brief but detailed. 6 | - It will make your project standout from a bunch of others. Also be sure your project is good too. 7 | - It will help you focus on what your project needs to deliver and how. 8 | 9 | ## The most important README sections 10 | 11 | ### 1. Project's Title 12 | 13 | This is the name of the project. It describes the whole project in one sentence, and helps people understand what the main goal and aim of the project is. 14 | 15 | ### 2. Project Description 16 | 17 | This is an important component of your project that many new developers often overlook. 18 | 19 | Your description is an extremely important aspect of your project. A well-crafted description allows you to show off your work to other developers as well as potential employers. 20 | 21 | The quality of a README description often differentiates a good project from a bad project. A good one takes advantage of the opportunity to explain and showcase: 22 | 23 | - What your application does, 24 | - Why you used the technologies you used, 25 | - Some of the challenges you faced and features you hope to implement in the future. 26 | 27 | ### 3. Table of Contents (Optional) 28 | 29 | If your README is very long, you might want to add a table of contents to make it easy for users to navigate to different sections easily. It will make it easier for readers to move around the project with ease. 30 | 31 | ### 4. How to Install and Run the Project 32 | 33 | If you are working on a project that a user needs to install or run locally in a machine like a "POS", you should include the steps required to install your project and also the required dependencies if any. 34 | 35 | Provide a step-by-step description of how to get the development environment set and running. 36 | 37 | ### 5. How to Use the Project 38 | 39 | Provide instructions and examples so users/contributors can use the project. This will make it easy for them in case they encounter a problem – they will always have a place to reference what is expected. 40 | 41 | You can also make use of visual aids by including materials like screenshots to show examples of the running project and also the structure and design principles used in your project. 42 | 43 | Also if your project will require authentication like passwords or usernames, this is a good section to include the credentials. 44 | 45 | ### 6. Include Credits 46 | 47 | If you worked on the project as a team or an organization, list your collaborators/team members. You should also include links to their GitHub profiles and social media too. 48 | 49 | Also, if you followed tutorials or referenced a certain material that might help the user to build that particular project, include links to those here as well. 50 | 51 | This is just a way to show your appreciation and also to help others get a first hand copy of the project. 52 | -------------------------------------------------------------------------------- /scaffolder-templates/create-readme/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-readme-in-repo 5 | title: Create a README 6 | description: Create a new PR with a basic README file. 7 | spec: 8 | owner: group:roadiehq/engineering 9 | type: file 10 | 11 | parameters: 12 | - title: Basic info 13 | required: 14 | - repoName 15 | - name 16 | properties: 17 | repoHost: 18 | type: string 19 | default: github.com 20 | ui:widget: hidden 21 | repoOrg: 22 | type: string 23 | default: roadiehq # Change this to match the name of your GitHub org 24 | ui:widget: hidden 25 | repoName: 26 | title: Repository name 27 | type: string 28 | name: 29 | title: Human readable service name 30 | type: string 31 | 32 | steps: 33 | - id: fetchTemplate 34 | action: fetch:template 35 | input: 36 | url: ./skeleton 37 | templateFileExtension: .njk 38 | values: 39 | name: ${{ parameters.name }} 40 | 41 | - id: createPullRequest 42 | name: create-pull-request 43 | action: publish:github:pull-request 44 | input: 45 | repoUrl: ${{ parameters.repoHost }}?owner=${{ parameters.repoOrg }}&repo=${{ parameters.repoName }} 46 | branchName: add-readme-${{ '' | now }} 47 | title: Add a README file 48 | description: | 49 | This PR adds a basic README file to this repository. 50 | 51 | It was created via a [scaffolder template on Roadie](https://example.com). 52 | 53 | output: 54 | links: 55 | - title: View the pull request on GitHub 56 | icon: github 57 | url: ${{ steps['createPullRequest'].output.remoteUrl }} 58 | - title: Learn about writing READMEs 59 | icon: help 60 | url: https://example.com 61 | -------------------------------------------------------------------------------- /scaffolder-templates/create-rfc/skeleton/template.md.njk: -------------------------------------------------------------------------------- 1 | # RFC-${{ values.rfcNumber }} - ${{ values.rfcTitle }} 2 | 3 | *Author(s)*: 4 | *Squad*: 5 | *Requested Reviewers*: 6 | *Status*: DRAFT 7 | 8 | ## Abstract 9 | ${{ values.abstract }} 10 | 11 | ## Background 12 | 13 | ## Non-Goals 14 | 15 | ## Key Terms 16 | 17 | ## Problem 18 | 19 | ## Proposal 20 | 21 | ## Technical Limitations 22 | 23 | ## Open Questions 24 | 25 | ## Outcomes and Forward References -------------------------------------------------------------------------------- /scaffolder-templates/create-rfc/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-rfc-template 5 | title: Create a new RFC flavored markdown document 6 | description: Create a new RFC flavored markdown document 7 | spec: 8 | owner: group:default/engineering 9 | type: service 10 | 11 | parameters: 12 | - title: Document front content 13 | properties: 14 | rfcNumber: 15 | title: rfcNumber 16 | type: string 17 | rfcTitle: 18 | title: RFC Title 19 | type: string 20 | abstract: 21 | title: Document Abstract (optional draft version) 22 | type: string 23 | ui:widget: textarea 24 | - title: Repository to place document 25 | properties: 26 | repoUrl: 27 | content: 28 | type: string 29 | description: Name of repository 30 | ui:field: RepoUrlPicker 31 | ui:options: 32 | allowedHosts: 33 | - github.com 34 | 35 | steps: 36 | - id: log-message 37 | name: Log Message 38 | action: debug:log 39 | input: 40 | message: Creating ${{ parameters.rfcNumber }}/index.md 41 | 42 | - id: fetch-template 43 | action: fetch:template 44 | input: 45 | url: https://github.com/RoadieHQ/software-templates/tree/main/scaffolder-templates/create-rfc/skeleton 46 | templateFileExtension: true 47 | targetPath: docs/rfcs/${{ parameters.rfcNumber }} 48 | values: 49 | rfcNumber: ${{ parameters.rfcNumber }} 50 | rfcTitle: ${{ parameters.rfcTitle }} 51 | abstract: ${{ parameters.abstract }} 52 | 53 | - id: move-rfc 54 | action: fs:rename 55 | input: 56 | files: 57 | - from: docs/rfcs/${{ parameters.rfcNumber }}/template.md 58 | to: docs/rfcs/${{ parameters.rfcNumber }}/index.md 59 | 60 | - id: create-pull-request 61 | name: create-pull-request 62 | action: publish:github:pull-request 63 | input: 64 | repoUrl: ${{ parameters.repoUrl }} 65 | branchName: RFC-${{ parameters.rfcNumber }}_${{ parameters.rfcTitle | replace(" ", "-") | replace("\"", "") | replace ("'", "") | lower }} 66 | title: RFC-${{ parameters.rfcNumber }} - ${{ parameters.rfcTitle }} 67 | description: ${{ parameters.abstract }} -------------------------------------------------------------------------------- /scaffolder-templates/create-tenant/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-tenant 5 | title: Create Tenant 6 | description: Send an API call to the tenant manager to create a tenant. 7 | tags: 8 | - Roadie 9 | 10 | spec: 11 | owner: group:roadiehq/solutions 12 | type: Tenant 13 | parameters: 14 | - title: Provide some simple information 15 | required: 16 | - tenant_name 17 | - tenant_email_domain 18 | - admin_email 19 | - tenant_environment 20 | properties: 21 | tenant_name: 22 | title: Name 23 | type: string 24 | description: The name of the tenant, used for the tenant slug. 25 | ui:autofocus: true 26 | maxLength: 30 27 | pattern: '^[a-z][a-z1-9-]*[a-z1-9]+$' 28 | ui:help: Lowercase characters, dash (-), and underscore (_) only. 29 | tenant_email_domain: 30 | title: Email domain 31 | type: string 32 | description: The email domain of users who will be allowed to access the tenant. 33 | pattern: '^[a-zA-Z0-9-]+.[a-zA-Z0-9-]+' 34 | admin_email: 35 | title: Admin email 36 | type: string 37 | description: The email of the person who will drive the evaluation. 38 | pattern: '^[a-zA-Z0-9-_.]+@[a-zA-Z0-9-.]+.[a-zA-Z0-9-]+$' 39 | tenant_environment: 40 | title: Environment 41 | type: string 42 | default: dev 43 | enum: ['dev', 'prod'] 44 | createSlack: 45 | title: Create Slack Channel? 46 | type: boolean 47 | default: false 48 | ui:widget: radio 49 | pov: 50 | title: PoV Tenant? 51 | type: boolean 52 | default: true 53 | ui:widget: radio 54 | 55 | steps: 56 | - id: createDevTenant 57 | name: Is it a Dev Tenant? 58 | if: ${{parameters.tenant_environment === 'dev'}} 59 | action: http:backstage:request 60 | input: 61 | method: 'POST' 62 | path: proxy/tenant-manager-dev/api/tenant 63 | body: | 64 | { 65 | "tenantName": "${{ parameters.tenant_name }}", 66 | "tenantEmailDomain": "${{ parameters.tenant_email_domain }}", 67 | "adminEmail": "${{ parameters.admin_email }}", 68 | "tenantEnvironment": "dev", 69 | "skipFailures": false 70 | } 71 | 72 | - id: createProdTenant 73 | name: Is it a Prod Tenant? 74 | if: ${{parameters.tenant_environment === 'prod'}} 75 | action: http:backstage:request 76 | input: 77 | method: 'POST' 78 | path: proxy/tenant-manager/api/tenant 79 | body: | 80 | { 81 | "tenantName": "${{ parameters.tenant_name }}", 82 | "tenantEmailDomain": "${{ parameters.tenant_email_domain }}", 83 | "adminEmail": "${{ parameters.admin_email }}", 84 | "tenantEnvironment": "prod", 85 | "skipFailures": false 86 | } 87 | 88 | - id: addPovTag 89 | name: Is it a PoV Tenant? 90 | if: ${{parameters.pov === true}} 91 | action: http:backstage:request 92 | input: 93 | method: 'POST' 94 | path: proxy/fragments 95 | body: | 96 | { 97 | "decorator": { 98 | "entityRef": "resource:default/${{ parameters.tenant_name }}", 99 | "fragment": { 100 | "metadata": { 101 | "tags": [ 102 | "pov" 103 | ] 104 | } 105 | } 106 | } 107 | } 108 | 109 | output: 110 | resp: ${{ steps.createDevTenant.output.body }} ${{ steps.createProdTenant.output.body }} 111 | -------------------------------------------------------------------------------- /scaffolder-templates/debug-template/skeleton/template.md.njk: -------------------------------------------------------------------------------- 1 | # RFC-${{ values.rfcNumber }} - ${{ values.rfcTitle }} 2 | 3 | *Author(s)*: 4 | *Squad*: 5 | *Requested Reviewers*: 6 | *Status*: DRAFT 7 | 8 | ## Abstract 9 | ${{ values.abstract }} 10 | 11 | ## Background 12 | 13 | ## Non-Goals 14 | 15 | ## Key Terms 16 | 17 | ## Problem 18 | 19 | ## Proposal 20 | 21 | ## Technical Limitations 22 | 23 | ## Open Questions 24 | 25 | ## Outcomes and Forward References -------------------------------------------------------------------------------- /scaffolder-templates/debug-template/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: debug-template 5 | title: Template to debug skeleton templates 6 | description: Basic template to trigger a github worklfow 7 | 8 | spec: 9 | owner: group:default/engineering 10 | type: service 11 | parameters: 12 | - title: Document front content 13 | properties: 14 | rfcNumber: 15 | title: rfcNumber 16 | type: string 17 | rfcTitle: 18 | title: RFC Title 19 | type: string 20 | abstract: 21 | title: Document Abstract (optional draft version) 22 | type: string 23 | ui:widget: textarea 24 | 25 | steps: 26 | - id: fetch-template 27 | action: fetch:template 28 | input: 29 | url: https://github.com/RoadieHQ/software-templates/tree/main/scaffolder-templates/debug-template/skeleton 30 | templateFileExtension: true 31 | values: 32 | rfcNumber: ${{ parameters.rfcNumber }} 33 | rfcTitle: ${{ parameters.rfcTitle }} 34 | abstract: ${{ parameters.abstract }} 35 | 36 | - id: read-file 37 | name: Read File 38 | action: fs:read 39 | input: 40 | path: ./template.md 41 | 42 | - id: log-message 43 | name: Log Message 44 | action: debug:log 45 | input: 46 | message: ${{ steps['read-file'].output.content }} 47 | -------------------------------------------------------------------------------- /scaffolder-templates/delete-entities/template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: scaffolder.backstage.io/v1beta3 3 | kind: Template 4 | metadata: 5 | name: delete-entities 6 | title: Delete Entities 7 | description: Deletes all entities associated with a given YAML file from the catalog. Note - if autodiscovery is turned on these entities will re-appear if the source file is not deleted before. 8 | spec: 9 | owner: roadie 10 | type: template 11 | parameters: 12 | - title: Entities to delete 13 | properties: 14 | catalog-info-url: 15 | title: Catalog info file url 16 | type: string 17 | description: The full SCM url to the YAML file you want to remove entities for from the catalog 18 | 19 | steps: 20 | - id: location 21 | name: Get Root Location 22 | action: http:backstage:request 23 | input: 24 | method: 'GET' 25 | path: '/catalog/entities?filter=spec.target=${{ parameters["catalog-info-url"] | replace("/tree/", "/blob/") }}&filter=metadata.annotations.backstage.io/managed-by-location=url:${{ parameters["catalog-info-url"] | replace("/blob/", "/tree/") }}&fields=metadata.uid,metadata.name' 26 | - id: parse 27 | name: Parse entities response 28 | if: ${{ steps.location.output.code === 200 }} 29 | action: roadiehq:utils:jsonata 30 | input: 31 | data: ${{ steps.location.output.body }} 32 | expression: '$.metadata.uid' 33 | - id: parseNames 34 | name: Parse entity names 35 | if: ${{ steps.location.output.code === 200 }} 36 | action: roadiehq:utils:jsonata 37 | input: 38 | data: ${{ steps.location.output.body }} 39 | expression: '$.metadata.name' 40 | - id: log-to-delete 41 | action: debug:log 42 | if: ${{ steps.location.output.code === 200 }} 43 | input: 44 | message: 'Deleting the following entities: ${{ steps.parseNames.output.result | string }}' 45 | - id: delete-all 46 | if: ${{ steps.parse.output.result is not string }} 47 | name: Delete entities 48 | each: ${{ steps.parse.output.result }} 49 | action: http:backstage:request 50 | input: 51 | method: 'DELETE' 52 | path: '/catalog/entities/by-uid/${{ each.value }}' 53 | - id: delete-one 54 | if: ${{ steps.parse.output.result is string }} 55 | name: Delete entity 56 | action: http:backstage:request 57 | input: 58 | method: 'DELETE' 59 | path: '/catalog/entities/by-uid/${{ steps.parse.output.result }}' 60 | - id: clean-catalog 61 | name: Clean 62 | action: http:backstage:request 63 | input: 64 | method: 'POST' 65 | path: '/catalog-extensions/refresh-state/garbage-collection' 66 | continueOnBadResponse: true 67 | - id: log-result 68 | action: debug:log 69 | input: 70 | message: 'Deleted the following entities for YAML file ${{ parameters["catalog-info-url"] }} with names: ${{ steps.parseNames.output.result | string }}' 71 | 72 | 73 | output: 74 | deletedEntityNames: ${{ steps.parseNames.output.result | string }} -------------------------------------------------------------------------------- /scaffolder-templates/delete-tenant/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: delete-tenant 5 | title: Delete tenant 6 | description: Send an API call to the tenant manager to delete a tenant. 7 | tags: 8 | - Roadie 9 | 10 | spec: 11 | owner: user:ianlink 12 | type: Tenant 13 | parameters: 14 | - title: Provide some simple information 15 | required: 16 | - tenant_name 17 | - tenant_email_domain 18 | - tenant_environment 19 | - s3_emptied 20 | - alarm_removed 21 | properties: 22 | tenant_name: 23 | title: Name 24 | type: string 25 | description: No special chars, numbers as the first char, or dashes as the first or last char. 26 | ui:autofocus: true 27 | tenant_email_domain: 28 | title: Email domain 29 | type: string 30 | description: The email domain of users who will be allowed to access the tenant.S 31 | tenant_environment: 32 | title: Environment 33 | type: string 34 | default: dev 35 | enum: ['dev', 'prod'] 36 | s3_emptied: 37 | title: Have you emptied the tenants S3 Bucket? 38 | type: boolean 39 | ui:widget: radio 40 | alarm_removed: 41 | title: Have you removed the pagerduty alert from roadie-infrastructure? 42 | type: boolean 43 | ui:widget: radio 44 | 45 | steps: 46 | - id: deleteDevTenant 47 | name: Delete development tenant 48 | if: ${{ parameters.tenant_environment === 'dev' and parameters.s3_emptied and parameters.alarm_removed }} 49 | action: http:backstage:request 50 | input: 51 | method: 'DELETE' 52 | path: proxy/tenant-manager-dev/api/tenant 53 | body: | 54 | { 55 | "tenantName": "${{ parameters.tenant_name }}", 56 | "tenantEmailDomain": "${{ parameters.tenant_email_domain }}", 57 | "tenantEnvironment": "dev", 58 | "skipFailures": false 59 | } 60 | 61 | - id: deleteProdTenant 62 | name: Delete production tenant 63 | if: ${{ parameters.tenant_environment === 'prod' and parameters.s3_emptied and parameters.alarm_removed }} 64 | action: http:backstage:request 65 | input: 66 | method: 'DELETE' 67 | path: proxy/tenant-manager/api/tenant 68 | body: | 69 | { 70 | "tenantName": "${{ parameters.tenant_name }}", 71 | "tenantEmailDomain": "${{ parameters.tenant_email_domain }}", 72 | "tenantEnvironment": "prod", 73 | "skipFailures": false 74 | } 75 | 76 | - id: notify-tenant-deletion 77 | name: Notify tenant deletion 78 | if: ${{ parameters.s3_emptied and parameters.alarm_removed }} 79 | action: 'http:backstage:request' 80 | input: 81 | method: 'POST' 82 | header: 83 | - Content-type: application/json 84 | path: /proxy/tenant-deletion-notification 85 | body: | 86 | { 87 | 'blocks': [ 88 | { 89 | 'type': 'section', 90 | 'text': { 91 | 'type': 'mrkdwn', 92 | 'text': '${{ user.entity.metadata.name }} has deleted tenant ${{ parameters.tenant_name }}.' 93 | } 94 | } 95 | ] 96 | } 97 | 98 | output: 99 | resp: ${{ steps.deleteDevTenant.output.body }} ${{ steps.deleteProdTenant.output.body }} ${{ steps.logAction.output.body }} 100 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/README.md: -------------------------------------------------------------------------------- 1 | ## GitHub Pages Website 2 | 3 | This scaffolder template will perform the following steps 4 | 5 | 1. Create a new GitHub repository with an `index.html` file in it. 6 | 2. Modify the content of the `index.html` file based on the website name the user provides when they run the scaffolder. 7 | 3. Make a HTTP request to the GitHub API to publish the `index.html` via GitHub pages. 8 | 9 | ## Pre-requisites for use outside of Roadie 10 | 11 | If you are running this software template in Roadie, you will need to set a secret GITHUB_TOKEN so that the github proxy can authenticate against GitHub. If you are running a vanilla backstage you will need to create a new proxy congfiguration like the following: 12 | 13 | ``` 14 | proxy: 15 | '/github/api': 16 | target: https://api.github.com 17 | headers: 18 | Authorization: 'token ${GITHUB_TOKEN}' 19 | ``` 20 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build_and_test: 11 | runs-on: ubuntu-latest 12 | 13 | env: 14 | CI: true 15 | NODE_ENV: test 16 | 17 | steps: 18 | - name: Log node version 19 | run: node --version 20 | 21 | - uses: actions/checkout@v2 22 | with: 23 | fetch-depth: '0' 24 | 25 | - name: Install dependencies 26 | run: yarn install --frozen-lockfile 27 | 28 | - name: Cypress run 29 | uses: cypress-io/github-action@v2 30 | with: 31 | start: yarn start --port 8001 32 | 33 | - name: Upload screenshots 34 | uses: actions/upload-artifact@v1 35 | if: failure() 36 | with: 37 | name: cypress-screenshots 38 | path: cypress/screenshots 39 | 40 | - name: Upload videos 41 | uses: actions/upload-artifact@v1 42 | if: always() 43 | with: 44 | name: cypress-videos 45 | path: cypress/videos 46 | 47 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .parcel-cache 4 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # ${{ values.website_name | title }} 2 | 3 | This is a website wihch is published on GitHub pages. 4 | 5 | ## Getting started 6 | 7 | ```bash 8 | yarn install 9 | yarn start 10 | ``` 11 | 12 | Now open up: http://localhost:1234 in your browser. 13 | 14 | ## Testing 15 | 16 | End to end tests can be written with Cypress.io. 17 | 18 | They are run locally like this: 19 | 20 | ```bash 21 | yarn test 22 | ``` 23 | 24 | ## Docs 25 | 26 | Docs can be found in the `docs` directory. They are written in markdown. 27 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: ${{ values.repo_name }} 5 | title: ${{ values.website_name | title }} 6 | description: A static HTML website. Just like the good old days. 7 | links: 8 | - url: https://${{ values.repo_owner}}.github.io/${{ values.repo_name }}/ 9 | title: Live website 10 | annotations: 11 | github.com/project-slug: ${{ values.repo_owner }}/${{ values.repo_name }} 12 | spec: 13 | type: website 14 | owner: user:dtuite 15 | lifecycle: experimental 16 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8001" 3 | } 4 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/cypress/integration/sample_spec.js: -------------------------------------------------------------------------------- 1 | describe('The website', () => { 2 | it('is accessible', () => { 3 | cy.visit(''); 4 | cy.contains('Welcome to ${{ values.website_name }}').click(); 5 | }) 6 | }) 7 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | // eslint-disable-next-line no-unused-vars 19 | module.exports = (on, config) => { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | } 23 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/docs/index.md: -------------------------------------------------------------------------------- 1 | These are the docs for the ${{ values.website_name | title }} website. 2 | 3 | This is where you would put information about getting started with the website, maybe how 4 | to authenticate etc. 5 | 6 | 7 | It's just normal markdown. For example, you can write code blocks here like this: 8 | 9 | ```js 10 | 11 | const myFunction = () => { 12 | return 'Hello World'; 13 | }; 14 | ``` 15 | 16 | When you add a new docs file, be sure to update the `mkdocs.yml` file in this repo to 17 | display the file in the sidebar. 18 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${{ values.website_name | title }} 7 | 8 | 9 |

Welcome to ${{ values.website_name }}

10 |

This website was created by following the Backstage scaffolder tutorial published by Roadie

11 | 12 | 13 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: ${{ values.website_name | title }} 2 | 3 | nav: 4 | - Home: index.md 5 | 6 | plugins: 7 | - monorepo 8 | - techdocs-core 9 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{ values.repo_name }}", 3 | "version": "0.0.1", 4 | "description": "A static HTML website. Just like the good old days.", 5 | "main": "index.js", 6 | "repository": "https://github.com/${{ values.repo_owner }}/${{ values.repo_name }}", 7 | "author": "${{ values.repo_owner }}", 8 | "license": "MIT", 9 | "private": true, 10 | "devDependencies": { 11 | "cypress": "^9.4.1", 12 | "parcel": "^2.2.1" 13 | }, 14 | "scripts": { 15 | "start": "parcel index.html", 16 | "test": "cypress open" 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/skeleton/package.json.tpl: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-pages-site-skeleton", 3 | "version": "0.0.1", 4 | "description": "A skeleton for creating a GitHub pages site.", 5 | "main": "index.js", 6 | "repository": "https://github.com/roadiehq/software-templates", 7 | "author": "David Tuite", 8 | "license": "MIT", 9 | "private": true, 10 | "devDependencies": { 11 | "cypress": "^9.4.1", 12 | "parcel": "^2.2.1" 13 | }, 14 | "scripts": { 15 | "start": "parcel index.html", 16 | "test": "cypress open" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scaffolder-templates/github-pages-site/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: github-pages-website 5 | title: GitHub Pages Website 6 | description: Create a static HTML website and publish it via GitHub pages. 7 | annotations: 8 | roadie.io/certified: "true" 9 | 10 | spec: 11 | owner: user:dtuite 12 | type: website 13 | parameters: 14 | - title: Provide some simple information 15 | required: 16 | - website_name 17 | properties: 18 | website_name: 19 | title: Website name 20 | type: string 21 | name: website-name 22 | description: This will be displayed prominently on your website and in the title tag. 23 | escalation_policy: 24 | title: PagerDuty escalation policy 25 | type: string 26 | ui:field: SelectFieldFromApi 27 | ui:options: 28 | path: "proxy/pagerduty/escalation_policies" 29 | arraySelector: 'escalation_policies' 30 | valueSelector: 'id' 31 | labelSelector: 'summary' 32 | description: 'Choose a Pagerduty Escalation policy to notify when the page goes down' 33 | 34 | 35 | - title: Choose a Source Control Management tool to store your new website in. 36 | required: 37 | - repoUrl 38 | properties: 39 | repoUrl: 40 | title: Repository Location 41 | type: string 42 | ui:field: RepoUrlPicker 43 | ui:options: 44 | allowedHosts: 45 | - github.com 46 | 47 | 48 | steps: 49 | - id: template 50 | name: Fetch Skeleton + Template 51 | action: fetch:template 52 | input: 53 | url: ./skeleton 54 | values: 55 | website_name: ${{ parameters.website_name }} 56 | repo_name: ${{ (parameters.repoUrl | parseRepoUrl)["repo"] }} 57 | repo_owner: ${{ (parameters.repoUrl | parseRepoUrl)["owner"] }} 58 | 59 | - id: publishToGitHub 60 | name: Publish to GitHub 61 | action: publish:github 62 | input: 63 | allowedHosts: ['github.com'] 64 | description: 'A static HTML website. Just like the good old days.' 65 | repoUrl: ${{ parameters.repoUrl }} 66 | defaultBranch: main 67 | repoVisibility: public 68 | 69 | - id: publishToWeb 70 | name: Publish to web with GitHub Pages 71 | action: http:backstage:request 72 | input: 73 | method: 'POST' 74 | path: /proxy/mygithub/api/repos/${{ (parameters.repoUrl | parseRepoUrl)["owner"] }}/${{ (parameters.repoUrl | parseRepoUrl)["repo"] }}/pages 75 | headers: 76 | content-type: 'application/json' 77 | body: 78 | source: 79 | branch: main 80 | path: '/' 81 | 82 | - id: registerInBetterUptime 83 | name: Register in Better Uptime 84 | action: http:backstage:request 85 | input: 86 | method: 'POST' 87 | path: /proxy/betteruptime/monitors 88 | headers: 89 | content-type: 'application/json' 90 | body: 91 | url: https://${{ (parameters.repoUrl | parseRepoUrl)["owner"] }}.github.io/${{ (parameters.repoUrl | parseRepoUrl)["repo"] }}/ 92 | 93 | output: 94 | remoteUrl: ${{ steps.publishToGitHub.output.remoteUrl }} 95 | -------------------------------------------------------------------------------- /scaffolder-templates/oneof-example/oneof-example.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: oneof-example 5 | description: An advanced template 6 | spec: 7 | type: service 8 | owner: user:guest 9 | parameters: 10 | - title: Select an Environment 11 | type: object 12 | oneOf: 13 | - properties: 14 | lorem: 15 | type: string 16 | required: 17 | - lorem 18 | title: "Lorem" 19 | - properties: 20 | ipsum: 21 | type: string 22 | required: 23 | - ipsum 24 | title: "Ipsum" 25 | 26 | steps: 27 | - id: log 28 | name: Log 29 | action: debug:log 30 | input: 31 | message: ${{ parameters.lorem }} ${{ parameters.ipsum }} 32 | -------------------------------------------------------------------------------- /scaffolder-templates/pr-with-catalog-entry/skeleton/catalog-info.yaml.njk: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: ${{ values.name }} 5 | title: ${{ values.name | replace(" ", "-") | lower}} 6 | description: ${{ values.description }} 7 | annotations: 8 | github.com/project-slug: ${{ values.repoOrg }}/${{ values.repoSlug }} 9 | {%if values.argoAppName %}argocd/app-name: ${{values.argoAppName}} {% endif %} 10 | {%if values.pagerdutyServiceId %}pagerduty.com/service-id: ${{values.pagerdutyServiceId}} {% endif %} 11 | spec: 12 | type: ${{ values.type }} 13 | owner: ${{ values.owner }} 14 | lifecycle: ${{ values.lifecycle }} 15 | -------------------------------------------------------------------------------- /scaffolder-templates/pr-with-catalog-entry/template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: scaffolder.backstage.io/v1beta3 3 | kind: Template 4 | metadata: 5 | name: open-pr-with-catalog-entry 6 | title: Onboard your service to Backstage 7 | description: Create a new PR with your service's details. 8 | spec: 9 | owner: group:roadiehq/engineering 10 | type: service 11 | 12 | parameters: 13 | - title: What is your service about? 14 | required: 15 | - name 16 | - description 17 | - type 18 | - lifecycle 19 | properties: 20 | name: 21 | title: Service name 22 | type: string 23 | description: Human readable name. We'll generate a dasherized version from it. 24 | 25 | description: 26 | title: Service description 27 | type: string 28 | 29 | type: 30 | title: Service type 31 | type: string 32 | default: service 33 | enum: ['service', 'website', 'test', 'documentation', 'library'] 34 | 35 | lifecycle: 36 | title: Service lifecycle 37 | type: string 38 | default: production 39 | enum: ['production', 'experimental', 'deprecated'] 40 | 41 | owner: 42 | title: Service Owner 43 | type: string 44 | description: Owner of the component 45 | ui:field: OwnerPicker 46 | ui:options: 47 | catalogFilter: 48 | kind: Group 49 | 50 | - title: Where is your codebase? 51 | required: 52 | - repoSlug 53 | properties: 54 | repoHost: 55 | type: string 56 | default: github.com 57 | ui:widget: hidden 58 | repoOrg: 59 | type: string 60 | default: roadiehq # Change this to match the name of your GitHub org 61 | ui:widget: hidden 62 | repoSlug: 63 | title: Repository name 64 | type: string 65 | 66 | - title: Integrations (optional) 67 | properties: 68 | argoAppName: 69 | title: Argo CD App Name 70 | type: string 71 | pagerdutyServiceId: 72 | title: PagerDuty service ID 73 | type: string 74 | 75 | steps: 76 | - id: fetchTemplate 77 | action: fetch:template 78 | input: 79 | url: ./skeleton 80 | templateFileExtension: .njk 81 | values: 82 | name: ${{ parameters.name }} 83 | description: ${{ parameters.description }} 84 | owner: ${{ parameters.owner }} 85 | type: ${{ parameters.type }} 86 | repoOrg: ${{ parameters.repoOrg }} 87 | repoSlug: ${{ parameters.repoSlug }} 88 | argoAppName: ${{ parameters.argoAppName }} 89 | pagerdutyServiceId: ${{ parameters.pagerdutyServiceId }} 90 | lifecycle: ${{ parameters.lifecycle }} 91 | 92 | - id: createPullRequest 93 | name: createPullRequest 94 | action: publish:github:pull-request 95 | input: 96 | repoUrl: ${{ parameters.repoHost }}?owner=${{ parameters.repoOrg }}&repo=${{ parameters.repoSlug }} 97 | branchName: onboard-to-catalog-${{ '' | now }} 98 | title: Onboard service to Catalog 99 | description: This PR adds a metadata file about this service so that it can be registered in our software catalog. 100 | 101 | output: 102 | links: 103 | - title: View the pull request on GitHub 104 | icon: github 105 | url: ${{ steps['createPullRequest'].output.remoteUrl }} 106 | -------------------------------------------------------------------------------- /scaffolder-templates/pull-request-test/skeleton/new-change.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: image.toolkit.fluxcd.io/v1beta1 3 | kind: ImageRepository 4 | metadata: 5 | name: tenant-backstage 6 | namespace: flux-system 7 | spec: 8 | image: account_id.dkr.ecr.region.amazonaws.com/${{ values.tenant_name }}-backstage 9 | interval: 1m0s 10 | secretRef: 11 | name: ecr-secret 12 | --- 13 | apiVersion: image.toolkit.fluxcd.io/v1beta1 14 | kind: ImagePolicy 15 | metadata: 16 | name: tenant-backstage 17 | namespace: flux-system 18 | spec: 19 | imageRepositoryRef: 20 | name: ${{ values.tenant_name }}-backstage 21 | filterTags: 22 | pattern: ".*-(?P[0-9T]*)$" 23 | extract: "$date" 24 | policy: 25 | alphabetical: 26 | order: asc 27 | -------------------------------------------------------------------------------- /scaffolder-templates/pull-request-test/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: open-pull-request 5 | title: Open pull request 6 | description: Open a pull request against an IaaC repo. 7 | 8 | spec: 9 | owner: user:dtuite 10 | type: none 11 | parameters: 12 | - title: Provide some simple information 13 | required: 14 | - tenant_name 15 | properties: 16 | tenant_name: 17 | title: Name 18 | type: string 19 | description: No special chars, numbers as the first char, or dashes as the first or last char. 20 | ui:autofocus: true 21 | 22 | steps: 23 | 24 | - id: fetchTemplate 25 | name: Fetch diff 26 | action: fetch:template 27 | input: 28 | url: ./skeleton 29 | values: 30 | tenant_name: ${{ parameters.tenant_name }} 31 | 32 | - id: openPullRequest 33 | name: Open pull request 34 | action: publish:github:pull-request 35 | input: 36 | repoUrl: 'github.com?repo=demo-iaac-repo&owner=RoadieHQ' 37 | branchName: mybranch-124 38 | title: Make a change to state 39 | description: 'This is an automated PR' 40 | 41 | - id: log-message 42 | name: Log Message 43 | action: debug:log 44 | input: 45 | message: 'RemoteURL: ${{ steps.openPullRequest.output.remoteUrl }}, ${{ steps.openPullRequest.output.pullRequestNumber }}!' 46 | 47 | output: 48 | resp: ${{ steps.openPullRequest.output.remoteUrl }} 49 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/skeleton/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | ARG TOKEN=example-broker-token 4 | 5 | ENV BROKER_TOKEN $TOKEN 6 | 7 | WORKDIR /app 8 | 9 | COPY yarn.lock package.json ./ 10 | COPY src ./src 11 | COPY config ./config 12 | 13 | RUN apk add --no-cache tini 14 | 15 | RUN cd /app 16 | 17 | RUN yarn install --frozen-lockfile 18 | 19 | ENTRYPOINT ["/sbin/tini", "--"] 20 | CMD ["node", "src/index"] 21 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # Roadie Agent Entity Provider 2 | 3 | See Roadie Agent documentation in https://github.com/RoadieHQ/roadie-agent. 4 | 5 | ## Usage 6 | 7 | Configure your Roadie instance to allow traffic from the IP address this Agent service is running. 8 | Enable and register a Roadie Agent `entity-provider` connection type in Roadie. The token used by this agent service should be configured as environment variable `BROKER_TOKEN`, the name of the Agent provider is `${{ values.agent_name }}`. 9 | 10 | Modify the example entity handler in `src/myEntityHandler.js` to provide entities to your liking. 11 | 12 | ## Running 13 | 14 | Locally: 15 | * `yarn` 16 | * `yarn start` 17 | 18 | ## As a container 19 | 20 | Build the container: 21 | `docker build . --tag my-agent` 22 | 23 | Run the container: 24 | `docker run --env BROKER_TOKEN=my-broker-token my-agent ` 25 | 26 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/skeleton/config/accept.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": [ 3 | { 4 | "method": "GET", 5 | "path": "/agent-provider/*", 6 | "origin": "http://localhost:7044" 7 | } 8 | ], 9 | "public": [ 10 | { 11 | "method": "any", 12 | "path": "/*" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roadie-agent-entity-provider", 3 | "version": "1.0.0", 4 | "description": "A Roadie Agent Entity Provider.", 5 | "main": "index.js", 6 | "repository": "https://github.com/${{ values.repo_owner }}/${{ values.repo_name }}", 7 | "author": "${{ values.repo_owner }}", 8 | "license": "UNLICENSED", 9 | "type": "module", 10 | "scripts": { 11 | "start": "node src/index.js" 12 | }, 13 | "dependencies": { 14 | "@roadiehq/roadie-agent": "^1.1.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/skeleton/src/index.js: -------------------------------------------------------------------------------- 1 | import { RoadieAgent, createRoadieAgentEntityProvider } from '@roadiehq/roadie-agent'; 2 | import { myEntityHandler } from './myEntityHandler.js'; 3 | 4 | RoadieAgent.fromConfig({ 5 | server: 'https://${{ values.tenant }}.broker.roadie.so', 6 | accept: `${process.cwd()}/config/accept.json`, 7 | identifier: process.env.BROKER_TOKEN 8 | }) 9 | .addEntityProvider(createRoadieAgentEntityProvider({ 10 | handler: myEntityHandler, 11 | name: '${{ values.agent_name }}' 12 | })) 13 | .start(); 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/skeleton/src/myEntityHandler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A fake payload example 3 | * Replace this with your own implementation to retrieve actual entity information from within your infrastructure 4 | */ 5 | const fakePayload = { 6 | type: 'full', 7 | entities: [ 8 | { 9 | entity: { 10 | metadata: { 11 | namespace: 'default', 12 | annotations: {}, 13 | name: 'locally-provided-group-entity', 14 | title: 'Locally provided entity', 15 | description: 16 | 'Entity that is provided via Broker connection from an entity provider running on a separate machine', 17 | }, 18 | apiVersion: 'backstage.io/v1alpha1', 19 | kind: 'Group', 20 | spec: { 21 | type: 'team', 22 | profile: { 23 | displayName: 'Locally provided group entity', 24 | email: 'team-alpha@example.com', 25 | picture: 26 | 'https://avatars.dicebear.com/api/identicon/team-alpha@example.com.svg?background=%23fff&margin=25', 27 | }, 28 | children: [], 29 | }, 30 | }, 31 | }, 32 | ], 33 | }; 34 | 35 | export const myEntityHandler = async (emit) => { 36 | await emit(fakePayload); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-entity-provider/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-roadie-agent-entity-provider 5 | title: Create Roadie Agent Entity Provider 6 | description: Create a Roadie Agent service repository to provide entities securely from your infrastructure 7 | 8 | spec: 9 | owner: info@roadie.io 10 | type: service 11 | parameters: 12 | - title: Provide some simple information 13 | required: 14 | - agent_name 15 | properties: 16 | agent_name: 17 | title: Name 18 | type: string 19 | description: Unique name of the Roadie Agent Entity Provider. 20 | 21 | - title: Choose a Source Control Management tool to store your Roadie Agent Service in. 22 | required: 23 | - repoUrl 24 | properties: 25 | repoUrl: 26 | title: Repository Location 27 | type: string 28 | ui:field: RepoUrlPicker 29 | ui:options: 30 | allowedHosts: 31 | - github.com 32 | steps: 33 | - id: template 34 | name: Fetch Skeleton + Template 35 | action: fetch:template 36 | input: 37 | url: ./skeleton 38 | values: 39 | repo_name: ${{ (parameters.repoUrl | parseRepoUrl)["repo"] }} 40 | repo_owner: ${{ (parameters.repoUrl | parseRepoUrl)["owner"] }} 41 | tenant: ${{ roadie.tenantName }} 42 | agent_name: ${{ parameters.agent_name }} 43 | 44 | - id: publish 45 | name: Publish 46 | action: publish:github 47 | input: 48 | allowedHosts: ['github.com'] 49 | description: 'This is ${{ parameters.agent_name }}' 50 | repoUrl: ${{ parameters.repoUrl }} 51 | defaultBranch: main 52 | 53 | output: 54 | remoteUrl: ${{ steps.publish.output.remoteUrl }} 55 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/skeleton/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | ARG TOKEN=${{ values.agent_name }} 4 | 5 | ENV BROKER_TOKEN $TOKEN 6 | 7 | WORKDIR /app 8 | 9 | COPY yarn.lock package.json ./ 10 | COPY src ./src 11 | COPY config ./config 12 | 13 | RUN apk add --no-cache tini 14 | 15 | RUN cd /app 16 | 17 | RUN yarn install --frozen-lockfile 18 | 19 | ENTRYPOINT ["/sbin/tini", "--"] 20 | CMD ["node", "src/index"] 21 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # Roadie Agent Scaffolder Action 2 | 3 | See Roadie Agent documentation in https://github.com/RoadieHQ/roadie-agent. 4 | 5 | ## Usage 6 | 7 | Configure your Roadie instance to allow traffic from the IP address this Agent service is running. 8 | Enable and register a Roadie Agent `scaffolder-action` connection type in Roadie. The token used by this agent service should be configured as environment variable `BROKER_TOKEN`, the name of the Agent action is `${{ values.agent_name }}`. 9 | 10 | Modify the example scaffolder action handler in `src/myScaffolderActionHandler.js` to run the custom scaffolder code. 11 | 12 | ## Running 13 | 14 | Locally: 15 | * `yarn` 16 | * `yarn start` 17 | 18 | ## As a container 19 | 20 | Build the container: 21 | `docker build . --tag my-agent` 22 | 23 | Run the container: 24 | `docker run --env BROKER_TOKEN=my-broker-token my-agent ` 25 | 26 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/skeleton/config/accept.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": [ 3 | { 4 | "method": "POST", 5 | "path": "/scaffolder-action/*", 6 | "origin": "http://localhost:7044" 7 | } 8 | ], 9 | "public": [ 10 | { 11 | "method": "any", 12 | "path": "/*" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roadie-agent-scaffolder-action", 3 | "version": "1.0.0", 4 | "description": "A Roadie Agent Scaffolder Action.", 5 | "main": "index.js", 6 | "repository": "https://github.com/${{ values.repo_owner }}/${{ values.repo_name }}", 7 | "author": "${{ values.repo_owner }}", 8 | "license": "UNLICENSED", 9 | "type": "module", 10 | "scripts": { 11 | "start": "node src/index.js" 12 | }, 13 | "dependencies": { 14 | "@roadiehq/roadie-agent": "^1.1.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/skeleton/src/helloWorldScaffolderActionHandler.js: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from "fs"; 2 | 3 | export const helloWorldScaffolderActionHandler = async (context) => { 4 | try { 5 | const greeting = `Hello, ${context.payload.body.name || 'world!'}` 6 | await context.log(greeting); 7 | writeFileSync(`${context.workspacePath}/greeting.txt`, greeting); 8 | } catch (e) { 9 | console.log('An error occurred'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/skeleton/src/index.js: -------------------------------------------------------------------------------- 1 | import { RoadieAgent, createRoadieAgentScaffolderAction } from '@roadiehq/roadie-agent'; 2 | import { helloWorldScaffolderActionHandler } from './helloWorldScaffolderActionHandler.js'; 3 | 4 | RoadieAgent.fromConfig({ 5 | server: 'https://${{ values.tenant }}.broker.roadie.so', 6 | accept: `${process.cwd()}/config/accept.json`, 7 | identifier: process.env.BROKER_TOKEN 8 | }) 9 | .addScaffolderAction(createRoadieAgentScaffolderAction({ 10 | name: 'hello-world', 11 | handler: helloWorldScaffolderActionHandler 12 | })) 13 | .start(); 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-agent-scaffolder-action/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-roadie-agent-scaffolder-action-mono-repo 5 | title: Create Roadie Agent Scaffolder Action Repository 6 | description: Create a Roadie Agent service repository to execute a scaffolder action from your infrastructure. You can run this once to create the repo, and then add multiple scaffolder actions in the created repo. 7 | 8 | spec: 9 | owner: info@roadie.io 10 | type: service 11 | parameters: 12 | - title: Provide some simple information 13 | required: 14 | - agent_name 15 | properties: 16 | agent_name: 17 | title: Name 18 | type: string 19 | description: Unique name of the Roadie Agent Scaffolder Action repository. 20 | 21 | - title: Choose a Source Control Management tool to store your Roadie Agent Service in. 22 | required: 23 | - repoUrl 24 | properties: 25 | repoUrl: 26 | title: Repository Location 27 | type: string 28 | ui:field: RepoUrlPicker 29 | ui:options: 30 | allowedHosts: 31 | - github.com 32 | steps: 33 | - id: template 34 | name: Fetch Skeleton + Template 35 | action: fetch:template 36 | input: 37 | url: ./skeleton 38 | values: 39 | repo_name: ${{ (parameters.repoUrl | parseRepoUrl)["repo"] }} 40 | repo_owner: ${{ (parameters.repoUrl | parseRepoUrl)["owner"] }} 41 | tenant: ${{ roadie.tenantName }} 42 | agent_name: ${{ parameters.agent_name }} 43 | 44 | - id: publish 45 | name: Publish 46 | action: publish:github 47 | input: 48 | allowedHosts: ['github.com'] 49 | description: 'This is ${{ parameters.agent_name }}' 50 | repoUrl: ${{ parameters.repoUrl }} 51 | defaultBranch: main 52 | 53 | output: 54 | remoteUrl: ${{ steps.publish.output.remoteUrl }} 55 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); 2 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # Roadie Plugins monorepo 2 | 3 | Welcome to Roadie plugins monorepo! 4 | 5 | _This plugin was created through a scaffolder template_ 6 | 7 | ## Getting started 8 | 9 | This is a TypeScript monorepo repository containing a place to hold and develop Roadie plugins. 10 | 11 | ### Repository structure 12 | 13 | The root level contains configuration files to hold the structure of the monorepo and a top level package.json file. 14 | 15 | The folder `packages` hosts the actual plugins and code files related to them in individual folders. Each plugin has their own `package.json` configuration pre-filled with some useful scripts to develop, build and deploy Roadie plugins. 16 | 17 | ### Installing 18 | 19 | This repository needs `node.js` (> 18.x) and `NPM` installed. 20 | 21 | To install needed dependencies, run: 22 | `npm i -f` or `npm install --force` 23 | 24 | ### Running and developing plugins 25 | 26 | Plugins within the repository can all be run from within the root folder. 27 | 28 | Example commands, if your plugin is named `${{ values.plugin_name }}` 29 | 30 | #### Run in development mode 31 | 32 | This will build the plugin code and start a webserver to host the generated Roadie compatible plugin assets. 33 | 34 | `npm run develop --workspace=${{ values.plugin_name }}` 35 | 36 | #### Run in development mode, with a file watcher 37 | 38 | This will build the plugin code and start a webserver while listening to file changes within the plugin folder. Each change to a file restarts the webserver, allowing for a faster development workflow 39 | 40 | `npm run develop:watch --workspace=${{ values.plugin_name }}` 41 | 42 | 43 | #### Bundling a production build of a plugin 44 | 45 | This will build your wanted plugin and output the generated Roadie compatible assets to the defined folder, so they can be uploaded to a static hosting site. 46 | 47 | ` npm run build --workspace=${{ values.plugin_name }} --host https://my-static-hosting.com/${{ values.plugin_name }}` 48 | 49 | 50 | #### Bundling a production build of a plugin and uploading it to AWS S3 51 | 52 | This will build your wanted plugin and output the generated Roadie compatible assets to the defined folder, and uploads the generated Roadie compatible assets to AWS S3. The command uses environment variables `S3_BUCKET_NAME` & `S3_BUCKET_PREFIX` to determine the S3 bucket and path. Normal AWS credential chain is used to determine AWS credentials. 53 | 54 | ` npm run build:upload:awsS3 --workspace=${{ values.plugin_name }} --host https://static-assets.roadie.so/` 55 | 56 | 57 | 58 | 59 | > For more information, take a look at the package.json within the plugin folder and Roadie CLI documentation in https://www.npmjs.com/package/@roadiehq/roadie-cli 60 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roadie-plugins", 3 | "version": "1.0.0", 4 | "description": "Roadie Plugins monorepo", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "help": "roadie" 9 | }, 10 | "workspaces": ["plugins/*"], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@backstage/cli": "^0.22.8", 15 | "@backstage/core-components": "^0.13.2", 16 | "@backstage/plugin-catalog-react": "^1.7.0", 17 | "@material-ui/core": "^4.12.2", 18 | "@roadiehq/roadie-cli": "^1.1.1", 19 | "react": "^17.0.2", 20 | "react-dom": "^17.0.2" 21 | }, 22 | "devDependencies": { 23 | "@aoberoi/chokidar-cli": "^2.0.0", 24 | "@spotify/prettier-config": "^14.0.0", 25 | "prettier": "^2.3.2", 26 | "ts-node": "^10.9.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); 2 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/README.md: -------------------------------------------------------------------------------- 1 | # my-plugin 2 | 3 | Welcome to the ${{ values.plugin_name }} plugin! 4 | 5 | _This plugin was created through the Backstage CLI_ 6 | 7 | ## Getting started 8 | 9 | To install needed dependencies, run: 10 | `npm i` or `npm install` 11 | 12 | ### Standalone development 13 | 14 | You can serve the plugin in isolation by running `npm start` in the plugin directory. 15 | This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. 16 | It is only meant for local development, and the setup for it can be found inside the [/dev](dev) directory. 17 | 18 | ### Developing against Roadie instances 19 | 20 | Each command defined below will provide instructions on how to install the plugin to Roadie application. 21 | 22 | #### Run in development mode 23 | 24 | This will build the plugin code and start a webserver to host the generated Roadie compatible plugin assets. 25 | 26 | `npm run develop` 27 | 28 | #### Run in development mode, with a file watcher 29 | 30 | This will build the plugin code and start a webserver while listening to file changes within the plugin folder. Each change to a file restarts the webserver, allowing for a faster development workflow 31 | 32 | `npm run develop:watch` 33 | 34 | 35 | #### Bundling a production build of a plugin 36 | 37 | This will build your wanted plugin and output the generated Roadie compatible assets to the defined folder, so they can be uploaded to a static hosting site. 38 | 39 | ` npm run build --host https://my-static-hosting.com/${{ values.plugin_name }}` 40 | 41 | 42 | #### Bundling a production build of a plugin and uploading it to AWS S3 43 | 44 | This will build your wanted plugin and output the generated Roadie compatible assets to the defined folder, and uploads the generated Roadie compatible assets to AWS S3. The command uses environment variables `S3_BUCKET_NAME` & `S3_BUCKET_PREFIX` to determine the S3 bucket and path. Normal AWS credential chain is used to determine AWS credentials. 45 | 46 | ` npm run build:upload:s3 --host https://my-static-hosting.com/${{ values.plugin_name }}` 47 | 48 | 49 | 50 | > For more information, take a look at the package.json within the plugin folder and Roadie CLI documentation in https://www.npmjs.com/package/@roadiehq/roadie-cli 51 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/app-config.yaml: -------------------------------------------------------------------------------- 1 | app: 2 | baseUrl: http://localhost:3333 3 | backend: 4 | baseUrl: http://localhost:7777 5 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/dev/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { createDevApp } from "@backstage/dev-utils"; 3 | import { myPluginPlugin, MyPluginPage } from "../src/plugin"; 4 | import { EntityProvider } from "@backstage/plugin-catalog-react"; 5 | import { Entity } from "@backstage/catalog-model"; 6 | 7 | const entity = { 8 | apiVersion: "backstage.io/v1alpha1", 9 | kind: "Component", 10 | metadata: { 11 | name: 'awesome-test-entity-1', 12 | }, 13 | } as Entity; 14 | 15 | createDevApp() 16 | .registerPlugin(myPluginPlugin) 17 | .addPage({ 18 | element: ( 19 | 20 | 21 | 22 | ), 23 | title: "Root Page", 24 | path: "/my-plugin", 25 | }) 26 | .render(); -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{ values.plugin_name }}", 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 | "scripts": { 17 | "develop": "roadie plugin:dev -l $PWD/ --output $PWD/out --port 7046", 18 | "develop:watch": "chokidar \"./src/**\" -c \"npm run develop\" -d 1000 --initial", 19 | "build": "roadie plugin:build -l $PWD/ --output $PWD/out --host", 20 | "build:upload:awsS3": "roadie plugin:build --withUpload -l $PWD/ --output $PWD/out --host", 21 | "start": "backstage-cli package start", 22 | "lint": "backstage-cli package lint", 23 | "test": "backstage-cli package test" 24 | }, 25 | "dependencies": { 26 | "@backstage/core-components": "^0.13.2", 27 | "@backstage/core-plugin-api": "^1.5.2", 28 | "@backstage/theme": "^0.4.0", 29 | "@material-ui/core": "^4.12.2", 30 | "@material-ui/icons": "^4.9.1", 31 | "@material-ui/lab": "4.0.0-alpha.61", 32 | "react-router-dom": "^7.1.5", 33 | "react-use": "~17.2.4" 34 | }, 35 | "peerDependencies": { 36 | "react": "^16.13.1 || ^17.0.0" 37 | }, 38 | "devDependencies": { 39 | "@aoberoi/chokidar-cli": "^2.0.0", 40 | "@backstage/cli": "^0.29.4", 41 | "@backstage/core-app-api": "^1.15.3", 42 | "@backstage/dev-utils": "^1.0.16", 43 | "@backstage/test-utils": "^1.7.3", 44 | "@roadiehq/roadie-cli": "^1.1.1", 45 | "@testing-library/jest-dom": "^5.10.1", 46 | "@testing-library/react": "^12.1.3", 47 | "@testing-library/user-event": "^14.0.0", 48 | "@types/node": "^16.11.26", 49 | "msw": "^1.0.0", 50 | "ts-node": "^10.9.1" 51 | }, 52 | "files": [ 53 | "dist" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/components/EntityComponentExample/EntityContentComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useEntity } from "@backstage/plugin-catalog-react"; 3 | import { Grid } from "@material-ui/core"; 4 | import { 5 | Page, 6 | Content, 7 | ContentHeader, 8 | SupportButton, 9 | } from "@backstage/core-components"; 10 | import { ExampleFetchComponent } from "../ExampleFetchComponent"; 11 | 12 | export const EntityContentComponent = () => { 13 | const { entity } = useEntity(); 14 | console.info(`Displaying data for ${JSON.stringify(entity)}`); 15 | return ( 16 | 17 | 18 | 19 | My Custom Roadie Plugin 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/components/EntityComponentExample/index.ts: -------------------------------------------------------------------------------- 1 | export { EntityContentComponent } from "./EntityContentComponent"; 2 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/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 my-plugin!')).toBeInTheDocument(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/components/ExampleComponent/ExampleComponent.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Typography, Grid } 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 | export const ExampleComponent = () => ( 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | A description of your plugin goes here. 23 | 24 | 25 | 26 | 27 | 28 | All content should be wrapped in a card like this. 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | ); 39 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/components/ExampleComponent/index.ts: -------------------------------------------------------------------------------- 1 | export { ExampleComponent } from "./ExampleComponent"; 2 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/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 | import { TestApiProvider } from "@backstage/test-utils"; 5 | import { analyticsApiRef } from "@backstage/core-plugin-api"; 6 | 7 | const mockAnalyticsApi = { 8 | captureEvent: jest.fn(), 9 | }; 10 | 11 | describe("ExampleFetchComponent", () => { 12 | it("renders the user table", async () => { 13 | render( 14 | 15 | 16 | 17 | ); 18 | 19 | // Wait for the table to render 20 | const table = await screen.findByRole("table"); 21 | const nationality = screen.getAllByText("GB"); 22 | 23 | // Assert that the table contains the expected user data 24 | expect(table).toBeInTheDocument(); 25 | expect(screen.getByAltText("Carolyn")).toBeInTheDocument(); 26 | expect(screen.getByText("Carolyn Moore")).toBeInTheDocument(); 27 | expect(screen.getByText("carolyn.moore@example.com")).toBeInTheDocument(); 28 | expect(nationality[0]).toBeInTheDocument(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { makeStyles } from "@material-ui/core/styles"; 3 | import { 4 | Table, 5 | TableColumn, 6 | Progress, 7 | ResponseErrorPanel, 8 | } from "@backstage/core-components"; 9 | import useAsync from "react-use/lib/useAsync"; 10 | import { analyticsApiRef, useApi } from "@backstage/core-plugin-api"; 11 | 12 | export const exampleUsers = { 13 | results: [ 14 | { 15 | gender: "female", 16 | name: { 17 | title: "Miss", 18 | first: "Carolyn", 19 | last: "Moore", 20 | }, 21 | email: "carolyn.moore@example.com", 22 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Carolyn", 23 | nat: "GB", 24 | }, 25 | { 26 | gender: "female", 27 | name: { 28 | title: "Ms", 29 | first: "Esma", 30 | last: "Berberoğlu", 31 | }, 32 | email: "esma.berberoglu@example.com", 33 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Esma", 34 | nat: "TR", 35 | }, 36 | { 37 | gender: "female", 38 | name: { 39 | title: "Ms", 40 | first: "Isabella", 41 | last: "Rhodes", 42 | }, 43 | email: "isabella.rhodes@example.com", 44 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella", 45 | nat: "GB", 46 | }, 47 | { 48 | gender: "male", 49 | name: { 50 | title: "Mr", 51 | first: "Derrick", 52 | last: "Carter", 53 | }, 54 | email: "derrick.carter@example.com", 55 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Derrick", 56 | nat: "IE", 57 | }, 58 | { 59 | gender: "female", 60 | name: { 61 | title: "Miss", 62 | first: "Mattie", 63 | last: "Lambert", 64 | }, 65 | email: "mattie.lambert@example.com", 66 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Mattie", 67 | nat: "AU", 68 | }, 69 | { 70 | gender: "male", 71 | name: { 72 | title: "Mr", 73 | first: "Mijat", 74 | last: "Rakić", 75 | }, 76 | email: "mijat.rakic@example.com", 77 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Mijat", 78 | nat: "RS", 79 | }, 80 | { 81 | gender: "male", 82 | name: { 83 | title: "Mr", 84 | first: "Javier", 85 | last: "Reid", 86 | }, 87 | email: "javier.reid@example.com", 88 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Javier", 89 | nat: "US", 90 | }, 91 | { 92 | gender: "female", 93 | name: { 94 | title: "Ms", 95 | first: "Isabella", 96 | last: "Li", 97 | }, 98 | email: "isabella.li@example.com", 99 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella", 100 | nat: "CA", 101 | }, 102 | { 103 | gender: "female", 104 | name: { 105 | title: "Mrs", 106 | first: "Stephanie", 107 | last: "Garrett", 108 | }, 109 | email: "stephanie.garrett@example.com", 110 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Stephanie", 111 | nat: "AU", 112 | }, 113 | { 114 | gender: "female", 115 | name: { 116 | title: "Ms", 117 | first: "Antonia", 118 | last: "Núñez", 119 | }, 120 | email: "antonia.nunez@example.com", 121 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Antonia", 122 | nat: "ES", 123 | }, 124 | { 125 | gender: "male", 126 | name: { 127 | title: "Mr", 128 | first: "Donald", 129 | last: "Young", 130 | }, 131 | email: "donald.young@example.com", 132 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Donald", 133 | nat: "US", 134 | }, 135 | { 136 | gender: "male", 137 | name: { 138 | title: "Mr", 139 | first: "Iegor", 140 | last: "Holodovskiy", 141 | }, 142 | email: "iegor.holodovskiy@example.com", 143 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Iegor", 144 | nat: "UA", 145 | }, 146 | { 147 | gender: "female", 148 | name: { 149 | title: "Madame", 150 | first: "Jessica", 151 | last: "David", 152 | }, 153 | email: "jessica.david@example.com", 154 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Jessica", 155 | nat: "CH", 156 | }, 157 | { 158 | gender: "female", 159 | name: { 160 | title: "Ms", 161 | first: "Eve", 162 | last: "Martinez", 163 | }, 164 | email: "eve.martinez@example.com", 165 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Eve", 166 | nat: "FR", 167 | }, 168 | { 169 | gender: "male", 170 | name: { 171 | title: "Mr", 172 | first: "Caleb", 173 | last: "Silva", 174 | }, 175 | email: "caleb.silva@example.com", 176 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Caleb", 177 | nat: "US", 178 | }, 179 | { 180 | gender: "female", 181 | name: { 182 | title: "Miss", 183 | first: "Marcia", 184 | last: "Jenkins", 185 | }, 186 | email: "marcia.jenkins@example.com", 187 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Marcia", 188 | nat: "US", 189 | }, 190 | { 191 | gender: "female", 192 | name: { 193 | title: "Mrs", 194 | first: "Mackenzie", 195 | last: "Jones", 196 | }, 197 | email: "mackenzie.jones@example.com", 198 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Mackenzie", 199 | nat: "NZ", 200 | }, 201 | { 202 | gender: "male", 203 | name: { 204 | title: "Mr", 205 | first: "Jeremiah", 206 | last: "Gutierrez", 207 | }, 208 | email: "jeremiah.gutierrez@example.com", 209 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Jeremiah", 210 | nat: "AU", 211 | }, 212 | { 213 | gender: "female", 214 | name: { 215 | title: "Ms", 216 | first: "Luciara", 217 | last: "Souza", 218 | }, 219 | email: "luciara.souza@example.com", 220 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Luciara", 221 | nat: "BR", 222 | }, 223 | { 224 | gender: "male", 225 | name: { 226 | title: "Mr", 227 | first: "Valgi", 228 | last: "da Cunha", 229 | }, 230 | email: "valgi.dacunha@example.com", 231 | picture: "https://api.dicebear.com/6.x/open-peeps/svg?seed=Valgi", 232 | nat: "BR", 233 | }, 234 | ], 235 | }; 236 | 237 | const useStyles = makeStyles({ 238 | avatar: { 239 | height: 32, 240 | width: 32, 241 | borderRadius: "50%", 242 | }, 243 | }); 244 | 245 | type User = { 246 | gender: string; // "male" 247 | name: { 248 | title: string; // "Mr", 249 | first: string; // "Duane", 250 | last: string; // "Reed" 251 | }; 252 | email: string; // "duane.reed@example.com" 253 | picture: string; // "https://api.dicebear.com/6.x/open-peeps/svg?seed=Duane" 254 | nat: string; // "AU" 255 | }; 256 | 257 | type DenseTableProps = { 258 | users: User[]; 259 | }; 260 | 261 | export const DenseTable = ({ users }: DenseTableProps) => { 262 | const classes = useStyles(); 263 | 264 | const columns: TableColumn[] = [ 265 | { title: "Avatar", field: "avatar" }, 266 | { title: "Name", field: "name" }, 267 | { title: "Email", field: "email" }, 268 | { title: "Nationality", field: "nationality" }, 269 | ]; 270 | 271 | const data = users.map((user) => { 272 | return { 273 | avatar: ( 274 | {user.name.first} 279 | ), 280 | name: `${user.name.first} ${user.name.last}`, 281 | email: user.email, 282 | nationality: user.nat, 283 | }; 284 | }); 285 | 286 | return ( 287 | 293 | ); 294 | }; 295 | 296 | export const ExampleFetchComponent = () => { 297 | const analyticsApi = useApi(analyticsApiRef); 298 | 299 | useEffect(() => { 300 | analyticsApi.captureEvent({ 301 | attributes: { component: "ExampleFetchComponent" }, 302 | subject: "test-subject", 303 | value: 1, 304 | action: "component-load", 305 | context: { 306 | extension: "my-custom-plugin", 307 | pluginId: "my-custom-plugin", 308 | routeRef: "myPluginRouteRef", 309 | }, 310 | }); 311 | }, [analyticsApi]); 312 | 313 | const { value, loading, error } = useAsync(async (): Promise => { 314 | // Would use fetch in a real world example 315 | return exampleUsers.results; 316 | }, []); 317 | 318 | if (loading) { 319 | return ; 320 | } else if (error) { 321 | return ; 322 | } 323 | 324 | return ; 325 | }; 326 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/components/ExampleFetchComponent/index.ts: -------------------------------------------------------------------------------- 1 | export { ExampleFetchComponent } from './ExampleFetchComponent'; 2 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | myPluginPlugin, 3 | MyPluginPage, 4 | MyPluginEntityComponentContent, 5 | MyPluginCard, 6 | } from "./plugin"; 7 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/plugin.test.ts: -------------------------------------------------------------------------------- 1 | import { myPluginPlugin } from './plugin'; 2 | 3 | describe('my-plugin', () => { 4 | it('should export plugin', () => { 5 | expect(myPluginPlugin).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/plugin.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createComponentExtension, 3 | createPlugin, 4 | createRoutableExtension, 5 | createRouteRef, 6 | } from "@backstage/core-plugin-api"; 7 | 8 | import { rootRouteRef } from "./routes"; 9 | 10 | export const myPluginPlugin = createPlugin({ 11 | id: "my-plugin", 12 | routes: { 13 | root: rootRouteRef, 14 | }, 15 | }); 16 | 17 | export const myPluginRouteRef = createRouteRef({ 18 | id: "my-catalog-plugin", 19 | }); 20 | 21 | export const MyPluginPage = myPluginPlugin.provide( 22 | createRoutableExtension({ 23 | name: "MyPluginPage", 24 | component: () => 25 | import("./components/ExampleComponent").then((m) => m.ExampleComponent), 26 | mountPoint: rootRouteRef, 27 | }) 28 | ); 29 | 30 | export const MyPluginCard = myPluginPlugin.provide( 31 | createComponentExtension({ 32 | name: "MyPluginContent", 33 | component: { 34 | lazy: () => 35 | import("./components/ExampleFetchComponent").then( 36 | (m) => m.ExampleFetchComponent 37 | ), 38 | }, 39 | }) 40 | ); 41 | 42 | export const MyPluginEntityComponentContent = myPluginPlugin.provide( 43 | createRoutableExtension({ 44 | name: "MyPluginContent", 45 | component: () => 46 | import("./components/EntityComponentExample").then( 47 | (m) => m.EntityContentComponent 48 | ), 49 | mountPoint: myPluginRouteRef, 50 | }) 51 | ); 52 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/routes.ts: -------------------------------------------------------------------------------- 1 | import { createRouteRef } from '@backstage/core-plugin-api'; 2 | 3 | export const rootRouteRef = createRouteRef({ 4 | id: 'my-plugin', 5 | }); 6 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | 3 | import { TextEncoder } from "util"; 4 | 5 | global.TextEncoder = TextEncoder; 6 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/skeleton/plugins/my-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@backstage/cli/config/tsconfig.json", 3 | "include": [ 4 | "src", 5 | "dev" 6 | ], 7 | "exclude": ["node_modules"], 8 | "compilerOptions": { 9 | "outDir": "dist-types", 10 | "rootDir": "." 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scaffolder-templates/roadie-plugin/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | kind: Template 3 | metadata: 4 | name: create-roadie-plugins-monorepo 5 | title: Create Roadie Plugins Monorepo 6 | description: Creates a Roadie plugins monorepo with example TypeScript code and example plugin with sample commands to develop, build and deploy Roadie plugins. 7 | 8 | spec: 9 | owner: info@roadie.io 10 | type: service 11 | parameters: 12 | - title: Provide some simple information 13 | required: 14 | - plugin_name 15 | properties: 16 | plugin_name: 17 | title: Plugin name 18 | type: string 19 | description: Unique name of the first plugin in the repository. 20 | ui:placeholder: docs-plugin 21 | 22 | - title: Create a GitHub repo to store your custom plugins in 23 | required: 24 | - repoUrl 25 | properties: 26 | repoUrl: 27 | title: Repository Location 28 | type: string 29 | ui:field: RepoUrlPicker 30 | ui:options: 31 | allowedHosts: 32 | - github.com 33 | steps: 34 | - id: template 35 | name: Fetch Skeleton + Template 36 | action: fetch:template 37 | input: 38 | url: ./skeleton 39 | values: 40 | repo_name: ${{ (parameters.repoUrl | parseRepoUrl)["repo"] }} 41 | repo_owner: ${{ (parameters.repoUrl | parseRepoUrl)["owner"] }} 42 | tenant: ${{ parameters.repository }} 43 | plugin_name: ${{ parameters.plugin_name }} 44 | 45 | - id: fs:rename 46 | name: Fill in names and descriptions 47 | action: fs:rename 48 | input: 49 | files: 50 | - from: ./plugins/my-plugin 51 | to: ./plugins/${{ parameters.plugin_name }} 52 | 53 | - id: publish 54 | name: Publish 55 | action: publish:github 56 | input: 57 | allowedHosts: ['github.com'] 58 | description: 'This is ${{ parameters.plugin_name }}' 59 | repoUrl: ${{ parameters.repoUrl }} 60 | defaultBranch: main 61 | 62 | 63 | output: 64 | links: 65 | - title: Repository 66 | icon: github 67 | url: ${{ steps['publish'].output.remoteUrl }} 68 | - title: Roadie CLI documentation 69 | icon: help 70 | url: https://www.npmjs.com/package/@roadiehq/roadie-cli 71 | --------------------------------------------------------------------------------