본문 바로가기
WIKI 기술 지식 베이스

커스텀 액션 작성

원문 보기 위키 갱신

Scaffolder의 기능을 확장하고 싶다면, 내장 액션과 함께 사용할 수 있는 커스텀 액션을 작성해 확장할 수 있습니다.

출처: 문서

본문

Scaffolder의 기능을 확장하고 싶다면, 내장 액션과 함께 사용할 수 있는 커스텀 액션을 작성해 확장할 수 있습니다.

Backstage CLI로 커스텀 액션 생성 간소화

Backstage CLI 덕분에 Backstage에서 커스텀 액션 생성이 그 어느 때보다 쉬워졌습니다. 이 도구는 설정 과정을 간소화해, 여러분이 액션의 고유한 기능에 집중할 수 있게 해 줍니다.

먼저 yarn backstage-cli new 명령을 사용해 스캐폴더 모듈을 생성하세요. 이 명령은 필요한 보일러플레이트 코드를 설정해 부드러운 시작을 제공합니다.

$ yarn backstage-cli new? What do you want to create?  web-library - A library package, exporting shared functionality for web environments  node-library - A library package, exporting shared functionality for Node.js environments  catalog-provider-module - An Entity Provider module for the Software Catalog> scaffolder-backend-module - A module exporting custom actions for @backstage/plugin-scaffolder-backend  frontend-plugin - A new frontend plugin  backend-plugin - A new backend plugin  backend-plugin-module - A new backend module that extends an existing backend plugin(Move up and down to reveal more choices)

프롬프트가 나타나면 아래 화살표 키를 사용해 scaffolder-backend-module을 생성하는 옵션을 선택하세요. 이것은 커스텀 액션을 위한 견고한 기반을 만듭니다. 만들고 싶은 모듈의 이름을 입력하면 CLI가 필요한 파일과 디렉터리 구조를 생성합니다.

커스텀 액션 작성

명령을 실행한 후 CLI는 새 스캐폴더 모듈과 함께 새 디렉터리를 만듭니다. 이 디렉터리가 커스텀 액션을 만들기 위한 작업 디렉터리가 됩니다. 시작하는 데 필요한 모든 필수 파일과 보일러플레이트 코드를 담고 있습니다.

input으로 함수에 전달되는 몇 가지 내용과 새 파일을 추가하는 간단한 액션을 만들어 보겠습니다. 생성된 디렉터리 안에서 src/actions/example/example.ts에 있는 파일을 찾으세요. 이 파일과 생성된 단위 테스트는 자유롭게 이름을 바꾸세요. 기존 플레이스홀더 코드를 다음과 같이 커스텀 액션 코드로 대체할 것입니다.

Zod와 함께

import { resolveSafeChildPath } from '@backstage/backend-plugin-api';import { createTemplateAction } from '@backstage/plugin-scaffolder-node';import fs from 'fs-extra';import { type z } from 'zod/v3';export const createNewFileAction = () => {  return createTemplateAction({    id: 'acme:file:create',    description: 'Create an Acme file.',    schema: {      input: {        contents: z => z.string({ description: 'The contents of the file' }),        filename: z =>          z.string({            description: 'The filename of the file that will be created',          }),      },    },    async handler(ctx) {      await fs.outputFile(        resolveSafeChildPath(ctx.workspacePath, ctx.input.filename),        ctx.input.contents,      );    },  });};

그럼 이것을 분석해 보겠습니다. createNewFileAction은 createTemplateAction을 반환하는 함수이며, TemplateAction을 닫는(close over) 의존성을 전달하기 좋은 곳입니다. 참조를 위해 우리의 내장 액션을 살펴보세요.

createTemplateAction은 다음을 명시하는 객체를 받습니다.

  • id — 커스텀 액션을 위한 고유 ID. 우리가 scaffolder-backend 플러그인과 함께 제공할 수도 있는 미래의 내장 액션과 충돌하지 않도록 어떤 방식으로든 네임스페이스를 지정할 것을 권장합니다.
  • description — 액션의 목적을 설명하는 선택적 필드. 이것은 /create/actions 엔드포인트에 채워집니다.
  • schema.input — 함수에 입력되는 값에 대한 zod 스키마 객체.
  • schema.output — ctx.output을 사용해 함수에서 출력되는 값에 대한 zod 스키마 객체.
  • handler — 컨텍스트와 함께 액션의 일부로 실제 실행되는 코드.

명명 규칙

여러분 자신의 커스텀 액션과 오픈소스에 기여하는 어떤 액션 모두 이름을 일관되게 유지하세요. 우리는 :로 구분하고 이름의 마지막 부분에 동사를 사용하는 것이 잘 작동한다는 것을 발견했습니다. 우리는 내장 액션에 대해 provider:entity:verb 또는 가능한 한 그것에 가깝게 따릅니다. 예를 들어 github:actions:create 또는 github:repo:create와 같습니다.

원한다면 회사 이름으로 네임스페이스를 지정해도 됩니다. 예를 들어 위와 같이 acme:file:create처럼요.

가능하면 이 액션들에 snake_case나 kebab-case보다 camelCase를 선호하세요. 이것은 템플릿 엔티티 정의를 더 잘 읽고 쓰게 해 줍니다.

TemplateExample 추가

TemplateExample은 커스텀 액션을 사용할 수 있는 다양한 방법을 문서화하는 방법입니다. 추가되면 여러분의 Backstage 인스턴스의 /create/actions 경로 아래에서 볼 수 있습니다. 하나의 액션에 여러 예시를 가질 수 있으며, 입력의 다양한 조합과 그것을 사용하는 방법을 보여줄 수 있습니다.

TemplateExamples 정의

아래는 publish:github에 사용되는 TemplateExample 샘플입니다. 소스 코드는 GitHub에서 볼 수 있고, 데모.backstage.io/create/actions에서 미리보기를 볼 수 있습니다.

JSON Schema와 함께

import { TemplateExample } from '@backstage/plugin-scaffolder-node';import yaml from 'yaml';export const examples: TemplateExample[] = [  {    description: 'Initializes a GitHub repository with a description.',    example: yaml.stringify({      steps: [        {          id: 'publish',          action: 'publish:github',          name: 'Publish to GitHub',          input: {            repoUrl: 'github.com?repo=repo&owner=owner',            description: 'Initialize a git repository',          },        },      ],    }),  },  {    description:      'Initializes a GitHub repository with public repo visibility, if not set defaults to private',    example: yaml.stringify({      steps: [        {          id: 'publish',          action: 'publish:github',          name: 'Publish to GitHub',          input: {            repoUrl: 'github.com?repo=repo&owner=owner',            repoVisibility: 'public',          },        },      ],    }),  },];

커스텀 액션과 함께 TemplateExample 등록

createTemplateAction을 호출할 때 examples 속성을 포함해 TemplateExample을 등록하는 것도 중요합니다.

return createTemplateAction({  id: 'publish:github',  description:    'Initializes a git repository of contents in workspace and publishes it to GitHub.',  examples,  // ...rest of the action configuration});

TemplateAction 예시 테스트

예시 TemplateAction을 테스트하는 것도 가능합니다. GitHub에서 샘플 테스트를 볼 수 있습니다.

컨텍스트 객체

액션 handler가 호출될 때, 우리는 유일한 인자로 context를 제공합니다. 다음과 같습니다.

  • ctx.baseUrl — 템플릿이 위치한 문자열.
  • ctx.checkpoint — 이전 실행에서 이미 성공적으로 실행된 함수를 건너뛰어 멱등 액션을 구현할 수 있게 해 줍니다. 작업 복구와 함께 사용됩니다.
  • ctx.logger — 액션 안에서 추가 로깅을 위한 LoggerService 인스턴스.
  • ctx.workspacePath — 템플릿 실행의 작업 디렉터리의 문자열.
  • ctx.input — 액션 정의의 schema.input 부분에 제공된 zod 스키마와 일치해야 하는 객체.
  • ctx.output — schema.output의 zod 스키마와 일치하는 출력을 설정하기 위해 호출할 수 있는 함수. 예: ctx.output('downloadUrl', myDownloadUrl).
  • createTemporaryDirectory — 러너 어딘가에 임시 디렉터리를 제공하기 위해 호출하는 함수. workspacePath를 오염시키는 대신 일부 파일을 거기에 저장할 수 있습니다.
  • ctx.metadata — 템플릿 이름을 나타내는 name 필드를 포함하는 객체. 더 많은 메타데이터 필드가 나중에 추가될 수 있습니다.

커스텀 액션에서 핵심 서비스 사용

커스텀 액션이 config나 cache 같은 핵심 서비스를 요구한다면, 그것들을 의존성에 import해 커스텀 액션 함수에 전달할 수 있습니다.

module.ts

import {  coreServices,  createBackendModule,} from '@backstage/backend-plugin-api';...env.registerInit({  deps: {    scaffolder: scaffolderActionsExtensionPoint,    cache: coreServices.cache,    config: coreServices.rootConfig,  },  async init({scaffolder, cache, config}) {    scaffolder.addActions(      customActionNeedingCacheAndConfig({cache: cache, config: config}),    );  })

커스텀 액션에서 체크포인트 사용

멱등 액션은 체크포인트 사용을 통해 달성할 수 있습니다. 예를 들어:

plugins/my-company-scaffolder-actions-plugin/src/vendor/my-custom-action.ts

const res = await ctx.checkpoint?.({  key: 'create.projects',  fn: async () => {    const projectStgId = createStagingProjectId();    const projectProId = createProductionProjectId();    return {      projectStgId,      projectProId,    };  },});

스캐폴더 작업 범위에서 체크포인트의 고유 키를 정의해야 합니다. 작업 엔진은 실행 중에 그러한 키를 가진 체크포인트가 이미 실행되었는지 확인하며, 그렇고 실행이 성공했다면 콜백을 건너뛰고 대신 저장된 값을 반환합니다.

체크포인트의 반환 타입을 변경할 때마다 ID를 변경할 것을 권장합니다. 예를 들어 그에 대한 버전이나 다른 표시기를 포함할 수 있습니다(키 create.projects 대신 create.projects.v1처럼). 같은 키를 유지하고 영향을 받는 작업을 재시작하려 하면, 이 체크포인트에서 실패할 것입니다. 캐시된 결과가 기대하는 갱신된 반환 타입과 일치하지 않을 것입니다. 키를 바꾸면 체크포인트의 캐시를 무효화하게 됩니다.

기여된 커뮤니티 액션

커뮤니티가 기여하고 오픈소스인 액션의 목록은 다음으로 찾을 수 있습니다.

  • Backstage 플러그인 디렉터리로 가서 scaffolder로 필터링하기!
  • 커뮤니티 플러그인 저장소(Community Plugins Repo) 확인하기!

더 알아보기 (Learn more)