Techdocs without docker-in-docker (#2438)
We're deploying backstage to GKE and have had issues getting techdocs volume mount logic to work because of mixing paths between the host and the container running the backend. So we added a condition where if mkdocs is found in the backend container it will use that to generate the docs rather than spinning it up in a docker container.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
"@backstage/config": "^0.1.1-alpha.21",
|
||||
"@types/dockerode": "^2.5.34",
|
||||
"@types/express": "^4.17.6",
|
||||
"command-exists-promise": "^2.0.2",
|
||||
"default-branch": "^1.0.8",
|
||||
"dockerode": "^3.2.1",
|
||||
"express": "^4.17.1",
|
||||
|
||||
@@ -18,6 +18,7 @@ import { Entity } from '@backstage/catalog-model';
|
||||
import { Writable, PassThrough } from 'stream';
|
||||
import Docker from 'dockerode';
|
||||
import { SupportedGeneratorKey } from './types';
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
// TODO: Implement proper support for more generators.
|
||||
export function getGeneratorKey(entity: Entity): SupportedGeneratorKey {
|
||||
@@ -38,6 +39,13 @@ type RunDockerContainerOptions = {
|
||||
createOptions?: Docker.ContainerCreateOptions;
|
||||
};
|
||||
|
||||
export type RunCommandOptions = {
|
||||
command: string;
|
||||
args: string[];
|
||||
options: object;
|
||||
logStream?: Writable;
|
||||
};
|
||||
|
||||
export async function runDockerContainer({
|
||||
imageName,
|
||||
args,
|
||||
@@ -96,3 +104,41 @@ export async function runDockerContainer({
|
||||
|
||||
return { error, statusCode };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param options the options object
|
||||
* @param options.command the command to run
|
||||
* @param options.args the arguments to pass the command
|
||||
* @param options.options options used in spawn
|
||||
* @param options.logStream the log streamer to capture log messages
|
||||
*/
|
||||
export const runCommand = async ({
|
||||
command,
|
||||
args,
|
||||
options,
|
||||
logStream = new PassThrough(),
|
||||
}: RunCommandOptions) => {
|
||||
await new Promise((resolve, reject) => {
|
||||
const process = spawn(command, args, options);
|
||||
|
||||
process.stdout.on('data', stream => {
|
||||
logStream.write(stream);
|
||||
});
|
||||
|
||||
process.stderr.on('data', stream => {
|
||||
logStream.write(stream);
|
||||
});
|
||||
|
||||
process.on('error', error => {
|
||||
return reject(error);
|
||||
});
|
||||
|
||||
process.on('close', code => {
|
||||
if (code !== 0) {
|
||||
return reject(`Command ${command} failed, exit code: ${code}`);
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -24,7 +24,9 @@ import {
|
||||
GeneratorRunOptions,
|
||||
GeneratorRunResult,
|
||||
} from './types';
|
||||
import { runDockerContainer } from './helpers';
|
||||
import { runDockerContainer, runCommand } from './helpers';
|
||||
|
||||
const commandExists = require('command-exists-promise');
|
||||
|
||||
export class TechdocsGenerator implements GeneratorBase {
|
||||
private readonly logger: Logger;
|
||||
@@ -46,17 +48,29 @@ export class TechdocsGenerator implements GeneratorBase {
|
||||
);
|
||||
|
||||
try {
|
||||
await runDockerContainer({
|
||||
imageName: 'spotify/techdocs',
|
||||
args: ['build', '-d', '/result'],
|
||||
logStream,
|
||||
docsDir: directory,
|
||||
resultDir,
|
||||
dockerClient,
|
||||
});
|
||||
this.logger.info(
|
||||
`[TechDocs]: Successfully generated docs from ${directory} into ${resultDir}`,
|
||||
);
|
||||
const mkdocsInstalled = await commandExists('mkdocs');
|
||||
if (mkdocsInstalled) {
|
||||
await runCommand({
|
||||
command: 'mkdocs',
|
||||
args: ['build', '-d', resultDir, '-v'],
|
||||
options: {
|
||||
cwd: directory,
|
||||
},
|
||||
logStream,
|
||||
});
|
||||
} else {
|
||||
await runDockerContainer({
|
||||
imageName: 'spotify/techdocs',
|
||||
args: ['build', '-d', '/result'],
|
||||
logStream,
|
||||
docsDir: directory,
|
||||
resultDir,
|
||||
dockerClient,
|
||||
});
|
||||
this.logger.info(
|
||||
`[TechDocs]: Successfully generated docs from ${directory} into ${resultDir}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.debug(
|
||||
`[TechDocs]: Failed to generate docs from ${directory} into ${resultDir}`,
|
||||
|
||||
Reference in New Issue
Block a user