techdocs: Add build timestamp to techdocs_metadata.json

Co-authored-by: Raghunandan Balachandran <soapraj@gmail.com>
This commit is contained in:
Himanshu Mishra
2021-02-12 10:56:57 +01:00
parent 3fe4e34749
commit ec7ba00581
3 changed files with 112 additions and 28 deletions
@@ -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 tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp';
describe('helpers', () => {
describe('getGeneratorKey', () => {
@@ -329,4 +331,47 @@ describe('helpers', () => {
);
});
});
describe('addBuildTimestampMetadata', () => {
beforeEach(() => {
mockFs({
[tmpDir]: {
'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(tmpDir, '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(tmpDir, 'invalid_techdocs_metadata.json');
// Check if the file exists
await expect(
addBuildTimestampMetadata(filePath, mockLogger),
).rejects.toThrowError();
});
it('should add build timestamp to the metadata json', async () => {
const filePath = path.join(tmpDir, '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,
);
}
}