Merge pull request #4509 from backstage/mob/techdocs-build-timestamp-metadata
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
After TechDocs generate step, insert build timestamp to techdocs_metadata.json
|
||||
@@ -13,22 +13,23 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import Stream, { PassThrough } from 'stream';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import Docker from 'dockerode';
|
||||
import fs from 'fs-extra';
|
||||
import mockFs from 'mock-fs';
|
||||
import * as winston from 'winston';
|
||||
import {
|
||||
runDockerContainer,
|
||||
getGeneratorKey,
|
||||
isValidRepoUrlForMkdocs,
|
||||
getRepoUrlFromLocationAnnotation,
|
||||
patchMkdocsYmlPreBuild,
|
||||
} from './helpers';
|
||||
import { RemoteProtocol } from '../prepare/types';
|
||||
import os from 'os';
|
||||
import path, { resolve as resolvePath } from 'path';
|
||||
import Stream, { PassThrough } from 'stream';
|
||||
import { ParsedLocationAnnotation } from '../../helpers';
|
||||
import { RemoteProtocol } from '../prepare/types';
|
||||
import {
|
||||
addBuildTimestampMetadata,
|
||||
getGeneratorKey,
|
||||
getRepoUrlFromLocationAnnotation,
|
||||
isValidRepoUrlForMkdocs,
|
||||
patchMkdocsYmlPreBuild,
|
||||
runDockerContainer,
|
||||
} from './helpers';
|
||||
|
||||
const mockEntity = {
|
||||
apiVersion: 'version',
|
||||
@@ -46,7 +47,8 @@ const mkdocsYml = fs.readFileSync(
|
||||
const mkdocsYmlWithRepoUrl = fs.readFileSync(
|
||||
resolvePath(__filename, '../__fixtures__/mkdocs_with_repo_url.yml'),
|
||||
);
|
||||
const mockLogger = winston.createLogger();
|
||||
const mockLogger = getVoidLogger();
|
||||
const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
|
||||
|
||||
describe('helpers', () => {
|
||||
describe('getGeneratorKey', () => {
|
||||
@@ -329,4 +331,47 @@ describe('helpers', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addBuildTimestampMetadata', () => {
|
||||
beforeEach(() => {
|
||||
mockFs.restore();
|
||||
mockFs({
|
||||
[rootDir]: {
|
||||
'invalid_techdocs_metadata.json': 'dsds',
|
||||
'techdocs_metadata.json': '{"site_name": "Tech Docs"}',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it('should create the file if it does not exist', async () => {
|
||||
const filePath = path.join(rootDir, 'wrong_techdocs_metadata.json');
|
||||
await addBuildTimestampMetadata(filePath, mockLogger);
|
||||
|
||||
// Check if the file exists
|
||||
await expect(
|
||||
fs.access(filePath, fs.constants.F_OK),
|
||||
).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
it('should throw error when the JSON is invalid', async () => {
|
||||
const filePath = path.join(rootDir, 'invalid_techdocs_metadata.json');
|
||||
|
||||
await expect(
|
||||
addBuildTimestampMetadata(filePath, mockLogger),
|
||||
).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('should add build timestamp to the metadata json', async () => {
|
||||
const filePath = path.join(rootDir, 'techdocs_metadata.json');
|
||||
|
||||
await addBuildTimestampMetadata(filePath, mockLogger);
|
||||
|
||||
const json = await fs.readJson(filePath);
|
||||
expect(json.build_timestamp).toBeLessThanOrEqual(Date.now());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import { spawn } from 'child_process';
|
||||
import { Writable, PassThrough } from 'stream';
|
||||
import Docker from 'dockerode';
|
||||
import yaml from 'js-yaml';
|
||||
import { Logger } from 'winston';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { SupportedGeneratorKey } from './types';
|
||||
import { spawn } from 'child_process';
|
||||
import Docker from 'dockerode';
|
||||
import fs from 'fs-extra';
|
||||
import yaml from 'js-yaml';
|
||||
import { PassThrough, Writable } from 'stream';
|
||||
import { Logger } from 'winston';
|
||||
import { ParsedLocationAnnotation } from '../../helpers';
|
||||
import { RemoteProtocol } from '../prepare/types';
|
||||
import { SupportedGeneratorKey } from './types';
|
||||
|
||||
// TODO: Implement proper support for more generators.
|
||||
export function getGeneratorKey(entity: Entity): SupportedGeneratorKey {
|
||||
@@ -275,3 +275,34 @@ export const patchMkdocsYmlPreBuild = async (
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the techdocs_metadata.json to add a new build timestamp metadata. Create the .json file if it doesn't exist.
|
||||
*
|
||||
* @param {string} techdocsMetadataPath File path to techdocs_metadata.json
|
||||
*/
|
||||
export const addBuildTimestampMetadata = async (
|
||||
techdocsMetadataPath: string,
|
||||
logger: Logger,
|
||||
): Promise<void> => {
|
||||
// check if file exists, create if it does not.
|
||||
try {
|
||||
await fs.access(techdocsMetadataPath, fs.constants.F_OK);
|
||||
} catch (err) {
|
||||
// Bootstrap file with empty JSON
|
||||
await fs.writeJson(techdocsMetadataPath, JSON.parse('{}'));
|
||||
}
|
||||
// check if valid Json
|
||||
let json;
|
||||
try {
|
||||
json = await fs.readJson(techdocsMetadataPath);
|
||||
} catch (err) {
|
||||
const message = `Invalid JSON at ${techdocsMetadataPath} with error ${err.message}`;
|
||||
logger.error(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
json.build_timestamp = Date.now();
|
||||
await fs.writeJson(techdocsMetadataPath, json);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { Logger } from 'winston';
|
||||
import { PassThrough } from 'stream';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
import { GeneratorBase, GeneratorRunOptions } from './types';
|
||||
import path from 'path';
|
||||
import { PassThrough } from 'stream';
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
runDockerContainer,
|
||||
runCommand,
|
||||
addBuildTimestampMetadata,
|
||||
patchMkdocsYmlPreBuild,
|
||||
runCommand,
|
||||
runDockerContainer,
|
||||
} from './helpers';
|
||||
import { GeneratorBase, GeneratorRunOptions } from './types';
|
||||
|
||||
type TechdocsGeneratorOptions = {
|
||||
// This option enables users to configure if they want to use TechDocs container
|
||||
@@ -118,5 +118,13 @@ export class TechdocsGenerator implements GeneratorBase {
|
||||
`Failed to generate docs from ${inputDir} into ${outputDir} with error ${error.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Post Generate steps
|
||||
|
||||
// Add build timestamp to techdocs_metadata.json
|
||||
addBuildTimestampMetadata(
|
||||
path.join(outputDir, 'techdocs_metadata.json'),
|
||||
this.logger,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user