Skip to content

Commit efc1592

Browse files
feat(marketplace): add new marketplace-cli init command (#499)
Signed-off-by: Christoph Jerolimov <jerolimov+git@redhat.com>
1 parent 10b3518 commit efc1592

6 files changed

Lines changed: 485 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/marketplace-cli': minor
3+
---
4+
5+
add new marketplace-cli init command

workspaces/marketplace/packages/cli/cli-report.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Options:
1111
-h, --help
1212
1313
Commands:
14+
init
1415
generate [options]
1516
verify
1617
help [command]
@@ -29,6 +30,15 @@ Options:
2930
-h, --help
3031
```
3132

33+
### `marketplace-cli init`
34+
35+
```
36+
Usage: marketplace-cli init [options]
37+
38+
Options:
39+
-h, --help
40+
```
41+
3242
### `marketplace-cli verify`
3343

3444
```

workspaces/marketplace/packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"commander": "^12.0.0",
3939
"fs-extra": "^11.2.0",
4040
"glob": "^9.3.5",
41+
"inquirer": "^12.4.3",
4142
"yaml": "^2.7.0"
4243
},
4344
"nodemonConfig": {

workspaces/marketplace/packages/cli/src/commands/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ function lazy(
3535
}
3636

3737
export const registerCommands = (program: Command) => {
38+
program
39+
.command('init')
40+
.description('init')
41+
.action(lazy(() => import('./init').then(m => m.default)));
42+
3843
program
3944
.command('generate')
4045
.description(
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* Copyright The Backstage Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import fs from 'fs';
18+
import inquirer, { DistinctQuestion } from 'inquirer';
19+
import glob from 'glob';
20+
import yaml from 'yaml';
21+
22+
import {
23+
EXTENSIONS_API_VERSION,
24+
MarketplaceKind,
25+
MarketplacePackage,
26+
MarketplacePlugin,
27+
} from '@red-hat-developer-hub/backstage-plugin-marketplace-common';
28+
29+
export default async function init() {
30+
const pluginFolders = await glob.glob('plugins/*/package.json/../');
31+
32+
const autoGeneratePackages = pluginFolders.length === 0;
33+
34+
// current working basename
35+
const cwd = process.cwd().split('/').pop() ?? '';
36+
// replace spaces with dashes and uppercase all first letters
37+
const defaultTitle = cwd
38+
.split('-')
39+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
40+
.join(' ');
41+
42+
const questions: DistinctQuestion[] = [
43+
{
44+
type: 'input',
45+
name: 'title',
46+
message: 'Plugin name (display name)',
47+
default: defaultTitle,
48+
},
49+
];
50+
51+
if (autoGeneratePackages) {
52+
questions.push({
53+
type: 'input',
54+
name: 'packageName',
55+
message: 'NPM package name incl. org (e.g. @my-org/my-plugin)',
56+
});
57+
questions.push({
58+
type: 'checkbox',
59+
name: 'packages',
60+
message: 'Packages',
61+
choices: [
62+
{ name: 'Frontend', value: 'frontend', checked: true },
63+
{ name: 'Backend', value: 'backend', checked: true },
64+
],
65+
});
66+
} else {
67+
questions.push({
68+
type: 'checkbox',
69+
name: 'packages',
70+
message: 'Packages',
71+
choices: pluginFolders.map(pluginFolder => ({
72+
name: pluginFolder,
73+
value: pluginFolder,
74+
checked: true,
75+
})),
76+
});
77+
}
78+
79+
const answers = await inquirer.prompt(questions);
80+
81+
console.log('answers', answers);
82+
83+
const { title, packageName, namespace, author } = answers;
84+
85+
let name = (packageName || (title as string)).toLowerCase().replace(/^@/, '');
86+
if (name.includes('/')) {
87+
name = name.substring(name.lastIndexOf('/') + 1);
88+
}
89+
90+
const plugin: MarketplacePlugin = {
91+
apiVersion: EXTENSIONS_API_VERSION,
92+
kind: MarketplaceKind.Plugin,
93+
metadata: {
94+
namespace,
95+
name,
96+
title,
97+
description: 'Plugin summary',
98+
},
99+
spec: {
100+
author,
101+
description: '# Plugin name\n\nFull plugin description...',
102+
},
103+
};
104+
console.log(yaml.stringify(plugin).trim());
105+
106+
if (autoGeneratePackages) {
107+
if (answers.packages.includes('frontend')) {
108+
const frontendPackage: MarketplacePackage = {
109+
apiVersion: EXTENSIONS_API_VERSION,
110+
kind: MarketplaceKind.Package,
111+
metadata: {
112+
namespace,
113+
name: packageName
114+
.toLowerCase()
115+
.replace(/^@/, '')
116+
.replaceAll(/[^a-z0-9]/g, '-'),
117+
title: packageName,
118+
},
119+
spec: {
120+
packageName,
121+
version: '0.1.0',
122+
partOf: [plugin.metadata.name],
123+
},
124+
};
125+
console.log('---');
126+
console.log(yaml.stringify(frontendPackage).trim());
127+
}
128+
129+
if (answers.packages.includes('backend')) {
130+
const backendPackage: MarketplacePackage = {
131+
apiVersion: EXTENSIONS_API_VERSION,
132+
kind: MarketplaceKind.Package,
133+
metadata: {
134+
namespace,
135+
name: `${packageName
136+
.toLowerCase()
137+
.replace(/^@/, '')
138+
.replaceAll(/[^a-z0-9]/g, '-')}-backend`,
139+
title: `${packageName}-backend`,
140+
},
141+
spec: {
142+
packageName: `${packageName}-backend`,
143+
version: '0.1.0',
144+
partOf: [plugin.metadata.name],
145+
},
146+
};
147+
console.log('---');
148+
console.log(yaml.stringify(backendPackage).trim());
149+
}
150+
} else {
151+
answers.packages.forEach((pluginFolder: string) => {
152+
const packageJsonPath = `${pluginFolder}/package.json`;
153+
const packageJson = JSON.parse(
154+
fs.readFileSync(packageJsonPath, { encoding: 'utf8' }),
155+
);
156+
157+
const pkg: MarketplacePackage = {
158+
apiVersion: EXTENSIONS_API_VERSION,
159+
kind: MarketplaceKind.Package,
160+
metadata: {
161+
namespace,
162+
name: packageJson.name
163+
.toLowerCase()
164+
.replace(/^@/, '')
165+
.replaceAll(/[^a-z0-9]/g, '-'),
166+
},
167+
spec: {
168+
packageName: packageJson.name,
169+
version: packageJson.version,
170+
partOf: [plugin.metadata.name],
171+
},
172+
};
173+
console.log('---');
174+
console.log(yaml.stringify(pkg).trim());
175+
});
176+
}
177+
}

0 commit comments

Comments
 (0)