cli: add new role-based bundle command
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import { buildBundle } from '../../lib/bundler';
|
||||
import { parseParallel, PARALLEL_ENV_VAR } from '../../lib/parallel';
|
||||
import { loadCliConfig } from '../../lib/config';
|
||||
import { paths } from '../../lib/paths';
|
||||
|
||||
interface BundleAppOptions {
|
||||
writeStats: boolean;
|
||||
configPaths: string[];
|
||||
}
|
||||
|
||||
export async function bundleApp(options: BundleAppOptions) {
|
||||
const { name } = await fs.readJson(paths.resolveTarget('package.json'));
|
||||
await buildBundle({
|
||||
entry: 'src/index',
|
||||
parallel: parseParallel(process.env[PARALLEL_ENV_VAR]),
|
||||
statsJsonEnabled: options.writeStats,
|
||||
...(await loadCliConfig({
|
||||
args: options.configPaths,
|
||||
fromPackage: name,
|
||||
})),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import os from 'os';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import tar, { CreateOptions } from 'tar';
|
||||
import { createDistWorkspace } from '../../lib/packager';
|
||||
import { paths } from '../../lib/paths';
|
||||
import { parseParallel, PARALLEL_ENV_VAR } from '../../lib/parallel';
|
||||
import { buildPackage, Output } from '../../lib/builder';
|
||||
|
||||
const BUNDLE_FILE = 'bundle.tar.gz';
|
||||
const SKELETON_FILE = 'skeleton.tar.gz';
|
||||
|
||||
interface BundleBackendOptions {
|
||||
skipBuildDependencies: boolean;
|
||||
}
|
||||
|
||||
export async function bundleBackend(options: BundleBackendOptions) {
|
||||
const targetDir = paths.resolveTarget('dist');
|
||||
const pkg = await fs.readJson(paths.resolveTarget('package.json'));
|
||||
|
||||
// We build the target package without generating type declarations.
|
||||
await buildPackage({ outputs: new Set([Output.cjs]) });
|
||||
|
||||
const tmpDir = await fs.mkdtemp(resolvePath(os.tmpdir(), 'backstage-bundle'));
|
||||
try {
|
||||
await createDistWorkspace([pkg.name], {
|
||||
targetDir: tmpDir,
|
||||
buildDependencies: !options.skipBuildDependencies,
|
||||
buildExcludes: [pkg.name],
|
||||
parallel: parseParallel(process.env[PARALLEL_ENV_VAR]),
|
||||
skeleton: SKELETON_FILE,
|
||||
});
|
||||
|
||||
// We built the target backend package using the regular build process, but the result of
|
||||
// that has now been packed into the dist workspace, so clean up the dist dir.
|
||||
await fs.remove(targetDir);
|
||||
await fs.mkdir(targetDir);
|
||||
|
||||
// Move out skeleton.tar.gz before we create the main bundle, no point having that included up twice.
|
||||
await fs.move(
|
||||
resolvePath(tmpDir, SKELETON_FILE),
|
||||
resolvePath(targetDir, SKELETON_FILE),
|
||||
);
|
||||
|
||||
// Create main bundle.tar.gz, with some tweaks to make it more likely hit Docker build cache.
|
||||
await tar.create(
|
||||
{
|
||||
file: resolvePath(targetDir, BUNDLE_FILE),
|
||||
cwd: tmpDir,
|
||||
portable: true,
|
||||
noMtime: true,
|
||||
gzip: true,
|
||||
} as CreateOptions & { noMtime: boolean },
|
||||
[''],
|
||||
);
|
||||
} finally {
|
||||
await fs.remove(tmpDir);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import { Command } from 'commander';
|
||||
import { paths } from '../../lib/paths';
|
||||
import { readPackageRole } from '../../lib/role/packageRoles';
|
||||
import { bundleApp } from './bundleApp';
|
||||
import { bundleBackend } from './bundleBackend';
|
||||
|
||||
export async function command(cmd: Command): Promise<void> {
|
||||
const pkg = await fs.readJson(paths.resolveTarget('package.json'));
|
||||
const roleInfo = readPackageRole(pkg);
|
||||
if (!roleInfo) {
|
||||
throw new Error(`Target package must have 'backstage.role' set`);
|
||||
}
|
||||
|
||||
const options = {
|
||||
configPaths: cmd.config as string[],
|
||||
writeStats: Boolean(cmd.stats),
|
||||
skipBuildDependencies: Boolean(cmd.skipBuildDependencies),
|
||||
};
|
||||
|
||||
if (roleInfo.role === 'app') {
|
||||
return bundleApp(options);
|
||||
} else if (roleInfo.role === 'backend') {
|
||||
return bundleBackend(options);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Bundle command is not supported for package role '${roleInfo.role}'`,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export { command } from './command';
|
||||
@@ -133,6 +133,20 @@ export function registerCommands(program: CommanderStatic) {
|
||||
.option('--experimental-type-build', 'Enable experimental type build')
|
||||
.action(lazy(() => import('./build').then(m => m.default)));
|
||||
|
||||
program
|
||||
.command('bundle')
|
||||
.description('Bundle a package for deployment')
|
||||
.option(
|
||||
'--skip-build-dependencies',
|
||||
'Skip the automatic building of local dependencies',
|
||||
)
|
||||
.option(
|
||||
'--stats',
|
||||
'If bundle stats are available, write them to the output directory',
|
||||
)
|
||||
.option(...configOption)
|
||||
.action(lazy(() => import('./bundle').then(m => m.command)));
|
||||
|
||||
program
|
||||
.command('lint')
|
||||
.option(
|
||||
|
||||
Reference in New Issue
Block a user