Skip to content

Commit

Permalink
feat(scaffolder): add new plugin for extending scaffolder actions (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
bbckr authored Sep 18, 2024
1 parent 7708f12 commit 9d30f86
Show file tree
Hide file tree
Showing 12 changed files with 679 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ This SeatGeek Backstage Plugins Collection offers the following plugins:
- [plugins/aws-catalog-backend](plugins/aws-catalog-backend)
- **Gitlab Catalog**: the Gitlab Catalog Plugin offers catalog integrations with the Gitlab API.
- [plugins/gitlab-catalog-backend](plugins/gitlab-catalog-backend/)
- **HCL Scaffolder Actions**: the HCL Scaffolder Actions plugin includes custom actions for working with HCL in your Backstage Software Templates.
- [plugins/scaffolder-backend-module-hcl](plugins/scaffolder-backend-module-hcl/)

Each of the plugins contain instructions for installation and development within
their respective locations.
Expand Down
5 changes: 5 additions & 0 deletions plugins/scaffolder-backend-module-hcl/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
* Copyright SeatGeek
* Licensed under the terms of the Apache-2.0 license. See LICENSE file in project root for terms.
*/
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
1 change: 1 addition & 0 deletions plugins/scaffolder-backend-module-hcl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
testdir/
30 changes: 30 additions & 0 deletions plugins/scaffolder-backend-module-hcl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# scaffolder-backend-module-hcl

This contains a collection of actions to use in scaffolder templates for working with HCL (Hashicorp Configuration Language). See https://github.com/hashicorp/hcl to learn more about HCL.

## Getting started

### From your Backstage root directory

```bash
# From your Backstage root directory
yarn add --cwd packages/backend @seatgeek/backstage-plugin-scaffolder-backend-module-hcl
```

Then ensure that both the scaffolder and this module are added to your backend:

```typescript
// In packages/backend/src/index.ts
const backend = createBackend();
// ...
backend.add(import('@seatgeek/backstage-plugin-scaffolder-backend-module-hcl'));
```

After that you can use the actions in your template.

## Actions

- `hcl:merge` Merge HCL strings
- `hcl:merge:write` Merge HCL strings and write to a file
- `hcl:merge:files` Merge HCL files
- `hcl:merge:files:write` Merge HCL files and write to a file
48 changes: 48 additions & 0 deletions plugins/scaffolder-backend-module-hcl/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@seatgeek/backstage-plugin-scaffolder-backend-module-hcl",
"version": "0.0.0-semantically-released",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module",
"pluginId": "scaffolder",
"pluginPackages": [
"@seatgeek/backstage-plugin-scaffolder-backend-module-hcl"
],
"pluginPackage": "@backstage/plugin-scaffolder-backend"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test --no-cache",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-common": "^0.24.1",
"@backstage/backend-plugin-api": "^0.8.1",
"@backstage/config": "^1.2.0",
"@backstage/plugin-scaffolder-node": "^0.4.10",
"@seatgeek/node-hcl": "^1.0.0",
"fs-extra": "^11.2.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@backstage/cli": "^0.27.0",
"@testing-library/jest-dom": "^5.10.1",
"@types/fs-extra": "^11.0.4",
"msw": "^1.0.0",
"stream": "^0.0.3"
},
"files": [
"dist"
]
}
119 changes: 119 additions & 0 deletions plugins/scaffolder-backend-module-hcl/src/actions/hcl/hcl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright SeatGeek
* Licensed under the terms of the Apache-2.0 license. See LICENSE file in project root for terms.
*/
import { getVoidLogger } from '@backstage/backend-common';
import { randomBytes } from 'crypto';
import { writeFileSync } from 'fs-extra';
import { tmpdir } from 'os';
import { PassThrough } from 'stream';
import { createHclMergeAction, createHclMergeFilesAction } from './hcl';

// Since we have to
const TMP_DIR = tmpdir();

describe('createHclMergeAction', () => {
const mockContext = {
logger: getVoidLogger(),
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory: jest.fn(),
checkpoint: jest.fn(),
getInitiatorCredentials: jest.fn(),
workspacePath: '.',
};

it('should merge HCL files', async () => {
const a = `
variable "name" {
description = "Name to be used on all the resources as identifier"
type = string
default = ""
}`;

const b = `
variable "name" {
type = string
default = "my-name"
}`;

const expected = `variable "name" {
default = "my-name"
description = "Name to be used on all the resources as identifier"
type = string
}
`;

const mockCtx = {
...mockContext,
input: {
aSourceContent: a,
bSourceContent: b,
},
};

await createHclMergeAction().handler(mockCtx);

expect(mockCtx.output.mock.calls[0][0]).toEqual('hcl');
expect(mockCtx.output.mock.calls[0][1]).toEqual(expected);
});
});

describe('createHclMergeFilesAction', () => {
const mockContext = {
logger: getVoidLogger(),
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory: jest.fn(),
checkpoint: jest.fn(),
getInitiatorCredentials: jest.fn(),
workspacePath: TMP_DIR,
};

it('should merge HCL files', async () => {
const a = `
variable "name" {
description = "Name to be used on all the resources as identifier"
type = string
default = ""
}`;

const b = `
variable "name" {
type = string
default = "my-name"
}`;

const expected = `variable "name" {
default = "my-name"
description = "Name to be used on all the resources as identifier"
type = string
}
`;

const aPath = `${mockContext.workspacePath}/${randomBytes(12).toString(
'hex',
)}.hcl`;
await writeFileSync(aPath, a, 'utf8');

const bPath = `${mockContext.workspacePath}/${randomBytes(12).toString(
'hex',
)}.hcl`;
await writeFileSync(bPath, b, 'utf8');

const mockCtx = {
...mockContext,
input: {
aSourcePath: aPath,
bSourcePath: bPath,
},
};

await createHclMergeFilesAction().handler(mockCtx);

expect(mockCtx.output.mock.calls[0][0]).toEqual('hcl');
expect(mockCtx.output.mock.calls[0][1]).toEqual(expected);
});
});
Loading

0 comments on commit 9d30f86

Please sign in to comment.