diff --git a/CHANGELOG.md b/CHANGELOG.md index bdaa23d5e63d..02755ca461bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * [Multi DataSource] Add data source config to opensearch-dashboards-docker ([#2557](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2557)) * [Multi DataSource] Make text content dynamically translated & update unit tests ([#2570](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2570)) * [Vis Builder] Change classname prefix wiz to vb ([#2581](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2581/files)) +* [Windows] Facilitate building and running OSD and plugins on Windows platforms ([#2601](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2601)) +* [Multi DataSource] Address UX comments on Data source list and create page ([#2625](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2625)) ### 🐛 Bug Fixes * [Vis Builder] Fixes auto bounds for timeseries bar chart visualization ([2401](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2401)) @@ -32,6 +34,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * [MD] Add data source param to low-level search call in Discover ([#2431](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2431)) * [Multi DataSource] Skip data source view in index pattern step when pick default ([#2574](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2574)) * [Multi DataSource] Address UX comments on Edit Data source page ([#2629](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2629)) +* [Multi DataSource] Address UX comments on index pattern management stack ([#2611](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2611)) +* [Multi DataSource] Apply get indices error handling in step index pattern ([#2652](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2652)) ### 🚞 Infrastructure diff --git a/package.json b/package.json index f95cbf55c7a2..367c0fd307f4 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "makelogs": "node scripts/makelogs", "uiFramework:compileCss": "cd packages/osd-ui-framework && yarn compileCss", "osd:watch": "node scripts/opensearch_dashboards --dev --logging.json=false", - "build:types": "rm -rf ./target/types && tsc --p tsconfig.types.json", + "build:types": "node scripts/remove.js ./target/types && tsc --p tsconfig.types.json", "docs:acceptApiChanges": "node --max-old-space-size=6144 scripts/check_published_api_changes.js --accept", "osd:bootstrap": "node scripts/build_ts_refs && node scripts/register_git_hook", "spec_to_console": "node scripts/spec_to_console", @@ -412,6 +412,7 @@ "mutation-observer": "^1.0.3", "ngreact": "^0.5.1", "nock": "12.0.3", + "node-stream-zip": "^1.15.0", "normalize-path": "^3.0.0", "nyc": "^15.1.0", "pixelmatch": "^5.1.0", @@ -461,4 +462,4 @@ "node": "14.20.0", "yarn": "^1.21.1" } -} \ No newline at end of file +} diff --git a/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts b/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts index e730a4ef9fdd..32bff7f29394 100644 --- a/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts +++ b/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts @@ -40,7 +40,7 @@ describe('getConfigurationFilePaths', () => { expect(getConfigurationFilePaths(argv)).toEqual([ resolve(cwd, join('.', 'relative-path')), - '/absolute-path', + resolve('/absolute-path'), ]); }); diff --git a/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap b/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap index c34dd719e650..38f81a0cc62b 100644 --- a/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap +++ b/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap @@ -3,6 +3,6 @@ exports[`includes stack 1`] = ` "Error: test at new SchemaError (packages/osd-config-schema/src/errors/schema_error.ts:35:5) - at Object. (packages/osd-config-schema/src/errors/schema_error.test.ts:55:11) + at Object. (packages/osd-config-schema/src/errors/schema_error.test.ts:59:11) at new Promise ()" `; diff --git a/packages/osd-config-schema/src/errors/schema_error.test.ts b/packages/osd-config-schema/src/errors/schema_error.test.ts index c6ebd5d0dbd9..9e7b5a897081 100644 --- a/packages/osd-config-schema/src/errors/schema_error.test.ts +++ b/packages/osd-config-schema/src/errors/schema_error.test.ts @@ -28,7 +28,7 @@ * under the License. */ -import { relative } from 'path'; +import { relative, sep } from 'path'; import { SchemaError } from '.'; /** @@ -37,7 +37,7 @@ import { SchemaError } from '.'; export const cleanStack = (stack: string) => stack .split('\n') - .filter((line) => !line.includes('node_modules/') && !line.includes('internal/')) + .filter((line) => !line.includes('node_modules' + sep) && !line.includes('internal/')) .map((line) => { const parts = /.*\((.*)\).?/.exec(line) || []; @@ -46,7 +46,11 @@ export const cleanStack = (stack: string) => } const path = parts[1]; - return line.replace(path, relative(process.cwd(), path)); + // Cannot use `standardize` from `@osd/utils + let relativePath = relative(process.cwd(), path); + if (process.platform === 'win32') relativePath = relativePath.replace(/\\/g, '/'); + + return line.replace(path, relativePath); }) .join('\n'); diff --git a/packages/osd-opensearch-archiver/package.json b/packages/osd-opensearch-archiver/package.json index e1c28cc47484..f130ae44138a 100644 --- a/packages/osd-opensearch-archiver/package.json +++ b/packages/osd-opensearch-archiver/package.json @@ -7,8 +7,8 @@ "devOnly": true }, "scripts": { - "osd:bootstrap": "rm -rf target && tsc", - "osd:watch": "rm -rf target && tsc --watch" + "osd:bootstrap": "node ../../scripts/remove.js target && tsc", + "osd:watch": "node ../../scripts/remove.js target && tsc --watch" }, "dependencies": { "@osd/dev-utils": "1.0.0", @@ -17,4 +17,4 @@ "devDependencies": { "@types/elasticsearch": "^5.0.33" } -} \ No newline at end of file +} diff --git a/packages/osd-opensearch/src/artifact.js b/packages/osd-opensearch/src/artifact.js index 69f443245d4d..b7d8857ba09f 100644 --- a/packages/osd-opensearch/src/artifact.js +++ b/packages/osd-opensearch/src/artifact.js @@ -186,12 +186,14 @@ async function getArtifactSpecForSnapshotFromUrl(urlVersion, log) { // issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/475 const platform = process.platform === 'win32' ? 'windows' : process.platform; const arch = process.arch === 'arm64' ? 'arm64' : 'x64'; - if (platform !== 'linux') { - throw createCliError(`Snapshots are only available for Linux`); + const extension = process.platform === 'win32' ? 'zip' : 'tar.gz'; + + if (platform !== 'linux' && platform !== 'windows') { + throw createCliError(`Snapshots are only available for Linux and Windows`); } const latestUrl = `${DAILY_SNAPSHOTS_BASE_URL}/${desiredVersion}-SNAPSHOT`; - const latestFile = `opensearch-min-${desiredVersion}-SNAPSHOT-${platform}-${arch}-latest.tar.gz`; + const latestFile = `opensearch-min-${desiredVersion}-SNAPSHOT-${platform}-${arch}-latest.${extension}`; const completeLatestUrl = `${latestUrl}/${latestFile}`; let { abc, resp } = await verifySnapshotUrl(completeLatestUrl, log); diff --git a/packages/osd-opensearch/src/artifact.test.js b/packages/osd-opensearch/src/artifact.test.js index b9c331517c74..1d5d0bdf330c 100644 --- a/packages/osd-opensearch/src/artifact.test.js +++ b/packages/osd-opensearch/src/artifact.test.js @@ -163,10 +163,10 @@ describe('Artifact', () => { }); }); - it('should throw when on a non-Linux platform', async () => { + it('should throw when on a non-Linux or non-Windows platform', async () => { Object.defineProperties(process, { platform: { - value: 'win32', + value: 'darwin', }, arch: { value: ORIGINAL_ARCHITECTURE, diff --git a/packages/osd-opensearch/src/utils/decompress.test.js b/packages/osd-opensearch/src/utils/decompress.test.js index e9e163c3ebc2..bf30b49eebaa 100644 --- a/packages/osd-opensearch/src/utils/decompress.test.js +++ b/packages/osd-opensearch/src/utils/decompress.test.js @@ -52,8 +52,8 @@ beforeEach(() => { fs.copyFileSync(path.resolve(fixturesFolder, 'snapshot.tar.gz'), tarGzSnapshot); }); -afterEach(() => { - del.sync(tmpFolder, { force: true }); +afterEach(async () => { + await del(tmpFolder, { force: true }); }); test('zip strips root directory', async () => { diff --git a/packages/osd-opensearch/src/utils/extract_config_files.test.js b/packages/osd-opensearch/src/utils/extract_config_files.test.js index 3d73d821dbc5..c9da144f6e3c 100644 --- a/packages/osd-opensearch/src/utils/extract_config_files.test.js +++ b/packages/osd-opensearch/src/utils/extract_config_files.test.js @@ -36,6 +36,7 @@ jest.mock('fs', () => ({ const { extractConfigFiles } = require('./extract_config_files'); const fs = require('fs'); +const path = require('path'); afterEach(() => { jest.clearAllMocks(); @@ -55,7 +56,7 @@ test('copies file', () => { extractConfigFiles(['path=/data/foo.yml'], '/opensearch'); expect(fs.readFileSync.mock.calls[0][0]).toEqual('/data/foo.yml'); - expect(fs.writeFileSync.mock.calls[0][0]).toEqual('/opensearch/config/foo.yml'); + expect(fs.writeFileSync.mock.calls[0][0]).toEqual(path.resolve('/opensearch/config/foo.yml')); }); test('ignores file which does not exist', () => { diff --git a/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js b/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js index 235ce9fd6690..10b3dd78ff94 100644 --- a/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js +++ b/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js @@ -27,6 +27,7 @@ * specific language governing permissions and limitations * under the License. */ +const path = require('path'); jest.mock('fs', () => ({ statSync: jest.fn().mockImplementation((path) => { @@ -57,7 +58,7 @@ const { findMostRecentlyChanged } = require('./find_most_recently_changed'); test('returns newest file', () => { const file = findMostRecentlyChanged('/data/*.yml'); - expect(file).toEqual('/data/newest.yml'); + expect(file).toEqual(path.resolve('/data/newest.yml')); }); afterAll(() => { diff --git a/packages/osd-optimizer/src/common/bundle.test.ts b/packages/osd-optimizer/src/common/bundle.test.ts index 16aa012cf91d..ceb7eff4b1db 100644 --- a/packages/osd-optimizer/src/common/bundle.test.ts +++ b/packages/osd-optimizer/src/common/bundle.test.ts @@ -28,6 +28,7 @@ * under the License. */ +import { resolve } from 'path'; import { Bundle, BundleSpec, parseBundles } from './bundle'; jest.mock('fs'); @@ -88,13 +89,16 @@ it('provides the module count from the cache', () => { it('parses bundles from JSON specs', () => { const bundles = parseBundles(JSON.stringify([SPEC])); + let expectedCachePath = resolve('/foo/bar/target/.osd-optimizer-cache'); + // Cannot use `standardize` from `@osd/util` due to mocking of fs + if (process?.platform === 'win32') expectedCachePath = expectedCachePath.replace(/\\/g, '\\\\'); expect(bundles).toMatchInlineSnapshot(` Array [ Bundle { "banner": undefined, "cache": BundleCache { - "path": "/foo/bar/target/.osd-optimizer-cache", + "path": "${expectedCachePath}", "state": undefined, }, "contextDir": "/foo/bar", diff --git a/packages/osd-optimizer/src/optimizer/get_changes.test.ts b/packages/osd-optimizer/src/optimizer/get_changes.test.ts index 071bb8e1a260..44e1637d5437 100644 --- a/packages/osd-optimizer/src/optimizer/get_changes.test.ts +++ b/packages/osd-optimizer/src/optimizer/get_changes.test.ts @@ -28,9 +28,12 @@ * under the License. */ +import path from 'path'; + jest.mock('execa'); import { getChanges } from './get_changes'; +import { standardize } from '@osd/dev-utils'; const execa: jest.Mock = jest.requireMock('execa'); @@ -56,12 +59,16 @@ it('parses git ls-files output', async () => { }; }); + const rootPath = path.resolve('/foo/bar/x/osd-optimizer') + path.sep; + const srcPath = path.join(rootPath, 'src') + path.sep; + const commonPath = path.join(srcPath, 'common') + path.sep; + await expect(getChanges('/foo/bar/x')).resolves.toMatchInlineSnapshot(` Map { - "/foo/bar/x/osd-optimizer/package.json" => "modified", - "/foo/bar/x/osd-optimizer/src/common/bundle.ts" => "modified", - "/foo/bar/x/osd-optimizer/src/common/bundles.ts" => "deleted", - "/foo/bar/x/osd-optimizer/src/get_bundle_definitions.test.ts" => "deleted", + "${standardize(rootPath, false, true)}package.json" => "modified", + "${standardize(commonPath, false, true)}bundle.ts" => "modified", + "${standardize(commonPath, false, true)}bundles.ts" => "deleted", + "${standardize(srcPath, false, true)}get_bundle_definitions.test.ts" => "deleted", } `); }); diff --git a/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts b/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts index 608b16a3661d..28ee6179f011 100644 --- a/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts +++ b/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts @@ -31,10 +31,15 @@ import { createAbsolutePathSerializer } from '@osd/dev-utils'; import { getPluginBundles } from './get_plugin_bundles'; +import path from 'path'; expect.addSnapshotSerializer(createAbsolutePathSerializer('/repo', '')); expect.addSnapshotSerializer(createAbsolutePathSerializer('/output', '')); +expect.addSnapshotSerializer(createAbsolutePathSerializer(path.resolve('/output'), '')); expect.addSnapshotSerializer(createAbsolutePathSerializer('/outside/of/repo', '')); +expect.addSnapshotSerializer( + createAbsolutePathSerializer(path.resolve('/outside/of/repo'), '') +); it('returns a bundle for core and each plugin', () => { expect( diff --git a/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts b/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts index 51378b14470d..45ec5a6986a1 100644 --- a/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts +++ b/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts @@ -32,13 +32,17 @@ import Path from 'path'; import del from 'del'; import execa from 'execa'; -import { REPO_ROOT } from '@osd/utils'; -import { createAbsolutePathSerializer } from '@osd/dev-utils'; +import { REPO_ROOT, standardize, createAbsolutePathSerializer } from '@osd/dev-utils'; import globby from 'globby'; -const GENERATED_DIR = Path.resolve(REPO_ROOT, `plugins`); +// Has to be a posix reference because it is used to generate glob patterns +const GENERATED_DIR = standardize(Path.resolve(REPO_ROOT, `plugins`), true); -expect.addSnapshotSerializer(createAbsolutePathSerializer()); +expect.addSnapshotSerializer( + createAbsolutePathSerializer( + process?.platform === 'win32' ? standardize(REPO_ROOT, true) : REPO_ROOT + ) +); beforeEach(async () => { await del([`${GENERATED_DIR}/**`, `!${GENERATED_DIR}`, `!${GENERATED_DIR}/.gitignore`], { diff --git a/packages/osd-plugin-helpers/package.json b/packages/osd-plugin-helpers/package.json index 447199730184..3738aae36b1a 100644 --- a/packages/osd-plugin-helpers/package.json +++ b/packages/osd-plugin-helpers/package.json @@ -12,7 +12,7 @@ "plugin-helpers": "bin/plugin-helpers.js" }, "scripts": { - "osd:bootstrap": "rm -rf target && tsc", + "osd:bootstrap": "node ../../scripts/remove.js && tsc", "osd:watch": "tsc --watch" }, "dependencies": { diff --git a/packages/osd-plugin-helpers/src/integration_tests/build.test.ts b/packages/osd-plugin-helpers/src/integration_tests/build.test.ts index 4dc550e5004e..35195f9bc163 100644 --- a/packages/osd-plugin-helpers/src/integration_tests/build.test.ts +++ b/packages/osd-plugin-helpers/src/integration_tests/build.test.ts @@ -32,8 +32,12 @@ import Path from 'path'; import Fs from 'fs'; import execa from 'execa'; -import { REPO_ROOT } from '@osd/utils'; -import { createStripAnsiSerializer, createReplaceSerializer } from '@osd/dev-utils'; +import { + REPO_ROOT, + standardize, + createStripAnsiSerializer, + createReplaceSerializer, +} from '@osd/dev-utils'; import extract from 'extract-zip'; import del from 'del'; import globby from 'globby'; @@ -78,7 +82,7 @@ it('builds a generated plugin into a viable archive', async () => { expect(generateProc.all).toMatchInlineSnapshot(` " succ 🎉 - Your plugin has been created in plugins/foo_test_plugin + Your plugin has been created in ${standardize('plugins/foo_test_plugin', false, true)} " `); @@ -165,7 +169,7 @@ it('builds a non-semver generated plugin into a viable archive', async () => { expect(generateProc.all).toMatchInlineSnapshot(` " succ 🎉 - Your plugin has been created in plugins/foo_test_plugin + Your plugin has been created in ${standardize('plugins/foo_test_plugin', false, true)} " `); diff --git a/packages/osd-pm/src/utils/projects.test.ts b/packages/osd-pm/src/utils/projects.test.ts index 57935452feb9..545b435a7e09 100644 --- a/packages/osd-pm/src/utils/projects.test.ts +++ b/packages/osd-pm/src/utils/projects.test.ts @@ -53,7 +53,8 @@ describe('#getProjects', () => { await promisify(symlink)( join(__dirname, '__fixtures__/symlinked-plugins/corge'), - join(rootPlugins, 'corge') + join(rootPlugins, 'corge'), + 'junction' // This parameter would only be used on Windows ); }); diff --git a/packages/osd-pm/src/utils/projects_tree.ts b/packages/osd-pm/src/utils/projects_tree.ts index 5a455f35ea63..41f9e4331098 100644 --- a/packages/osd-pm/src/utils/projects_tree.ts +++ b/packages/osd-pm/src/utils/projects_tree.ts @@ -31,6 +31,7 @@ import chalk from 'chalk'; import path from 'path'; +import { standardize } from '@osd/utils'; import { Project } from './project'; const projectKey = Symbol('__project'); @@ -117,7 +118,7 @@ function createTreeStructure(tree: IProjectsTree): ITree { // `foo/bar/baz` instead. if (subtree.children && subtree.children.length === 1) { const child = subtree.children[0]; - const newName = chalk.dim(path.join(dir.toString(), child.name!)); + const newName = chalk.dim(standardize(path.join(dir.toString(), child.name!), true)); children.push({ children: child.children, diff --git a/packages/osd-telemetry-tools/src/tools/ts_parser.ts b/packages/osd-telemetry-tools/src/tools/ts_parser.ts index 2932bd76d470..31940dcfdfd3 100644 --- a/packages/osd-telemetry-tools/src/tools/ts_parser.ts +++ b/packages/osd-telemetry-tools/src/tools/ts_parser.ts @@ -31,7 +31,7 @@ import * as ts from 'typescript'; import { createFailError } from '@osd/dev-utils'; import * as path from 'path'; -import { getProperty, getPropertyValue } from './utils'; +import { getProperty, getPropertyValue, normalizePath } from './utils'; import { getDescriptor, Descriptor } from './serializer'; export function* traverseNodes(maybeNodes: ts.Node | ts.Node[]): Generator { @@ -205,7 +205,7 @@ export function* parseUsageCollection( sourceFile: ts.SourceFile, program: ts.Program ): Generator { - const relativePath = path.relative(process.cwd(), sourceFile.fileName); + const relativePath = normalizePath(path.relative(process.cwd(), sourceFile.fileName), false); if (sourceHasUsageCollector(sourceFile)) { for (const node of traverseNodes(sourceFile)) { if (isMakeUsageCollectorFunction(node, sourceFile)) { diff --git a/packages/osd-telemetry-tools/src/tools/utils.ts b/packages/osd-telemetry-tools/src/tools/utils.ts index 3df213f82784..237175769479 100644 --- a/packages/osd-telemetry-tools/src/tools/utils.ts +++ b/packages/osd-telemetry-tools/src/tools/utils.ts @@ -311,6 +311,7 @@ export function difference(actual: any, expected: any) { return changes(actual, expected); } -export function normalizePath(inputPath: string) { - return normalize(path.relative('.', inputPath)); +export function normalizePath(inputPath: string, relativeToRoot: boolean = true) { + if (relativeToRoot) return normalize(path.relative('.', inputPath)); + return normalize(inputPath); } diff --git a/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts b/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts index f7c45727734c..cc628b9de811 100644 --- a/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts +++ b/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts @@ -40,7 +40,7 @@ import { REPO_ROOT } from '@osd/dev-utils'; import { Lifecycle } from './lifecycle'; import { SuiteTracker } from './suite_tracker'; -const DEFAULT_TEST_METADATA_PATH = join(REPO_ROOT, 'target', 'test_metadata.json'); +const DEFAULT_TEST_METADATA_PATH = resolve(REPO_ROOT, 'target', 'test_metadata.json'); const MOCK_CONFIG_PATH = join('test', 'config.js'); const MOCK_TEST_PATH = join('test', 'apps', 'test.js'); const ENVS_TO_RESET = ['TEST_METADATA_PATH']; diff --git a/packages/osd-utils/src/path/index.ts b/packages/osd-utils/src/path/index.ts index c661b04fb6ad..263d2d39ac36 100644 --- a/packages/osd-utils/src/path/index.ts +++ b/packages/osd-utils/src/path/index.ts @@ -28,7 +28,7 @@ * under the License. */ -import { join } from 'path'; +import { join, normalize } from 'path'; import { accessSync, constants } from 'fs'; import { TypeOf, schema } from '@osd/config-schema'; import { REPO_ROOT } from '../repo_root'; @@ -94,3 +94,27 @@ export const config = { data: schema.string({ defaultValue: () => getDataPath() }), }), }; + +/** + * Get a standardized reference to a path + * @param {string} path - the path to standardize + * @param {boolean} [usePosix=true] - produce a posix reference + * @param {boolean} [escapedBackslashes=true] - on Windows, double-backslash the reference + * @internal + */ +export const standardize = ( + path: string, + usePosix: boolean = true, + escapedBackslashes: boolean = true +) => { + /* Force os-dependant separators + * path.posix.normalize doesn't convert backslashes to slashes on Windows so we manually force it afterwards + */ + const normal = normalize(path); + + // Filter out in-browser executions as well as non-windows ones + if (process?.platform !== 'win32') return normal; + + if (usePosix) return normal.replace(/\\/g, '/'); + return escapedBackslashes ? normal.replace(/\\/g, '\\\\') : normal; +}; diff --git a/scripts/remove.js b/scripts/remove.js new file mode 100644 index 000000000000..cc3c62739371 --- /dev/null +++ b/scripts/remove.js @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/* eslint no-restricted-syntax: 0 */ +const del = require('del'); +const path = require('path'); + +if (!process.argv.includes(__filename)) { + console.error('Usage: node scripts/remove.js '); + process.exit(1); +} + +const toDeletes = process.argv + .slice(process.argv.indexOf(__filename + 1)) + .map((item) => path.resolve(item)); + +if (toDeletes.length === 0) { + console.warn('Nothing to delete'); + process.exit(0); +} + +(async () => { + const deletedPaths = await del(toDeletes); + if (deletedPaths === 0) { + console.warn('Nothing deleted'); + } else { + console.log('Deleted files and directories:\n\t', deletedPaths.join('\n\t')); + } +})(); diff --git a/src/cli_plugin/install/pack.test.js b/src/cli_plugin/install/pack.test.js index 5520e34bc3bb..783593c6d9fa 100644 --- a/src/cli_plugin/install/pack.test.js +++ b/src/cli_plugin/install/pack.test.js @@ -72,10 +72,11 @@ describe('opensearchDashboards cli', function () { Fs.mkdirSync(testWorkingPath, { recursive: true }); }); - afterEach(function () { + afterEach(async () => { logger.log.restore(); logger.error.restore(); - del.sync(workingPathRoot); + + await del(workingPathRoot); }); function copyReplyFile(filename) { diff --git a/src/cli_plugin/install/settings.js b/src/cli_plugin/install/settings.js index 3d7cdec3d620..2b0c34bfcd37 100644 --- a/src/cli_plugin/install/settings.js +++ b/src/cli_plugin/install/settings.js @@ -44,9 +44,7 @@ function generateUrls({ version, plugin }) { function generatePluginUrl(version, plugin) { const platform = process.platform === 'win32' ? 'windows' : process.platform; const arch = process.arch === 'arm64' ? 'arm64' : 'x64'; - if (platform !== 'linux') { - throw new Error('Plugins are only available for Linux'); - } + return `${LATEST_PLUGIN_BASE_URL}/${version}/latest/${platform}/${arch}/tar/builds/opensearch-dashboards/plugins/${plugin}-${version}.zip`; } diff --git a/src/cli_plugin/install/settings.test.js b/src/cli_plugin/install/settings.test.js index dc769496e9e4..ac7cf94e6761 100644 --- a/src/cli_plugin/install/settings.test.js +++ b/src/cli_plugin/install/settings.test.js @@ -137,7 +137,7 @@ describe('parse function', function () { `); }); - it('should throw when on a non-Linux platform', function () { + it('produces expected results on Windows', function () { Object.defineProperties(process, { platform: { value: 'win32', @@ -146,9 +146,23 @@ describe('parse function', function () { value: 'x64', }, }); - expect(() => parse(command, { ...defaultOptions }, osdPackage)).toThrow( - 'Plugins are only available for Linux' - ); + expect(parse(command, { ...defaultOptions }, osdPackage)).toMatchInlineSnapshot(` + Object { + "config": "", + "plugin": "plugin name", + "pluginDir": /plugins, + "quiet": false, + "silent": false, + "tempArchiveFile": /plugins/.plugin.installing/archive.part, + "timeout": 0, + "urls": Array [ + "plugin name", + "https://ci.opensearch.org/ci/dbc/distribution-build-opensearch-dashboards/1234/latest/windows/x64/tar/builds/opensearch-dashboards/plugins/plugin name-1234.zip", + ], + "version": 1234, + "workingPath": /plugins/.plugin.installing, + } + `); }); it('should not throw when on a non-x64 arch', function () { diff --git a/src/cli_plugin/install/zip.test.js b/src/cli_plugin/install/zip.test.js index f010acdd8295..206b091c367d 100644 --- a/src/cli_plugin/install/zip.test.js +++ b/src/cli_plugin/install/zip.test.js @@ -48,8 +48,8 @@ describe('opensearchDashboards cli', function () { tempPath = path.resolve(os.tmpdir(), randomDir); }); - afterEach(() => { - del.sync(tempPath, { force: true }); + afterEach(async () => { + await del(tempPath, { force: true }); }); describe('analyzeArchive', function () { diff --git a/src/core/server/metrics/collectors/cgroup.test.ts b/src/core/server/metrics/collectors/cgroup.test.ts index 633b3c8aeae5..50fc952566bc 100644 --- a/src/core/server/metrics/collectors/cgroup.test.ts +++ b/src/core/server/metrics/collectors/cgroup.test.ts @@ -31,6 +31,7 @@ import mockFs from 'mock-fs'; import { loggerMock } from '@osd/logging/target/mocks'; import { OsCgroupMetricsCollector } from './cgroup'; +import path from 'path'; describe('OsCgroupMetricsCollector', () => { afterEach(() => mockFs.restore()); @@ -140,10 +141,14 @@ throttled_time 666 const logger = loggerMock.create(); + const usagePath = + (process.platform === 'win32' ? '\\\\?\\' : '') + + path.resolve('/sys/fs/cgroup/cpuacct/groupname/cpuacct.usage'); + const collector = new OsCgroupMetricsCollector({ logger }); expect(await collector.collect()).toEqual({}); expect(logger.error).toHaveBeenCalledWith( - "cgroup metrics could not be read due to error: [Error: EACCES, permission denied '/sys/fs/cgroup/cpuacct/groupname/cpuacct.usage']" + `cgroup metrics could not be read due to error: [Error: EACCES, permission denied '${usagePath}']` ); }); }); diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.ts b/src/core/server/plugins/discovery/plugins_discovery.test.ts index bc7480bb8adb..92b2cb71ef98 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.test.ts +++ b/src/core/server/plugins/discovery/plugins_discovery.test.ts @@ -44,6 +44,7 @@ import { discover } from './plugins_discovery'; import { CoreContext } from '../../core_context'; const OPENSEARCH_DASHBOARDS_ROOT = process.cwd(); +const EXTENDED_PATH_PREFIX = process.platform === 'win32' ? '\\\\?\\' : ''; const Plugins = { invalid: () => ({ @@ -243,7 +244,7 @@ describe('plugins discovery system', () => { const srcPluginsPath = resolve(OPENSEARCH_DASHBOARDS_ROOT, 'src', 'plugins'); expect(errors).toEqual( expect.arrayContaining([ - `Error: EACCES, permission denied '${srcPluginsPath}' (invalid-search-path, ${srcPluginsPath})`, + `Error: EACCES, permission denied '${EXTENDED_PATH_PREFIX}${srcPluginsPath}' (invalid-search-path, ${srcPluginsPath})`, ]) ); }); @@ -278,7 +279,7 @@ describe('plugins discovery system', () => { const errorPath = manifestPath('plugin_a'); expect(errors).toEqual( expect.arrayContaining([ - `Error: EACCES, permission denied '${errorPath}' (missing-manifest, ${errorPath})`, + `Error: EACCES, permission denied '${EXTENDED_PATH_PREFIX}${errorPath}' (missing-manifest, ${errorPath})`, ]) ); }); diff --git a/src/core/server/plugins/integration_tests/plugins_service.test.ts b/src/core/server/plugins/integration_tests/plugins_service.test.ts index 29396d0acce6..34310ea3de37 100644 --- a/src/core/server/plugins/integration_tests/plugins_service.test.ts +++ b/src/core/server/plugins/integration_tests/plugins_service.test.ts @@ -32,7 +32,7 @@ import { REPO_ROOT } from '@osd/dev-utils'; import { mockPackage, mockDiscover } from './plugins_service.test.mocks'; -import { join } from 'path'; +import { posix } from 'path'; import { PluginsService } from '../plugins_service'; import { ConfigPath, ConfigService, Env } from '../../config'; @@ -163,7 +163,7 @@ describe('PluginsService', () => { } as Plugin); jest.doMock( - join(pluginPath, 'server'), + posix.join(pluginPath, 'server'), () => ({ plugin: pluginInitializer, }), diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts index 1858f7557adb..9543d379493c 100644 --- a/src/core/server/plugins/plugin.test.ts +++ b/src/core/server/plugins/plugin.test.ts @@ -28,7 +28,7 @@ * under the License. */ -import { join } from 'path'; +import { posix } from 'path'; import { BehaviorSubject } from 'rxjs'; import { REPO_ROOT } from '@osd/dev-utils'; import { schema } from '@osd/config-schema'; @@ -47,6 +47,7 @@ import { InstanceInfo, } from './plugin_context'; +const { join } = posix; const mockPluginInitializer = jest.fn(); const logger = loggingSystemMock.create(); jest.doMock( diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index 7dbe4da4cc51..89a2aecc82f3 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -28,7 +28,7 @@ * under the License. */ -import { join } from 'path'; +import { posix } from 'path'; import typeDetect from 'type-detect'; import { Subject } from 'rxjs'; import { first } from 'rxjs/operators'; @@ -45,6 +45,8 @@ import { } from './types'; import { CoreSetup, CoreStart } from '..'; +const { join } = posix; + /** * Lightweight wrapper around discovered plugin that is responsible for instantiating * plugin and dispatching proper context and dependencies into plugin's lifecycle hooks. diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index cc4ac5e65fa5..cff5ae79b914 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -30,7 +30,7 @@ import { mockDiscover, mockPackage } from './plugins_service.test.mocks'; -import { resolve, join } from 'path'; +import { resolve, posix } from 'path'; import { BehaviorSubject, from } from 'rxjs'; import { schema } from '@osd/config-schema'; import { createAbsolutePathSerializer, REPO_ROOT } from '@osd/dev-utils'; @@ -48,6 +48,7 @@ import { config } from './plugins_config'; import { take } from 'rxjs/operators'; import { DiscoveredPlugin } from './types'; +const { join } = posix; const MockPluginsSystem: jest.Mock = PluginsSystem as any; let pluginsService: PluginsService; diff --git a/src/dev/build/args.test.ts b/src/dev/build/args.test.ts index 262305f62250..2304c560a687 100644 --- a/src/dev/build/args.test.ts +++ b/src/dev/build/args.test.ts @@ -62,6 +62,7 @@ it('build dist for current platform, without packages, by default', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -90,6 +91,7 @@ it('build dist for linux x64 platform, without packages, if --linux is passed', "darwin": false, "linux": true, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -118,6 +120,7 @@ it('build dist for linux arm64 platform, without packages, if --linux-arm is pas "darwin": false, "linux": false, "linuxArm": true, + "windows": false, }, "versionQualifier": "", }, @@ -146,6 +149,36 @@ it('build dist for darwin x64 platform, without packages, if --darwin is passed' "darwin": true, "linux": false, "linuxArm": false, + "windows": false, + }, + "versionQualifier": "", + }, + "log": , + "showHelp": false, + "unknownFlags": Array [], + } + `); +}); + +it('build dist for windows x64 platform, without packages, if --windows is passed', () => { + expect(readCliArgs(['node', 'scripts/build-platform', '--windows'])).toMatchInlineSnapshot(` + Object { + "buildOptions": Object { + "createArchives": true, + "createDebArmPackage": false, + "createDebPackage": false, + "createDockerPackage": false, + "createDockerUbiPackage": false, + "createRpmArmPackage": false, + "createRpmPackage": false, + "downloadFreshNode": true, + "isRelease": false, + "targetAllPlatforms": false, + "targetPlatforms": Object { + "darwin": false, + "linux": false, + "linuxArm": false, + "windows": true, }, "versionQualifier": "", }, @@ -174,6 +207,7 @@ it('builds packages if --all-platforms is passed', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -202,6 +236,7 @@ it('limits packages if --rpm passed with --all-platforms', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -230,6 +265,7 @@ it('limits packages if --deb passed with --all-platforms', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -259,6 +295,7 @@ it('limits packages if --docker passed with --all-platforms', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -288,6 +325,7 @@ it('limits packages if --docker passed with --skip-docker-ubi and --all-platform "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, diff --git a/src/dev/build/args.ts b/src/dev/build/args.ts index 7c16b6de5393..7e131174e330 100644 --- a/src/dev/build/args.ts +++ b/src/dev/build/args.ts @@ -50,6 +50,7 @@ export function readCliArgs(argv: string[]) { 'verbose', 'debug', 'all-platforms', + 'windows', 'darwin', 'linux', 'linux-arm', @@ -130,6 +131,7 @@ export function readCliArgs(argv: string[]) { createDockerPackage: isOsPackageDesired('docker'), createDockerUbiPackage: isOsPackageDesired('docker') && !Boolean(flags['skip-docker-ubi']), targetPlatforms: { + windows: Boolean(flags.windows), darwin: Boolean(flags.darwin), linux: Boolean(flags.linux), linuxArm: Boolean(flags['linux-arm']), diff --git a/src/dev/build/cli.ts b/src/dev/build/cli.ts index 0153a1768c9b..b075a6047acd 100644 --- a/src/dev/build/cli.ts +++ b/src/dev/build/cli.ts @@ -58,9 +58,10 @@ if (showHelp) { --skip-archives {dim Don't produce tar/zip archives} --skip-os-packages {dim Don't produce rpm/deb/docker packages} --all-platforms {dim Produce archives for all platforms, not just this one} - --linux {dim Produce archives for only linux x64 platform} - --linux-arm {dim Produce archives for only linux arm64 platform} - --darwin {dim Produce archives for only darwin x64 platform} + --linux {dim Produce archives only for linux x64 platform} + --linux-arm {dim Produce archives only for linux arm64 platform} + --darwin {dim Produce archives only for darwin x64 platform} + --windows {dim Produce archives only for windows x64 platform} --rpm {dim Only build the rpm package} --deb {dim Only build the deb package} --docker {dim Only build the docker image} diff --git a/src/dev/build/lib/config.test.ts b/src/dev/build/lib/config.test.ts index 57b9775bf3f2..db96a8c18dd0 100644 --- a/src/dev/build/lib/config.test.ts +++ b/src/dev/build/lib/config.test.ts @@ -30,7 +30,7 @@ import { resolve } from 'path'; -import { REPO_ROOT } from '@osd/utils'; +import { REPO_ROOT, standardize } from '@osd/utils'; import { createAbsolutePathSerializer } from '@osd/dev-utils'; import pkg from '../../../../package.json'; @@ -54,6 +54,7 @@ const setup = async ({ darwin: false, linux: false, linuxArm: false, + windows: false, }, }: { targetAllPlatforms?: boolean; @@ -61,6 +62,7 @@ const setup = async ({ darwin: boolean; linux: boolean; linuxArm: boolean; + windows: boolean; }; } = {}) => { return await Config.create({ @@ -87,7 +89,9 @@ describe('#getNodeVersion()', () => { describe('#getRepoRelativePath()', () => { it('converts an absolute path to relative path, from the root of the repo', async () => { const config = await setup(); - expect(config.getRepoRelativePath(__dirname)).toMatchInlineSnapshot(`"src/dev/build/lib"`); + expect(config.getRepoRelativePath(__dirname)).toMatchInlineSnapshot( + `"${standardize('src/dev/build/lib', false, true)}"` + ); }); }); @@ -115,6 +119,7 @@ describe('#hasSpecifiedPlatform', () => { darwin: true, linux: false, linuxArm: false, + windows: false, }, }); expect(config.hasSpecifiedPlatform() === true); @@ -127,6 +132,7 @@ describe('#hasSpecifiedPlatform', () => { darwin: false, linux: false, linuxArm: true, + windows: false, }, }); expect(config.hasSpecifiedPlatform() === true); @@ -139,6 +145,7 @@ describe('#hasSpecifiedPlatform', () => { darwin: false, linux: true, linuxArm: false, + windows: false, }, }); expect(config.hasSpecifiedPlatform() === true); @@ -205,6 +212,7 @@ describe('#getTargetPlatforms()', () => { darwin: true, linux: false, linuxArm: false, + windows: false, }, }); @@ -227,6 +235,7 @@ describe('#getTargetPlatforms()', () => { darwin: false, linux: true, linuxArm: false, + windows: false, }, }); @@ -249,6 +258,7 @@ describe('#getTargetPlatforms()', () => { darwin: false, linux: false, linuxArm: true, + windows: false, }, }); @@ -271,6 +281,7 @@ describe('#getTargetPlatforms()', () => { darwin: true, linux: false, linuxArm: true, + windows: false, }, }); diff --git a/src/dev/build/lib/config.ts b/src/dev/build/lib/config.ts index 2804a702be42..4f47a5ec8f50 100644 --- a/src/dev/build/lib/config.ts +++ b/src/dev/build/lib/config.ts @@ -143,6 +143,7 @@ export class Config { const platforms: Platform[] = []; if (this.targetPlatforms.darwin) platforms.push(this.getPlatform('darwin', 'x64')); if (this.targetPlatforms.linux) platforms.push(this.getPlatform('linux', 'x64')); + if (this.targetPlatforms.windows) platforms.push(this.getPlatform('win32', 'x64')); if (this.targetPlatforms.linuxArm) platforms.push(this.getPlatform('linux', 'arm64')); if (platforms.length > 0) return platforms; @@ -153,7 +154,7 @@ export class Config { /** * Return the list of Platforms we need/have node downloads for. We always * include the linux platform even if we aren't targeting linux so we can - * reliably get the LICENSE file, which isn't included in the windows version + * reliably get the LICENSE file. */ getNodePlatforms() { if (this.targetAllPlatforms) { @@ -164,6 +165,7 @@ export class Config { return [this.getPlatform('linux', 'x64')]; } + // ToDo: All node dists, including Windows, contain a LICENSE file; do we still need to do this? return [this.getPlatformForThisOs(), this.getPlatform('linux', 'x64')]; } diff --git a/src/dev/build/lib/exec.test.ts b/src/dev/build/lib/exec.test.ts index 2dc75b3a311c..7257f7f88db7 100644 --- a/src/dev/build/lib/exec.test.ts +++ b/src/dev/build/lib/exec.test.ts @@ -39,6 +39,8 @@ import { import { exec } from './exec'; +const escapedPathToNode = Path.sep === '\\' ? '\\\\node.exe' : '/node'; + const testWriter = new ToolingLogCollectingWriter(); const log = new ToolingLog(); log.setWriters([testWriter]); @@ -59,7 +61,7 @@ it('executes a command, logs the command, and logs the output', async () => { await exec(log, process.execPath, ['-e', 'console.log("hi")']); expect(testWriter.messages).toMatchInlineSnapshot(` Array [ - " debg $ /node -e console.log(\\"hi\\")", + " debg $ ${escapedPathToNode} -e console.log(\\"hi\\")", " debg hi", ] `); @@ -71,7 +73,7 @@ it('logs using level: option', async () => { }); expect(testWriter.messages).toMatchInlineSnapshot(` Array [ - " info $ /node -e console.log(\\"hi\\")", + " info $ ${escapedPathToNode} -e console.log(\\"hi\\")", " info hi", ] `); diff --git a/src/dev/build/lib/fs.ts b/src/dev/build/lib/fs.ts index ae846ef7d670..53fc241f7722 100644 --- a/src/dev/build/lib/fs.ts +++ b/src/dev/build/lib/fs.ts @@ -36,6 +36,7 @@ import { createGunzip } from 'zlib'; import { inspect, promisify } from 'util'; import archiver from 'archiver'; +import * as StreamZip from 'node-stream-zip'; import vfs from 'vinyl-fs'; import File from 'vinyl'; import del from 'del'; @@ -183,7 +184,7 @@ export async function copyAll( destination: string, options: CopyAllOptions = {} ) { - const { select = ['**/*'], dot = false, time = Date.now() } = options; + const { select = ['**/*'], dot = false, time = Date.now() / 1000 } = options; assertAbsolute(sourceDir); assertAbsolute(destination); @@ -266,6 +267,38 @@ export async function gunzip(source: string, destination: string) { ); } +interface UnzipOptions { + strip?: boolean | number; +} + +export async function unzip(source: string, destination: string, options: UnzipOptions) { + assertAbsolute(source); + assertAbsolute(destination); + + await mkdirAsync(destination, { recursive: true }); + + const zip = new StreamZip.async({ file: source }); + + if (!options.strip || !isFinite(options.strip as number)) { + // Extract the entire archive + await zip.extract(null, destination); + } else { + const stripLevels = options.strip === true ? 1 : options.strip; + + // Find the directories that are `stripLevels` deep and extract them only + for (const entry of Object.values(await zip.entries())) { + if (!entry.isDirectory) continue; + + const pathDepth = entry.name.replace(/\/+$/, '').split('/').length; + if (stripLevels === pathDepth) { + await zip.extract(entry.name, destination); + } + } + } + + await zip.close(); +} + interface CompressTarOptions { createRootDirectory: boolean; source: string; @@ -325,3 +358,7 @@ export async function compressZip({ return fileCount; } + +export function normalizePath(loc: string) { + return sep === '\\' ? loc.replace(/\\/g, '/') : loc; +} diff --git a/src/dev/build/lib/platform.ts b/src/dev/build/lib/platform.ts index 6553bcd3b11b..673356ec6205 100644 --- a/src/dev/build/lib/platform.ts +++ b/src/dev/build/lib/platform.ts @@ -35,6 +35,7 @@ export interface TargetPlatforms { darwin: boolean; linuxArm: boolean; linux: boolean; + windows: boolean; } export class Platform { diff --git a/src/dev/build/tasks/clean_tasks.ts b/src/dev/build/tasks/clean_tasks.ts index 8b1d635cdde6..c420a6b36b2c 100644 --- a/src/dev/build/tasks/clean_tasks.ts +++ b/src/dev/build/tasks/clean_tasks.ts @@ -30,7 +30,7 @@ import minimatch from 'minimatch'; -import { deleteAll, deleteEmptyFolders, scanDelete, Task, GlobalTask } from '../lib'; +import { deleteAll, deleteEmptyFolders, scanDelete, Task, GlobalTask, normalizePath } from '../lib'; export const Clean: GlobalTask = { global: true, @@ -190,8 +190,8 @@ export const CleanExtraBinScripts: Task = { if (platform.isWindows()) { await deleteAll( [ - build.resolvePathForPlatform(platform, 'bin', '*'), - `!${build.resolvePathForPlatform(platform, 'bin', '*.bat')}`, + normalizePath(build.resolvePathForPlatform(platform, 'bin', '*')), + `!${normalizePath(build.resolvePathForPlatform(platform, 'bin', '*.bat'))}`, ], log ); diff --git a/src/dev/build/tasks/nodejs/clean_node_builds_task.ts b/src/dev/build/tasks/nodejs/clean_node_builds_task.ts index 490d71e6d70d..938f7f43f692 100644 --- a/src/dev/build/tasks/nodejs/clean_node_builds_task.ts +++ b/src/dev/build/tasks/nodejs/clean_node_builds_task.ts @@ -28,7 +28,7 @@ * under the License. */ -import { deleteAll, Task } from '../../lib'; +import { deleteAll, normalizePath, Task } from '../../lib'; export const CleanNodeBuilds: Task = { description: 'Cleaning npm from node', @@ -37,9 +37,11 @@ export const CleanNodeBuilds: Task = { for (const platform of config.getTargetPlatforms()) { await deleteAll( [ - build.resolvePathForPlatform(platform, 'node/lib/node_modules'), - build.resolvePathForPlatform(platform, 'node/bin/npm'), - build.resolvePathForPlatform(platform, 'node/bin/npx'), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/node_modules')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/npm*')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/npx*')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/corepack*')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/nodevars*')), ], log ); diff --git a/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts b/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts index 73e23ecdf270..6b3a066a1d2d 100644 --- a/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts +++ b/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts @@ -69,6 +69,7 @@ async function setup() { linux: false, linuxArm: false, darwin: false, + windows: false, }, }); @@ -101,15 +102,6 @@ it('runs expected fs operations', async () => { expect(usedMethods).toMatchInlineSnapshot(` Object { - "copy": Array [ - Array [ - /.node_binaries//node.exe, - /.node_binaries//win32-x64/node.exe, - Object { - "clone": true, - }, - ], - ], "untar": Array [ Array [ /.node_binaries//node-v-linux-x64.tar.gz, @@ -133,6 +125,15 @@ it('runs expected fs operations', async () => { }, ], ], + "unzip": Array [ + Array [ + /.node_binaries//node-v-win-x64.zip, + /.node_binaries//win32-x64, + Object { + "strip": 1, + }, + ], + ], } `); }); diff --git a/src/dev/build/tasks/nodejs/extract_node_builds_task.ts b/src/dev/build/tasks/nodejs/extract_node_builds_task.ts index 8e915a8b4e4b..8252ce2153f5 100644 --- a/src/dev/build/tasks/nodejs/extract_node_builds_task.ts +++ b/src/dev/build/tasks/nodejs/extract_node_builds_task.ts @@ -28,9 +28,7 @@ * under the License. */ -import Path from 'path'; - -import { untar, GlobalTask, copy } from '../../lib'; +import { untar, unzip, GlobalTask } from '../../lib'; import { getNodeDownloadInfo } from './node_download_info'; export const ExtractNodeBuilds: GlobalTask = { @@ -41,10 +39,7 @@ export const ExtractNodeBuilds: GlobalTask = { config.getTargetPlatforms().map(async (platform) => { const { downloadPath, extractDir } = getNodeDownloadInfo(config, platform); if (platform.isWindows()) { - // windows executable is not extractable, it's just an .exe file - await copy(downloadPath, Path.resolve(extractDir, 'node.exe'), { - clone: true, - }); + await unzip(downloadPath, extractDir, { strip: 1 }); } else { await untar(downloadPath, extractDir, { strip: 1 }); } diff --git a/src/dev/build/tasks/nodejs/node_download_info.ts b/src/dev/build/tasks/nodejs/node_download_info.ts index 5b9006e89f70..86e0c680ab0d 100644 --- a/src/dev/build/tasks/nodejs/node_download_info.ts +++ b/src/dev/build/tasks/nodejs/node_download_info.ts @@ -37,7 +37,7 @@ export function getNodeDownloadInfo(config: Config, platform: Platform) { const arch = platform.getNodeArch(); const downloadName = platform.isWindows() - ? 'win-x64/node.exe' + ? `node-v${version}-win-x64.zip` : `node-v${version}-${arch}.tar.gz`; const url = `https://nodejs.org/dist/v${version}/${downloadName}`; diff --git a/src/plugins/data_source_management/public/components/create_button/create_button.test.tsx b/src/plugins/data_source_management/public/components/create_button/create_button.test.tsx index 64906045b004..f54aef129df3 100644 --- a/src/plugins/data_source_management/public/components/create_button/create_button.test.tsx +++ b/src/plugins/data_source_management/public/components/create_button/create_button.test.tsx @@ -13,10 +13,11 @@ const createButtonIdentifier = `[data-test-subj="createDataSourceButton"]`; describe('CreateButton', () => { const history = (scopedHistoryMock.create() as unknown) as ScopedHistory; + const dataTestSubj = 'createDataSourceButton'; let component: ShallowWrapper, React.Component<{}, {}, any>>; beforeEach(() => { - component = shallow(); + component = shallow(); }); it('should render normally', () => { diff --git a/src/plugins/data_source_management/public/components/create_button/create_button.tsx b/src/plugins/data_source_management/public/components/create_button/create_button.tsx index 072eb8af6029..7c893af0209d 100644 --- a/src/plugins/data_source_management/public/components/create_button/create_button.tsx +++ b/src/plugins/data_source_management/public/components/create_button/create_button.tsx @@ -11,13 +11,15 @@ import { FormattedMessage } from '@osd/i18n/react'; interface Props { history: History; + isEmptyState?: boolean; + dataTestSubj: string; } -export const CreateButton = ({ history }: Props) => { +export const CreateButton = ({ history, isEmptyState, dataTestSubj }: Props) => { return ( history.push('/create')} > + +
+ @@ -401,7 +408,7 @@ exports[`Datasource Management: Create Datasource Wizard case1: should load reso onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - placeholder="Sample URL: https://connectionurl.com" + placeholder="https://connectionurl.com" value="" > @@ -1079,6 +1086,13 @@ exports[`Datasource Management: Create Datasource Wizard case2: should fail to l
+ +
+ @@ -1368,7 +1382,7 @@ exports[`Datasource Management: Create Datasource Wizard case2: should fail to l onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - placeholder="Sample URL: https://connectionurl.com" + placeholder="https://connectionurl.com" value="" > diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap index 1006968b632f..fcd197cc0827 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/__snapshots__/create_data_source_form.test.tsx.snap @@ -140,6 +140,13 @@ exports[`Datasource Management: Create Datasource form should create data source
+ +
+ @@ -429,7 +436,7 @@ exports[`Datasource Management: Create Datasource form should create data source onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - placeholder="Sample URL: https://connectionurl.com" + placeholder="https://connectionurl.com" value="https://test.com" > @@ -867,6 +874,13 @@ exports[`Datasource Management: Create Datasource form should create data source
+ +
+ @@ -1156,7 +1170,7 @@ exports[`Datasource Management: Create Datasource form should create data source onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - placeholder="Sample URL: https://connectionurl.com" + placeholder="https://connectionurl.com" value="https://test.com" > @@ -1792,6 +1806,13 @@ exports[`Datasource Management: Create Datasource form should render normally 1`
+ +
+ @@ -2081,7 +2102,7 @@ exports[`Datasource Management: Create Datasource form should render normally 1` onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - placeholder="Sample URL: https://connectionurl.com" + placeholder="https://connectionurl.com" value="" > @@ -2717,6 +2738,13 @@ exports[`Datasource Management: Create Datasource form should throw validation e
+ +
+ @@ -3023,7 +3051,7 @@ exports[`Datasource Management: Create Datasource form should throw validation e onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - placeholder="Sample URL: https://connectionurl.com" + placeholder="https://connectionurl.com" value="https://test.com" > diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx index e5d779296a58..429790231a5c 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/create_form/create_data_source_form.tsx @@ -287,6 +287,7 @@ export class CreateDataSourceForm extends React.Component< return ( {this.renderHeader()} + {/* Endpoint section */} {this.renderSectionHeader( @@ -354,7 +355,7 @@ export class CreateDataSourceForm extends React.Component< placeholder={i18n.translate( 'dataSourcesManagement.createDataSource.endpointPlaceholder', { - defaultMessage: 'Sample URL: https://connectionurl.com', + defaultMessage: 'https://connectionurl.com', } )} isInvalid={!!this.state.formErrorsByField.endpoint.length} diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx index aaa50435d5e3..08ac198c7561 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx @@ -75,7 +75,7 @@ export const CreateDataSourceWizard: React.FunctionComponent { - toasts.addWarning(i18n.translate(id, { defaultMessage })); + toasts.addDanger(i18n.translate(id, { defaultMessage })); }; /* Render the creation wizard */ diff --git a/src/plugins/data_source_management/public/components/data_source_column/data_source_column.tsx b/src/plugins/data_source_management/public/components/data_source_column/data_source_column.tsx index 6ac2258b7811..640eb1b369fd 100644 --- a/src/plugins/data_source_management/public/components/data_source_column/data_source_column.tsx +++ b/src/plugins/data_source_management/public/components/data_source_column/data_source_column.tsx @@ -24,7 +24,7 @@ export class DataSourceColumn implements IndexPatternTableColumn public euiColumn = { field: 'referenceId', name: i18n.translate('dataSource.management.dataSourceColumn', { - defaultMessage: 'Data Source', + defaultMessage: 'Data Source Connection', }), render: (referenceId: string, index: IndexPatternTableRecord) => { if (!referenceId) { diff --git a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap index abd6fc95c88d..53e2fac37130 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap @@ -108,6 +108,7 @@ exports[`DataSourceTable should get datasources failed should render empty table className="euiFlexItem euiFlexItem--flexGrowZero" >