Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): compare config bundles using --target config.json #3016

Merged
merged 7 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/cli/src/cli/config/action.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ export class CommandBundle extends CommandLineAction {
const config = this.config.value ?? DefaultConfig;
const bundle = this.output.value ?? DefaultOutput;
const mem = await ConfigJson.fromPath(config, logger);
if (this.assets.value) mem.assets = this.assets.value;
blacha marked this conversation as resolved.
Show resolved Hide resolved
const configJson = mem.toJson();
const assets = this.assets.value;
if (assets) configJson.assets = assets;
await fsa.writeJson(bundle, configJson);
logger.info({ path: bundle }, 'ConfigBundled');
return;
Expand Down
17 changes: 16 additions & 1 deletion packages/cli/src/cli/config/action.import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class CommandImport extends CommandLineAction {
private backup!: CommandLineStringParameter;
private output!: CommandLineStringParameter;
private commit!: CommandLineFlagParameter;
private target!: CommandLineStringParameter;

promises: Promise<boolean>[] = [];
/** List of paths to invalidate at the end of the request */
Expand Down Expand Up @@ -65,6 +66,11 @@ export class CommandImport extends CommandLineAction {
parameterLongName: '--output',
description: 'Output a markdown file with the config changes',
});
this.target = this.defineStringParameter({
argumentName: 'TARGET',
parameterLongName: '--target',
description: 'import location',
blacha marked this conversation as resolved.
Show resolved Hide resolved
});
this.commit = this.defineFlagParameter({
parameterLongName: '--commit',
description: 'Actually start the import',
Expand All @@ -77,12 +83,21 @@ export class CommandImport extends CommandLineAction {
const commit = this.commit.value ?? false;
const config = this.config.value;
const backup = this.backup.value;
const cfg = getDefaultConfig();
let cfg = getDefaultConfig();
if (config == null) throw new Error('Please provide a config json');
if (commit && !config.startsWith('s3://') && Env.isProduction()) {
throw new Error('To actually import into dynamo has to use the config file from s3.');
}

// Load a configuration from a file, and use that as the comparision target
if (this.target.value) {
logger.info({ config: this.target.value }, 'Import:Target:Load');
const configJson = await fsa.readJson<ConfigBundled>(this.target.value);
const mem = ConfigProviderMemory.fromJson(configJson);
mem.createVirtualTileSets();
cfg = mem;
}

const HostPrefix = Env.isProduction() ? '' : 'dev.';
const healthEndpoint = `https://${HostPrefix}basemaps.linz.govt.nz/v1/health`;

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/cli/config/config.diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { LogType } from '@basemaps/shared';
import c from 'ansi-colors';
import diff from 'deep-diff';

export const IgnoredProperties = ['id', 'createdAt', 'updatedAt', 'year', 'resolution'];
export const IgnoredProperties = new Set(['id', 'createdAt', 'updatedAt', 'year', 'resolution']);

export class ConfigDiff {
static getDiff<T>(changes: diff.Diff<T, T>[]): string {
Expand Down Expand Up @@ -32,7 +32,7 @@ export class ConfigDiff {
}

static showDiff<T extends { id: string }>(type: string, oldData: T, newData: T, logger: LogType): boolean {
const changes = diff.diff(oldData, newData, (_path: string[], key: string) => IgnoredProperties.indexOf(key) >= 0);
const changes = diff.diff(oldData, newData, (_path: string[], key: string) => IgnoredProperties.has(key));
Wentao-Kuang marked this conversation as resolved.
Show resolved Hide resolved
if (changes) {
const changeDif = ConfigDiff.getDiff(changes);
logger.info({ type, record: newData.id }, 'Changes');
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/cli/config/config.update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class Updater<S extends BaseConfig = BaseConfig> {
const newData = this.getConfig();
const db = this.getDB();
const oldData = await this.getOldData();

if (oldData == null || ConfigDiff.showDiff(db.prefix, oldData, newData, this.logger)) {
const operation = oldData == null ? 'Insert' : 'Update';
this.logger.info({ type: db.prefix, record: newData.id, commit: this.isCommit }, `Change:${operation}`);
Expand Down
10 changes: 9 additions & 1 deletion packages/config/src/json/json.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { ConfigPrefix } from '../config/prefix.js';
import { ConfigProvider } from '../config/provider.js';
import { ConfigLayer, ConfigTileSet, TileSetType } from '../config/tile.set.js';
import { ConfigVectorStyle, StyleJson } from '../config/vector.style.js';
import { ConfigProviderMemory } from '../memory/memory.config.js';
import { ConfigBundled, ConfigProviderMemory } from '../memory/memory.config.js';
import { LogType } from './log.js';
import { zProviderConfig } from './parse.provider.js';
import { zStyleJson } from './parse.style.js';
Expand Down Expand Up @@ -93,6 +93,14 @@ export class ConfigJson {

/** Import configuration from a base path */
static async fromPath(basePath: string, log: LogType): Promise<ConfigProviderMemory> {
if (basePath.endsWith('.json') || basePath.endsWith('.json.gz')) {
const config = await fsa.readJson<BaseConfig>(basePath);
if (config.id && config.id.startsWith('cb_')) {
// We have been given a config bundle just load that instead!
return ConfigProviderMemory.fromJson(config as unknown as ConfigBundled);
}
}

const cfg = new ConfigJson(basePath, log);

const files = await fsa.toArray(fsa.list(basePath));
Expand Down
16 changes: 12 additions & 4 deletions packages/config/src/memory/memory.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ function removeUndefined(obj: unknown): void {
export class ConfigProviderMemory extends BasemapsConfigProvider {
override type = 'memory' as const;

/** Optional id of the configuration */
id?: string;

Imagery = new MemoryConfigObject<ConfigImagery>(this, ConfigPrefix.Imagery);
Style = new MemoryConfigObject<ConfigVectorStyle>(this, ConfigPrefix.Style);
TileSet = new MemoryConfigObject<ConfigTileSet>(this, ConfigPrefix.TileSet);
Expand Down Expand Up @@ -118,7 +121,8 @@ export class ConfigProviderMemory extends BasemapsConfigProvider {
}

cfg.hash = sha256base58(JSON.stringify(cfg));
cfg.id = ConfigId.prefix(ConfigPrefix.ConfigBundle, ulid());
this.id = this.id ?? ConfigId.prefix(ConfigPrefix.ConfigBundle, ulid());
cfg.id = this.id;

return cfg;
}
Expand All @@ -140,7 +144,8 @@ export class ConfigProviderMemory extends BasemapsConfigProvider {
const layerByName = new Map<string, ConfigLayer>();
// Set all layers as minZoom:32
for (const l of layers) {
const newLayer = { ...l, maxZoom: undefined, minZoom: 32 };
const newLayer = { ...l, minZoom: 32 };
delete newLayer.maxZoom; // max zoom not needed when minzoom is 32
layerByName.set(newLayer.name, { ...layerByName.get(l.name), ...newLayer });
}
const allTileset: ConfigTileSet = {
Expand Down Expand Up @@ -209,17 +214,20 @@ export class ConfigProviderMemory extends BasemapsConfigProvider {
if (cfg.id == null || ConfigId.getPrefix(cfg.id) !== ConfigPrefix.ConfigBundle) {
throw new Error('Provided configuration file is not a basemaps config bundle.');
}
// Load the time the bundle was created from the ULID
const updatedAt = decodeTime(ConfigId.unprefix(ConfigPrefix.ConfigBundle, cfg.id));
// TODO this should validate the config
const mem = new ConfigProviderMemory();

for (const ts of cfg.tileSet) mem.put(ts);
for (const st of cfg.style) mem.put(st);
for (const pv of cfg.provider) mem.put(pv);
for (const img of cfg.imagery) mem.put(img);

// Load the time the bundle was created from the ULID
const updatedAt = decodeTime(ConfigId.unprefix(ConfigPrefix.ConfigBundle, cfg.id));
for (const obj of mem.objects.values()) obj.updatedAt = updatedAt;

mem.assets = cfg.assets;
mem.id = cfg.id;

return mem;
}
Expand Down
Loading