Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/dev/typescript/build_ts_refs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Path from 'path';
import execa from 'execa';
import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';

export const REF_CONFIG_PATHS = [Path.resolve(REPO_ROOT, 'tsconfig.refs.json')];
import { REF_CONFIG_PATHS } from './root_refs_config';

export async function buildAllTsRefs(log: ToolingLog): Promise<{ failed: boolean }> {
for (const path of REF_CONFIG_PATHS) {
Expand Down
15 changes: 12 additions & 3 deletions src/dev/typescript/build_ts_refs_cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { run, REPO_ROOT } from '@kbn/dev-utils';
import del from 'del';

import { RefOutputCache } from './ref_output_cache';
import { buildAllTsRefs, REF_CONFIG_PATHS } from './build_ts_refs';
import { buildAllTsRefs } from './build_ts_refs';
import { updateRootRefsConfig, validateRootRefsConfig, REF_CONFIG_PATHS } from './root_refs_config';
import { getOutputsDeep } from './ts_configfile';
import { concurrentMap } from './concurrent_map';

Expand All @@ -36,6 +37,12 @@ export async function runBuildRefsCli() {
return;
}

if (!!flags['validate-root-refs-config']) {
await validateRootRefsConfig(log);
} else {
await updateRootRefsConfig(log);
}

const outDirs = getOutputsDeep(REF_CONFIG_PATHS);

const cacheEnabled = process.env.BUILD_TS_REFS_CACHE_ENABLE !== 'false' && !!flags.cache;
Expand Down Expand Up @@ -89,15 +96,17 @@ export async function runBuildRefsCli() {
{
description: 'Build TypeScript projects',
flags: {
boolean: ['clean', 'force', 'cache', 'ignore-type-failures'],
boolean: ['clean', 'force', 'cache', 'ignore-type-failures', 'validate-root-refs-config'],
default: {
cache: true,
},
help: `
--force Run the build even if the BUILD_TS_REFS_DISABLE is set to "true"
--clean Delete outDirs for each ts project before building
--no-cache Disable fetching/extracting outDir caches based on the mergeBase with upstream
--ignore-type-failures If tsc reports type errors, ignore them and just log a small warning.
--ignore-type-failures If tsc reports type errors, ignore them and just log a small warning
--validate-root-refs-config Ensure that all necessary files are listed in the root tsconfig.refs.json
file, and if not fail with an error message about how to update it
`,
},
log: {
Expand Down
8 changes: 8 additions & 0 deletions src/dev/typescript/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,12 @@ export class Project {
public isAbsolutePathSelected(path: string) {
return testMatchers(this.exclude, path) ? false : testMatchers(this.include, path);
}

public isCompositeProject() {
return !!this.config.compilerOptions?.composite;
}

public getRefdPaths() {
return this.config.references?.map((r: { path: string }) => r.path) ?? [];
}
}
114 changes: 114 additions & 0 deletions src/dev/typescript/root_refs_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import Path from 'path';
import Fs from 'fs/promises';

import { REPO_ROOT, ToolingLog, createFailError } from '@kbn/dev-utils';
import dedent from 'dedent';

import { PROJECTS } from './projects';
import { Project } from './project';

export const ROOT_REFS_CONFIG_PATH = Path.resolve(REPO_ROOT, 'tsconfig.refs.json');
export const REF_CONFIG_PATHS = [ROOT_REFS_CONFIG_PATH];

const sort = (arr: string[]) => arr.slice().sort((a, b) => a.localeCompare(b));

async function analyzeRootRefsConfig(log: ToolingLog) {
const compositeProjects = PROJECTS.filter((p) => p.isCompositeProject() && !p.disableTypeCheck);
const currentRefs = sort(new Project(ROOT_REFS_CONFIG_PATH).getRefdPaths());
const newRefs = sort(
compositeProjects.map((p) => `./${Path.relative(REPO_ROOT, p.tsConfigPath)}`)
);

log.verbose('updating root refs config file');
log.verbose('existing composite projects', currentRefs);
log.verbose('found the following composite projects', newRefs);

const removedRefs: string[] = [];
const addedRefs: string[] = [];

for (let i = 0; i < currentRefs.length || i < newRefs.length; ) {
const currentRef = currentRefs[i];
const newRef = newRefs[i];
if (currentRef === newRef) {
// continue with next item
i++;
continue;
}

// see if this item is lower down in current refs
const newIndex = currentRefs.indexOf(newRef, i + 1);
if (newIndex === -1) {
addedRefs.push(newRef);
currentRefs.splice(i, 0, newRef);
// recheck this index
continue;
}

// this item was removed from currentRefs
removedRefs.push(currentRef);
currentRefs.splice(i, 1);
// recheck this index
continue;
}

return {
refs: newRefs,
addedRefs,
removedRefs,
};
}

export async function validateRootRefsConfig(log: ToolingLog) {
const { addedRefs, removedRefs } = await analyzeRootRefsConfig(log);

for (const addedRef of addedRefs) {
log.warning('Missing reference to composite project', addedRef, 'in root refs config file');
}
for (const removedRef of removedRefs) {
log.warning('Extra reference to non-composite project', removedRef, 'in root refs config file');
}

if (addedRefs.length || removedRefs.length) {
throw createFailError(
'tsconfig.refs.json at the root of the repo is not valid and needs to be updated. Please run `node scripts/build_ts_refs` locally and commit the changes'
);
}
}

function generateTsConfig(refs: string[]) {
return dedent`
// This file is automatically updated when you run \`node scripts/build_ts_refs\` and validated to be up-to-date by CI
{
"include": [],
"references": [
${refs.map((p) => ` { "path": ${JSON.stringify(p)} },`).join('\n')}
]
}
`;
}

export async function updateRootRefsConfig(log: ToolingLog) {
const { refs, addedRefs, removedRefs } = await analyzeRootRefsConfig(log);

if (removedRefs.length === 0 && addedRefs.length === 0) {
log.verbose('root refs config file is up-to-date');
return;
}

for (const addedRef of addedRefs) {
log.info('Adding ref to composite project', addedRef, 'to root refs config file');
}
for (const removedRef of removedRefs) {
log.info('Removing ref to composite project', removedRef, 'to root refs config file');
}

await Fs.writeFile(ROOT_REFS_CONFIG_PATH, generateTsConfig(refs) + '\n');
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ export const getInputControlVisRenderer: (
if (!registeredController) {
const { createInputControlVisController } = await import('./vis_controller');

const Controller = createInputControlVisController(deps, handlers);
registeredController = new Controller(domNode);
registeredController = createInputControlVisController(deps, handlers, domNode);
inputControlVisRegistry.set(domNode, registeredController);

handlers.onDestroy(() => {
Expand Down
37 changes: 18 additions & 19 deletions src/plugins/input_control_vis/public/vis_controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,25 @@ import { ListControl } from './control/list_control_factory';
import { InputControlVisDependencies } from './plugin';
import { InputControlVisParams } from './types';

export type InputControlVisControllerType = InstanceType<
ReturnType<typeof createInputControlVisController>
>;
export type InputControlVisControllerType = ReturnType<typeof createInputControlVisController>;

export const createInputControlVisController = (
deps: InputControlVisDependencies,
handlers: IInterpreterRenderHandlers
handlers: IInterpreterRenderHandlers,
el: Element
) => {
return class InputControlVisController {
private I18nContext?: I18nStart['Context'];
private _isLoaded = false;
let I18nContext: I18nStart['Context'] | undefined;
let isLoaded = false;
Comment on lines +34 to +35
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes were necessary because this project wasn't being built in the composite build previously and private properties on class expressions aren't compatible. Functionality is the same but avoid the type errors


return new (class InputControlVisController {
controls: Array<RangeControl | ListControl>;
queryBarUpdateHandler: () => void;
filterManager: FilterManager;
updateSubsciption: any;
timeFilterSubscription: Subscription;
visParams?: InputControlVisParams;

constructor(public el: Element) {
constructor() {
this.controls = [];

this.queryBarUpdateHandler = this.updateControlsFromKbn.bind(this);
Expand All @@ -56,39 +55,39 @@ export const createInputControlVisController = (
.getTimeUpdate$()
.subscribe(() => {
if (this.visParams?.useTimeFilter) {
this._isLoaded = false;
isLoaded = false;
}
});
}

async render(visParams: InputControlVisParams) {
if (!this.I18nContext) {
if (!I18nContext) {
const [{ i18n }] = await deps.core.getStartServices();
this.I18nContext = i18n.Context;
I18nContext = i18n.Context;
}
if (!this._isLoaded || !isEqual(visParams, this.visParams)) {
if (!isLoaded || !isEqual(visParams, this.visParams)) {
this.visParams = visParams;
this.controls = [];
this.controls = await this.initControls(visParams);
this._isLoaded = true;
isLoaded = true;
}
this.drawVis();
}

destroy() {
this.updateSubsciption.unsubscribe();
this.timeFilterSubscription.unsubscribe();
unmountComponentAtNode(this.el);
unmountComponentAtNode(el);
this.controls.forEach((control) => control.destroy());
}

drawVis = () => {
if (!this.I18nContext) {
if (!I18nContext) {
throw new Error('no i18n context found');
}

render(
<this.I18nContext>
<I18nContext>
<VisualizationContainer handlers={handlers}>
<InputControlVis
updateFiltersOnChange={this.visParams?.updateFiltersOnChange}
Expand All @@ -102,8 +101,8 @@ export const createInputControlVisController = (
refreshControl={this.refreshControl}
/>
</VisualizationContainer>
</this.I18nContext>,
this.el
</I18nContext>,
el
);
};

Expand Down Expand Up @@ -235,5 +234,5 @@ export const createInputControlVisController = (
await this.controls[controlIndex].fetch(query);
this.drawVis();
};
};
})();
};
1 change: 1 addition & 0 deletions test/scripts/checks/type_check_plugin_public_api_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ source src/dev/ci_setup/setup_env.sh

checks-reporter-with-killswitch "Build TS Refs" \
node scripts/build_ts_refs \
--validate-root-refs-config \
--ignore-type-failures \
--clean \
--no-cache \
Expand Down
Loading