diff --git a/.changeset/add-cli-module-template-support.md b/.changeset/add-cli-module-template-support.md new file mode 100644 index 0000000000..be965d882d --- /dev/null +++ b/.changeset/add-cli-module-template-support.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-module-new': patch +--- + +Added support for the `cli-module` template role for scaffolding new CLI module packages. diff --git a/.changeset/add-cli-module-template.md b/.changeset/add-cli-module-template.md new file mode 100644 index 0000000000..f6b169906f --- /dev/null +++ b/.changeset/add-cli-module-template.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added a new `cli-module` template for creating CLI module packages. diff --git a/packages/cli-module-new/src/lib/defaultTemplates.ts b/packages/cli-module-new/src/lib/defaultTemplates.ts index 9d1543c452..dea35a6e99 100644 --- a/packages/cli-module-new/src/lib/defaultTemplates.ts +++ b/packages/cli-module-new/src/lib/defaultTemplates.ts @@ -23,6 +23,7 @@ export const defaultTemplates = [ '@backstage/cli/templates/plugin-common-library', '@backstage/cli/templates/web-library', '@backstage/cli/templates/node-library', + '@backstage/cli/templates/cli-module', '@backstage/cli/templates/catalog-provider-module', '@backstage/cli/templates/scaffolder-backend-module', ]; diff --git a/packages/cli-module-new/src/lib/preparation/collectPortableTemplateInput.ts b/packages/cli-module-new/src/lib/preparation/collectPortableTemplateInput.ts index 7279801d62..63e3791a49 100644 --- a/packages/cli-module-new/src/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli-module-new/src/lib/preparation/collectPortableTemplateInput.ts @@ -160,6 +160,7 @@ export function getPromptsForRole( case 'web-library': case 'node-library': case 'common-library': + case 'cli-module': return [namePrompt()]; case 'plugin-web-library': case 'plugin-node-library': diff --git a/packages/cli-module-new/src/lib/preparation/resolvePackageParams.test.ts b/packages/cli-module-new/src/lib/preparation/resolvePackageParams.test.ts index df128d4755..f279b702b1 100644 --- a/packages/cli-module-new/src/lib/preparation/resolvePackageParams.test.ts +++ b/packages/cli-module-new/src/lib/preparation/resolvePackageParams.test.ts @@ -37,6 +37,13 @@ describe.each([ packagePath: 'packages/test', }, ], + [ + { role: 'cli-module', name: 'test' }, + { + packageName: '@internal/cli-module-test', + packagePath: 'packages/cli-module-test', + }, + ], [ { role: 'plugin-web-library', pluginId: 'test' }, { diff --git a/packages/cli-module-new/src/lib/preparation/resolvePackageParams.ts b/packages/cli-module-new/src/lib/preparation/resolvePackageParams.ts index dd85f49fad..8a4f87c5c6 100644 --- a/packages/cli-module-new/src/lib/preparation/resolvePackageParams.ts +++ b/packages/cli-module-new/src/lib/preparation/resolvePackageParams.ts @@ -48,6 +48,8 @@ function getBaseNameForRole( case 'node-library': case 'common-library': return roleParams.name; + case 'cli-module': + return `cli-module-${roleParams.name}`; case 'plugin-web-library': return `${roleParams.pluginId}-react`; case 'plugin-node-library': diff --git a/packages/cli-module-new/src/lib/types.ts b/packages/cli-module-new/src/lib/types.ts index 9f221ea7aa..83a195a43a 100644 --- a/packages/cli-module-new/src/lib/types.ts +++ b/packages/cli-module-new/src/lib/types.ts @@ -50,6 +50,7 @@ export const TEMPLATE_ROLES = [ 'web-library', 'node-library', 'common-library', + 'cli-module', 'plugin-web-library', 'plugin-node-library', 'plugin-common-library', @@ -80,7 +81,7 @@ export type PortableTemplateParams = { export type PortableTemplateInputRoleParams = | { - role: 'web-library' | 'node-library' | 'common-library'; + role: 'web-library' | 'node-library' | 'common-library' | 'cli-module'; name: string; } | { diff --git a/packages/cli/templates/cli-module/.eslintrc.js.hbs b/packages/cli/templates/cli-module/.eslintrc.js.hbs new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/packages/cli/templates/cli-module/.eslintrc.js.hbs @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/packages/cli/templates/cli-module/README.md.hbs b/packages/cli/templates/cli-module/README.md.hbs new file mode 100644 index 0000000000..657b45805b --- /dev/null +++ b/packages/cli/templates/cli-module/README.md.hbs @@ -0,0 +1,5 @@ +# {{packageName}} + +A CLI module that adds commands to the Backstage CLI. + +_This package was created through the Backstage CLI_ diff --git a/packages/cli/templates/cli-module/bin/{{binName}} b/packages/cli/templates/cli-module/bin/{{binName}} new file mode 100644 index 0000000000..59f8267233 --- /dev/null +++ b/packages/cli/templates/cli-module/bin/{{binName}} @@ -0,0 +1,32 @@ +#!/usr/bin/env node +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const path = require('node:path'); + +/* eslint-disable-next-line no-restricted-syntax */ +const isLocal = require('node:fs').existsSync( + path.resolve(__dirname, '../src'), +); + +if (isLocal) { + require('@backstage/cli-node/config/nodeTransform.cjs'); +} + +const { runCliModule } = require('@backstage/cli-node'); +const cliModule = require(isLocal ? '../src/index' : '..').default; +const pkg = require('../package.json'); +runCliModule({ module: cliModule, name: pkg.name, version: pkg.version }); diff --git a/packages/cli/templates/cli-module/package.json.hbs b/packages/cli/templates/cli-module/package.json.hbs new file mode 100644 index 0000000000..5e077cca83 --- /dev/null +++ b/packages/cli/templates/cli-module/package.json.hbs @@ -0,0 +1,35 @@ +{ + "name": "{{packageName}}", + "description": "CLI module for Backstage CLI", + "main": "src/index.ts", + "types": "src/index.ts", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "cli-module" + }, + "scripts": { + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/cli-common": "{{versionQuery '@backstage/cli-common'}}", + "@backstage/cli-node": "{{versionQuery '@backstage/cli-node'}}", + "cleye": "^2.3.0" + }, + "devDependencies": { + "@backstage/cli": "{{versionQuery '@backstage/cli'}}" + }, + "files": [ + "dist", + "bin" + ], + "bin": "bin/{{binName}}" +} diff --git a/packages/cli/templates/cli-module/portable-template.yaml b/packages/cli/templates/cli-module/portable-template.yaml new file mode 100644 index 0000000000..72b6c2786b --- /dev/null +++ b/packages/cli/templates/cli-module/portable-template.yaml @@ -0,0 +1,5 @@ +name: cli-module +role: cli-module +description: A CLI module that adds commands to the Backstage CLI +values: + binName: 'backstage-cli-module-{{ name }}' diff --git a/packages/cli/templates/cli-module/src/commands/example.ts b/packages/cli/templates/cli-module/src/commands/example.ts new file mode 100644 index 0000000000..66722307b0 --- /dev/null +++ b/packages/cli/templates/cli-module/src/commands/example.ts @@ -0,0 +1,22 @@ +import { cli } from 'cleye'; +import type { CliCommandContext } from '@backstage/cli-node'; + +export default async ({ args, info }: CliCommandContext) => { + const { flags } = cli( + { + help: info, + booleanFlagNegation: true, + flags: { + name: { + type: String, + description: 'Your name', + }, + }, + }, + undefined, + args, + ); + + const name = flags.name ?? 'World'; + console.log(`Hello, ${name}!`); +}; diff --git a/packages/cli/templates/cli-module/src/index.ts.hbs b/packages/cli/templates/cli-module/src/index.ts.hbs new file mode 100644 index 0000000000..a947d3d666 --- /dev/null +++ b/packages/cli/templates/cli-module/src/index.ts.hbs @@ -0,0 +1,20 @@ +/***/ +/** + * CLI module for the Backstage CLI. + * + * @packageDocumentation + */ + +import { createCliModule } from '@backstage/cli-node'; +import packageJson from '../package.json'; + +export default createCliModule({ + packageJson, + init: async reg => { + reg.addCommand({ + path: ['example'], + description: 'An example command', + execute: { loader: () => import('./commands/example') }, + }); + }, +});