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

Skip embedded Node.js runtime deployment if sonar.nodejs.executable is set #4616

Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import javax.annotation.Nullable;
import org.sonar.api.SonarProduct;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
Expand Down Expand Up @@ -162,9 +163,9 @@ int getTimeoutSeconds() {
*
* @throws IOException
*/
void deploy() throws IOException {
void deploy(Configuration configuration) throws IOException {
bundle.deploy(temporaryDeployLocation);
embeddedNode.deploy();
embeddedNode.deploy(configuration);
ilia-kebets-sonarsource marked this conversation as resolved.
Show resolved Hide resolved
}

void startServer(SensorContext context, List<Path> deployedBundles) throws IOException {
Expand Down Expand Up @@ -285,7 +286,7 @@ public void startServerLazily(SensorContext context) throws IOException {
status = Status.FAILED;
throw new ServerAlreadyFailedException();
}
deploy();
deploy(context.config());
List<Path> deployedBundles = rulesBundles.deploy(temporaryDeployLocation.resolve("package"));
rulesBundles
.getUcfgRulesBundle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
import static org.sonar.plugins.javascript.bridge.EmbeddedNode.Platform.UNSUPPORTED;
import static org.sonar.plugins.javascript.nodejs.NodeCommandBuilderImpl.NODE_EXECUTABLE_PROPERTY;
import static org.sonarsource.api.sonarlint.SonarLintSide.INSTANCE;

import java.io.BufferedInputStream;
Expand All @@ -35,6 +36,8 @@
import java.nio.file.Path;
import java.util.Locale;
import java.util.Set;
import javax.annotation.Nullable;
import org.sonar.api.config.Configuration;
ilia-kebets-sonarsource marked this conversation as resolved.
Show resolved Hide resolved
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
Expand Down Expand Up @@ -159,7 +162,7 @@ public boolean isAvailable() {
*
* @throws IOException
*/
public void deploy() throws IOException {
public void deploy(@Nullable Configuration configuration) throws IOException {
LOG.info(
"Detected os: {} arch: {} alpine: {}. Platform: {}",
env.getOsName(),
Expand All @@ -170,6 +173,14 @@ public void deploy() throws IOException {
if (platform == UNSUPPORTED) {
return;
}
if (isNodejsExecutableSet(configuration)) {
LOG.info(
"'{}' is set. Skipping embedded Node.js runtime deployment.",
NODE_EXECUTABLE_PROPERTY
);
return;
}

ilia-kebets-sonarsource marked this conversation as resolved.
Show resolved Hide resolved
try {
var is = getClass().getResourceAsStream(platform.archivePathInJar());
if (is == null) {
Expand Down Expand Up @@ -197,6 +208,13 @@ public void deploy() throws IOException {
}
}

private static boolean isNodejsExecutableSet(@Nullable Configuration configuration) {
if (configuration == null) {
return false;
}
return configuration.get(NODE_EXECUTABLE_PROPERTY).isPresent();
}

private static boolean isDifferent(InputStream newVersionIs, Path currentVersionPath)
throws IOException {
var newVersionString = new String(newVersionIs.readAllBytes(), StandardCharsets.UTF_8);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class NodeCommandBuilderImpl implements NodeCommandBuilder {
private static final String NODE_EXECUTABLE_DEFAULT_MACOS =
"package/node_modules/run-node/run-node";

private static final String NODE_EXECUTABLE_PROPERTY = "sonar.nodejs.executable";
public static final String NODE_EXECUTABLE_PROPERTY = "sonar.nodejs.executable";
private static final String NODE_FORCE_HOST_PROPERTY = "sonar.nodejs.forceHost";

private static final Pattern NODEJS_VERSION_PATTERN = Pattern.compile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void tearDown() {
@Test
void should_throw_when_not_existing_script() throws Exception {
bridgeServer = createBridgeServer("NOT_EXISTING.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
ilia-kebets-sonarsource marked this conversation as resolved.
Show resolved Hide resolved
List<Path> deployedBundles = emptyList();

assertThatThrownBy(() -> bridgeServer.startServer(context, deployedBundles))
Expand Down Expand Up @@ -157,7 +157,7 @@ void should_throw_if_failed_to_build_node_command() throws Exception {
tempFolder,
unsupportedEmbeddedRuntime
);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
List<Path> deployedBundles = emptyList();

assertThatThrownBy(() -> bridgeServer.startServer(context, deployedBundles))
Expand All @@ -168,7 +168,7 @@ void should_throw_if_failed_to_build_node_command() throws Exception {
@Test
void should_forward_process_streams() throws Exception {
bridgeServer = createBridgeServer("logging.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

assertThat(logTester.logs(DEBUG)).contains("testing debug log");
Expand All @@ -180,7 +180,7 @@ void should_forward_process_streams() throws Exception {
@Test
void should_get_answer_from_server() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

DefaultInputFile inputFile = TestInputFileBuilder
Expand All @@ -194,7 +194,7 @@ void should_get_answer_from_server() throws Exception {
@Test
void test_init() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

List<EslintRule> rules = Collections.singletonList(
Expand Down Expand Up @@ -223,7 +223,7 @@ void test_init() throws Exception {
@Test
void should_get_answer_from_server_for_ts_request() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

DefaultInputFile inputFile = TestInputFileBuilder
Expand All @@ -250,7 +250,7 @@ void should_get_answer_from_server_for_ts_request() throws Exception {
@Test
void should_get_answer_from_server_for_yaml_request() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

DefaultInputFile inputFile = TestInputFileBuilder
Expand Down Expand Up @@ -278,7 +278,7 @@ private static JsAnalysisRequest createRequest(DefaultInputFile inputFile) {
@Test
void should_get_answer_from_server_for_program_based_requests() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

TsProgram programCreated = bridgeServer.createProgram(
Expand Down Expand Up @@ -308,7 +308,7 @@ void should_get_answer_from_server_for_program_based_requests() throws Exception
@Test
void should_create_tsconfig_files() throws IOException {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

var tsConfig = bridgeServer.createTsConfigFile("{\"include\":[\"/path/to/project/**/*\"]}");
Expand All @@ -318,7 +318,7 @@ void should_create_tsconfig_files() throws IOException {
@Test
void should_not_fail_when_error_during_create_program() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

TsProgram programCreated = bridgeServer.createProgram(
Expand All @@ -332,7 +332,7 @@ void should_not_fail_when_error_during_create_program() throws Exception {
@Test
void should_get_answer_from_server_for_css_request() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

DefaultInputFile inputFile = TestInputFileBuilder
Expand All @@ -350,7 +350,7 @@ void should_get_answer_from_server_for_css_request() throws Exception {
@Test
void should_throw_if_failed_to_start() throws Exception {
bridgeServer = createBridgeServer("throw.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
List<Path> deployedBundles = emptyList();

assertThatThrownBy(() -> bridgeServer.startServer(context, deployedBundles))
Expand All @@ -364,7 +364,7 @@ void should_return_command_info() throws Exception {
assertThat(bridgeServer.getCommandInfo())
.isEqualTo("Node.js command to start the bridge server was not built yet.");

bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

assertThat(bridgeServer.getCommandInfo())
Expand All @@ -378,7 +378,7 @@ void should_set_max_old_space_size() throws Exception {
assertThat(bridgeServer.getCommandInfo())
.isEqualTo("Node.js command to start the bridge server was not built yet.");

bridgeServer.deploy();
bridgeServer.deploy(context.config());
context.setSettings(new MapSettings().setProperty("sonar.javascript.node.maxspace", 2048));
bridgeServer.startServer(context, emptyList());

Expand All @@ -388,7 +388,7 @@ void should_set_max_old_space_size() throws Exception {
@Test
void should_set_allowTsParserJsFiles_to_false() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
context.setSettings(
new MapSettings().setProperty("sonar.javascript.allowTsParserJsFiles", "false")
);
Expand All @@ -401,7 +401,7 @@ void should_set_allowTsParserJsFiles_to_false() throws Exception {
@Test
void allowTsParserJsFiles_default_value_is_true() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());
bridgeServer.stop();

Expand Down Expand Up @@ -510,7 +510,7 @@ void should_throw_if_server_not_alive() throws Exception {
@Test
void should_fail_if_bad_json_response() throws Exception {
bridgeServer = createBridgeServer("badResponse.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServerLazily(context);

DefaultInputFile inputFile = TestInputFileBuilder
Expand All @@ -535,7 +535,7 @@ void should_fail_if_bad_json_response() throws Exception {
@Test
void should_not_search_typescript_when_no_ts_file() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
SensorContextTester ctx = SensorContextTester.create(moduleBase);
ctx.fileSystem().setWorkDir(workDir);
Path tsDir = moduleBase.resolve("dir/node_modules/typescript");
Expand All @@ -547,15 +547,15 @@ void should_not_search_typescript_when_no_ts_file() throws Exception {
@Test
void should_reload_tsconfig() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());
assertThat(bridgeServer.newTsConfig()).isTrue();
}

@Test
void should_return_files_for_tsconfig() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());
String tsconfig = "path/to/tsconfig.json";
BridgeServerImpl.TsConfigResponse tsConfigResponse = bridgeServer.tsConfigFiles(tsconfig);
Expand All @@ -571,7 +571,7 @@ void should_return_files_for_tsconfig() throws Exception {
@Test
void should_return_no_files_for_tsconfig_bad_response() throws Exception {
bridgeServer = createBridgeServer("badResponse.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());
BridgeServerImpl.TsConfigResponse response = bridgeServer.tsConfigFiles(
"path/to/tsconfig.json"
Expand All @@ -583,7 +583,7 @@ void should_return_no_files_for_tsconfig_bad_response() throws Exception {
@Test
void should_return_no_files_for_tsconfig_no_response() throws Exception {
bridgeServer = createBridgeServer("badResponse.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());
assertThat(bridgeServer.tsConfigFiles("path/to/tsconfig.json").files).isEmpty();
TsConfigFile tsConfigFile = bridgeServer.loadTsConfig("path/to/tsconfig.json");
Expand All @@ -593,7 +593,7 @@ void should_return_no_files_for_tsconfig_no_response() throws Exception {
@Test
void should_return_no_files_for_tsconfig_on_error() throws Exception {
bridgeServer = createBridgeServer("tsConfigError.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

TsConfigFile tsConfigFile = bridgeServer.loadTsConfig("path/to/tsconfig.json");
Expand All @@ -604,7 +604,7 @@ void should_return_no_files_for_tsconfig_on_error() throws Exception {
@Test
void log_error_when_timeout() throws Exception {
bridgeServer = createBridgeServer("timeout.js");
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, emptyList());

assertThatThrownBy(() -> bridgeServer.loadTsConfig("any.ts"))
Expand All @@ -626,7 +626,7 @@ void test_rule_tostring() {
@Test
void should_load_custom_rules() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServer(context, Arrays.asList(Paths.get("bundle1"), Paths.get("bundle2")));
bridgeServer.stop();

Expand All @@ -637,7 +637,7 @@ void should_load_custom_rules() throws Exception {
@Test
void should_skip_metrics_on_sonarlint() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
context.setRuntime(SonarRuntimeImpl.forSonarLint(Version.create(7, 9)));
bridgeServer.startServer(context, Arrays.asList(Paths.get("bundle1"), Paths.get("bundle2")));
bridgeServer.stop();
Expand All @@ -648,7 +648,7 @@ void should_skip_metrics_on_sonarlint() throws Exception {
@Test
void should_pass_debug_memory_option() throws Exception {
bridgeServer = createBridgeServer(START_SERVER_SCRIPT);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
context.setSettings(new MapSettings().setProperty("sonar.javascript.node.debugMemory", "true"));
bridgeServer.startServer(context, Arrays.asList(Paths.get("bundle1"), Paths.get("bundle2")));
bridgeServer.stop();
Expand Down Expand Up @@ -715,7 +715,7 @@ void enabled_monitoring() throws Exception {
tempFolder,
unsupportedEmbeddedRuntime
);
bridgeServer.deploy();
bridgeServer.deploy(context.config());
bridgeServer.startServerLazily(context);
bridgeServer.stop();
assertThat(logTester.logs(INFO).stream().anyMatch(s -> s.startsWith("no-commented-code")))
Expand Down
Loading
Loading