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

[MMF-2861] Embed Node.js runtime in analyzer #4150

Merged
merged 60 commits into from Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
e12532d
Fetch node script - wip
saberduck Aug 28, 2023
e6933d0
Fetch all distros and support custom target directory
ilia-kebets-sonarsource Aug 28, 2023
39fa959
cleanup
ilia-kebets-sonarsource Aug 28, 2023
617eeb9
cleanup
ilia-kebets-sonarsource Aug 28, 2023
222228d
Make destination folders stable
ilia-kebets-sonarsource Aug 28, 2023
9f4b3f7
use tar gz archives (instead of tar xz) because of lack of support fo…
ilia-kebets-sonarsource Aug 29, 2023
d3cda69
remove dep
ilia-kebets-sonarsource Aug 29, 2023
51f34b4
run script in CI
ilia-kebets-sonarsource Aug 30, 2023
a638214
fix commands order
ilia-kebets-sonarsource Aug 30, 2023
1564743
typo
ilia-kebets-sonarsource Aug 30, 2023
31c7196
fix path: we can use slashes since it's a URL
ilia-kebets-sonarsource Aug 30, 2023
694f52e
don't use array.at() since we're running old nodejs
ilia-kebets-sonarsource Aug 30, 2023
e09a9e2
skip download if file exists, and fix some logs
ilia-kebets-sonarsource Aug 30, 2023
52c02fa
modularize node version
ilia-kebets-sonarsource Aug 30, 2023
0fb87d9
filter out symlink failing on windows and apply prettier
ilia-kebets-sonarsource Aug 30, 2023
3277274
cleanup
ilia-kebets-sonarsource Aug 30, 2023
8245ce8
fix dependency versions
ilia-kebets-sonarsource Aug 30, 2023
69b5cfe
simplify implementation
ilia-kebets-sonarsource Aug 30, 2023
555c2e5
increase max JAR size to 160MB
ilia-kebets-sonarsource Aug 31, 2023
bf5c499
Merge branch 'master' into issue-4116
ilia-kebets-sonarsource Sep 4, 2023
8f801a8
Bunde node: compression (#4126)
ilia-kebets-sonarsource Sep 7, 2023
f4c16d0
Remove musl support (#4151)
saberduck Sep 8, 2023
9f93c74
Implement tests for tooling and use cache for runtime downloads (#4153)
ilia-kebets-sonarsource Sep 12, 2023
8fec5e0
Validate shasum's of downloaded Node.js runtimes (#4159)
ilia-kebets-sonarsource Sep 13, 2023
e4d4a91
Cache node runtimes downloads in CI and download from artifactory if …
ilia-kebets-sonarsource Sep 13, 2023
a896234
Build artifacts (#4162)
saberduck Sep 13, 2023
5d77408
Implement authentication to download runtimes from Artifactory (#4164)
ilia-kebets-sonarsource Sep 13, 2023
6b433df
Remove log when decompressing (#4170)
saberduck Sep 14, 2023
b9f4dfb
Use embedded node in ITs (#4167)
saberduck Sep 15, 2023
53d0f42
Remove runtime copies from resources and cleanup CI cache usage (#4168)
ilia-kebets-sonarsource Sep 18, 2023
8b28a90
Cache extracted runtime (#4179)
ilia-kebets-sonarsource Sep 20, 2023
4cfcc82
Merge remote-tracking branch 'origin/master' into feature/bundle-node…
saberduck Sep 20, 2023
668ccbd
Use embedded node in ruling and QA (#4180)
saberduck Sep 20, 2023
ded2b14
generate lockfile using node14
ilia-kebets-sonarsource Sep 20, 2023
c0917ba
generate lockfile using node16
ilia-kebets-sonarsource Sep 20, 2023
814732f
Fix runtime cache racing condition (#4184)
ilia-kebets-sonarsource Sep 20, 2023
ab29cc8
Improve coverage & fix code smells (#4188)
saberduck Sep 21, 2023
f50b267
Moare coverage!
saberduck Sep 21, 2023
051f31d
Remove codesmells
saberduck Sep 21, 2023
d20d3fc
Remove codesmells
saberduck Sep 21, 2023
43e66b3
remove debug logs
ilia-kebets-sonarsource Sep 21, 2023
612656d
put back check-format
ilia-kebets-sonarsource Sep 21, 2023
b6929d6
cleanup
ilia-kebets-sonarsource Sep 21, 2023
2fd5e44
Assert artifact sizes
saberduck Sep 21, 2023
ec1be85
Add ignore for prettier
saberduck Sep 21, 2023
74442d6
Run fetch-node as part of `build-full` instead of `build`
saberduck Sep 21, 2023
da8e954
rename mock function and document its usage
ilia-kebets-sonarsource Sep 21, 2023
65772bd
remove unused logTester
ilia-kebets-sonarsource Sep 21, 2023
4fb90a4
cleanup test file
ilia-kebets-sonarsource Sep 21, 2023
38ce2a1
Merge branch 'feature/bundle-node-runtime-in-analyzer' of github.com:…
ilia-kebets-sonarsource Sep 21, 2023
06d19ed
cleanup NodeCommand test
ilia-kebets-sonarsource Sep 21, 2023
5b72145
improve copy-to-plugin docs
ilia-kebets-sonarsource Sep 21, 2023
a69f60f
fix comment
ilia-kebets-sonarsource Sep 21, 2023
7c7bd86
fetch-node needs to be part of `build-plugin`
saberduck Sep 21, 2023
00d5d35
Revert "cleanup NodeCommand test"
ilia-kebets-sonarsource Sep 21, 2023
904cd8b
update JAR size limits
ilia-kebets-sonarsource Sep 21, 2023
d8f964c
dirty - add fetch-node before `mvn test`
ilia-kebets-sonarsource Sep 21, 2023
4554b5b
stub commit to trigger that promote check
ilia-kebets-sonarsource Sep 21, 2023
ab89722
Merge branch 'master' into feature/bundle-node-runtime-in-analyzer
ilia-kebets-sonarsource Sep 21, 2023
6755511
Fix promote task
saberduck Sep 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 36 additions & 19 deletions .cirrus.yml
Expand Up @@ -20,9 +20,6 @@
CIRRUS_SHELL: bash

container_definition: &CONTAINER_DEFINITION
dockerfile: .cirrus/nodejs.Dockerfile
docker_arguments:
CIRRUS_AWS_ACCOUNT: ${CIRRUS_AWS_ACCOUNT}
cluster_name: ${CIRRUS_CLUSTER_NAME}
builder_role: cirrus-builder
builder_image: docker-builder-v*
Expand All @@ -37,13 +34,18 @@
folder: ${CIRRUS_WORKING_DIR}/.m2/repository
fingerprint_script: cat **/pom.xml

nodejs_runtimes_cache_definition: &RUNTIME_CACHE
runtime_cache:
folder: tools/fetch-node/downloads/
fingerprint_script: cat tools/fetch-node/node-distros.mjs

win_vm_definition: &WINDOWS_VM_DEFINITION
ec2_instance:
experimental: true # see https://github.com/cirruslabs/cirrus-ci-docs/issues/1051
image: base-windows-jdk17-v*
platform: windows
region: eu-central-1
type: c6id.2xlarge
type: c6i.4xlarge
subnet_id: ${CIRRUS_AWS_SUBNET}
preemptible: false
use_ssd: true
Expand All @@ -63,17 +65,18 @@
CIRRUS_CLONE_DEPTH: 10
SONARSOURCE_QA: true
<<: *MAVEN_CACHE
node_version_script:
- node -v
qa_script:
- source cirrus-env QA
- source set_maven_build_version $BUILD_NUMBER
- mvn -f its/plugin/pom.xml -Dsonar.runtimeVersion=${SQ_VERSION} -B -e -V verify surefire-report:report
- mvn -f its/plugin/pom.xml -Dsonar.runtimeVersion=${SQ_VERSION} ${MVN_TEST} -B -e -V verify surefire-report:report
cleanup_before_cache_script: cleanup_maven_repository

build_task:
eks_container:
<<: *CONTAINER_DEFINITION
dockerfile: .cirrus/nodejs.Dockerfile
docker_arguments:
CIRRUS_AWS_ACCOUNT: ${CIRRUS_AWS_ACCOUNT}
cpu: 15
memory: 30G
env:
Expand All @@ -86,6 +89,7 @@
SIGN_KEY: VAULT[development/kv/data/sign data.key]
PGP_PASSPHRASE: VAULT[development/kv/data/sign data.passphrase]
<<: *MAVEN_CACHE
<<: *RUNTIME_CACHE
sonar_cache:
folder: ${HOME}/.sonar/cache
fingerprint_script:
Expand All @@ -104,9 +108,12 @@
<<: *WINDOWS_VM_DEFINITION
<<: *ONLY_SONARSOURCE_QA
<<: *MAVEN_CACHE
<<: *RUNTIME_CACHE
build_script:
- source cirrus-env CI
- npm config set registry "${ARTIFACTORY_URL}/api/npm/npm"
# TODO should be as close to build_task as possible, ie. remove incompatible bash scripts
- npm run build && npm run test
- mvn test
cleanup_before_cache_script: cleanup_maven_repository

Expand All @@ -115,6 +122,9 @@
- build
eks_container:
<<: *CONTAINER_DEFINITION
dockerfile: .cirrus/nodejs.Dockerfile
docker_arguments:
CIRRUS_AWS_ACCOUNT: ${CIRRUS_AWS_ACCOUNT}
cpu: 4
memory: 8G
# run only on master and long-term branches
Expand All @@ -133,25 +143,31 @@
ws_artifacts:
path: 'whitesource/**/*'

plugin_qa_task:
plugin_qa_with_node_task:
<<: *PLUGIN_QA_BODY
eks_container:
dockerfile: .cirrus/nodejs.jdk17.Dockerfile
docker_arguments:
matrix:
- NODE_VERSION: 14
- NODE_VERSION: 16
- NODE_VERSION: 18
- NODE_VERSION: 20
env:
SQ_VERSION: LATEST_RELEASE
MVN_TEST: ''

plugin_qa_no_node_task:
<<: *PLUGIN_QA_BODY
eks_container:
image: ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j17-latest
env:
SQ_VERSION: LATEST_RELEASE
SONARJS_ARTIFACT: multi
MVN_TEST: '-Dtest=!EslintCustomRulesTest,!SonarJsIntegrationTest --projects !org.sonarsource.javascript:eslint-custom-rules-plugin'

plugin_qa_sq_dev_task:
<<: *PLUGIN_QA_BODY
eks_container:
dockerfile: .cirrus/nodejs.jdk17.Dockerfile
image: ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j17-latest
env:
SQ_VERSION: DEV
SONARJS_ARTIFACT: multi
MVN_TEST: '-Dtest=!EslintCustomRulesTest,!SonarJsIntegrationTest --projects !org.sonarsource.javascript:eslint-custom-rules-plugin'

# Plugin QA for Windows is splint into 2 parts to make it faster
plugin_qa_win_task:
Expand Down Expand Up @@ -180,7 +196,7 @@
<<: *ONLY_SONARSOURCE_QA
eks_container:
<<: *CONTAINER_DEFINITION
dockerfile: .cirrus/nodejs.jdk17.Dockerfile
image: ${CIRRUS_AWS_ACCOUNT}.dkr.ecr.eu-central-1.amazonaws.com/base:j17-latest
cpu: 15
memory: 24G
env:
Expand All @@ -203,19 +219,20 @@
diff_artifacts:
path: '**/target/actual/**/*'

promote_task:

Check warning on line 222 in .cirrus.yml

View check run for this annotation

Cirrus CI / Build Parsing Results

.cirrus.yml#L222

task "promote" depends on task "ws_scan", but their only_if conditions are different
depends_on:
- ws_scan
- build_win
- plugin_qa
- plugin_qa_with_node
- plugin_qa_no_node
- plugin_qa_sq_dev
- plugin_qa_win
- ruling
<<: *ONLY_SONARSOURCE_QA
eks_container:
<<: *CONTAINER_DEFINITION
cpu: 1
memory: 1G
cpu: 2
memory: 4G
env:
#promotion cloud function
GCF_ACCESS_TOKEN: VAULT[development/kv/data/promote data.token]
Expand Down
2 changes: 2 additions & 0 deletions .prettierignore
Expand Up @@ -30,3 +30,5 @@ sonar-plugin/sonar-javascript-plugin/src/test/resources

typedoc/site
typedoc/models

tools/fetch-node/downloads
1 change: 1 addition & 0 deletions its/plugin/sonarlint-tests/pom.xml
Expand Up @@ -88,6 +88,7 @@
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-javascript-plugin</artifactId>
<classifier>multi</classifier>
<type>sonar-plugin</type>
<overWrite>true</overWrite>
</artifactItem>
Expand Down
22 changes: 14 additions & 8 deletions its/plugin/sonarlint-tests/src/test/java/SonarLintTest.java
Expand Up @@ -103,14 +103,20 @@ void should_raise_issues() throws IOException {
tuple("javascript:S3504", 4, filePath, "CRITICAL")
);

assertThat(
logs
.stream()
.anyMatch(s ->
s.matches("Using Node\\.js executable .* from property sonar\\.nodejs\\.executable\\.")
)
)
.isTrue();
if (!usingEmbeddedNode()) {
assertThat(
logs
.stream()
.anyMatch(s ->
s.matches("Using Node\\.js executable .* from property sonar\\.nodejs\\.executable\\.")
)
)
.isTrue();
}
}

private static boolean usingEmbeddedNode() {
return TestUtils.JAVASCRIPT_PLUGIN_LOCATION.toString().contains("multi");
}

@Test
Expand Down
35 changes: 21 additions & 14 deletions its/plugin/sonarlint-tests/src/test/java/TestUtils.java
Expand Up @@ -30,28 +30,35 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.regex.Pattern;
import org.sonarsource.sonarlint.core.analysis.api.ClientInputFile;

public class TestUtils {

static final Path JAVASCRIPT_PLUGIN_LOCATION;

static {
var start = homeDir().resolve("../sonar-plugin/sonar-javascript-plugin/target");
try (var walk = Files.walk(start)) {
JAVASCRIPT_PLUGIN_LOCATION =
walk
.filter(p -> {
var filename = p.getFileName().toString();
return filename.startsWith("sonar-javascript-plugin-") && filename.endsWith(".jar");
})
.findAny()
.orElseThrow();
static final Path JAVASCRIPT_PLUGIN_LOCATION = artifact();

/**
* This is used to test artifact with and without embedded runtime during plugin QA integration tests
*
*/
private static Path artifact() {
var target = homeDir().resolve("../sonar-plugin/sonar-javascript-plugin/target");
try (var stream = Files.walk(target, 1)) {
return stream
.filter(p -> pluginFilenameMatcher().matcher(p.getFileName().toString()).matches())
.findAny()
.orElseThrow();
} catch (IOException e) {
throw new IllegalStateException(e);
throw new UncheckedIOException(e);
}
}

private static Pattern pluginFilenameMatcher() {
return "multi".equals(System.getenv("SONARJS_ARTIFACT"))
? Pattern.compile("sonar-javascript-plugin-.*-multi\\.jar")
: Pattern.compile("sonar-javascript-plugin-[0-9.]*(?:-SNAPSHOT)?\\.jar");
}

public static Path homeDir() {
return Path.of("../../");
}
Expand Down
21 changes: 21 additions & 0 deletions its/plugin/tests/pom.xml
Expand Up @@ -109,6 +109,27 @@
<type>sonar-plugin</type>
<overWrite>true</overWrite>
</artifactItem>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-javascript-plugin</artifactId>
<classifier>win-x64</classifier>
<type>sonar-plugin</type>
<overWrite>true</overWrite>
</artifactItem>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-javascript-plugin</artifactId>
<classifier>linux-x64</classifier>
<type>sonar-plugin</type>
<overWrite>true</overWrite>
</artifactItem>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-javascript-plugin</artifactId>
<classifier>multi</classifier>
<type>sonar-plugin</type>
<overWrite>true</overWrite>
</artifactItem>
</artifactItems>
<outputDirectory>../../../sonar-plugin/sonar-javascript-plugin/target</outputDirectory>
<overWriteReleases>true</overWriteReleases>
Expand Down
@@ -0,0 +1,84 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2012-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.sonar.javascript.it.plugin;

import static com.sonar.javascript.it.plugin.OrchestratorStarter.getSonarScanner;
import static org.assertj.core.api.Assertions.assertThat;

import com.sonar.orchestrator.junit5.OrchestratorExtension;
import com.sonar.orchestrator.locator.FileLocation;
import java.io.File;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;

@Isolated
class EmbeddedNodeTest {

@Test
void embedded_node() {
var plugin = FileLocation.byWildcardMavenFilename(
new File("../../../sonar-plugin/sonar-javascript-plugin/target"),
"sonar-javascript-plugin-*" + classifier() + ".jar"
);

var orchestrator = OrchestratorExtension
.builderEnv()
.useDefaultAdminCredentialsForBuilds(true)
.setSonarVersion(System.getProperty("sonar.runtimeVersion", "LATEST_RELEASE"))
.restoreProfileAtStartup(FileLocation.ofClasspath("/eslint-based-rules.xml"))
.addPlugin(plugin)
.build();

synchronized (OrchestratorStarter.class) {
orchestrator.start();
}

var projectKey = "eslint_based_rules";
var server = orchestrator.getServer();
server.provisionProject(projectKey, projectKey);
server.associateProjectToQualityProfile(projectKey, "js", "eslint-based-rules-profile");

var projectDir = TestUtils.projectDir(projectKey);
var build = getSonarScanner()
.setProjectKey(projectKey)
.setSourceEncoding("UTF-8")
.setSourceDirs(".")
.setProjectDir(projectDir);

var buildResult = orchestrator.executeBuild(build);
assertThat(buildResult.isSuccess()).isTrue();
assertThat(buildResult.getLogs()).contains("INFO: Using embedded Node.js runtime");
assertThat(buildResult.getLogsLines(l -> l.startsWith("ERROR"))).isEmpty();
orchestrator.stop();
}

private static String classifier() {
var os = System.getProperty("os.name").toLowerCase(Locale.ROOT);
var arch = System.getProperty("os.arch");
if (os.contains("linux") && arch.contains("64")) {
return "-linux-x64";
} else if (os.contains("windows")) {
return "-win-x64";
} else {
return "-multi";
}
}
}
Expand Up @@ -164,6 +164,7 @@ void should_not_use_node_in_cwd() throws Exception {
.setSourceEncoding("UTF-8")
.setSourceDirs(".")
.setDebugLogs(true)
.setProperty("sonar.nodejs.forceHost", "true")
.setProjectDir(projectDir);

// copy ping.exe to node.exe and place it in the project directory
Expand Down