mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
IJI-1455 reporting build steps of distribution build test as TeamCity tests
GitOrigin-RevId: a7837fe388570ae8be635dd57ed1fe182441c3cf
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ecce5f78de
commit
fe99f89930
@@ -25,7 +25,9 @@ abstract class BuildMessageLoggerBase : BuildMessageLogger() {
|
|||||||
val errorsString = (message as CompilationErrorsLogMessage).errorMessages.joinToString(separator = "\n")
|
val errorsString = (message as CompilationErrorsLogMessage).errorMessages.joinToString(separator = "\n")
|
||||||
Span.current().addEvent("compilation errors (${message.compilerName}):\n$errorsString")
|
Span.current().addEvent("compilation errors (${message.compilerName}):\n$errorsString")
|
||||||
}
|
}
|
||||||
LogMessage.Kind.BUILD_CANCEL -> throw BuildScriptsLoggedError(message.text)
|
LogMessage.Kind.BUILD_CANCEL, LogMessage.Kind.BUILD_PROBLEM -> {
|
||||||
|
throw BuildScriptsLoggedError(message.text)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if (shouldBePrinted(message.kind)) {
|
if (shouldBePrinted(message.kind)) {
|
||||||
Span.current().addEvent(message.text)
|
Span.current().addEvent(message.text)
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class TeamCityBuildMessageLogger : BuildMessageLogger() {
|
|||||||
print(ServiceMessageTypes.COMPILATION_FINISHED, "compiler" to compiler)
|
print(ServiceMessageTypes.COMPILATION_FINISHED, "compiler" to compiler)
|
||||||
}
|
}
|
||||||
DEBUG -> {} //debug messages are printed to a separate file available in the build artifacts
|
DEBUG -> {} //debug messages are printed to a separate file available in the build artifacts
|
||||||
BUILD_PROBLEM -> {
|
BUILD_PROBLEM -> { // The text is limited to 4000 symbols and will be truncated if the limit is exceeded
|
||||||
check(message is BuildProblemLogMessage) {
|
check(message is BuildProblemLogMessage) {
|
||||||
"Unexpected build problem message type: ${message::class.java.canonicalName}"
|
"Unexpected build problem message type: ${message::class.java.canonicalName}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.intellij.openapi.application.PathManager
|
|||||||
import com.intellij.platform.buildScripts.testFramework.createBuildOptionsForTest
|
import com.intellij.platform.buildScripts.testFramework.createBuildOptionsForTest
|
||||||
import com.intellij.platform.buildScripts.testFramework.runEssentialPluginsTest
|
import com.intellij.platform.buildScripts.testFramework.runEssentialPluginsTest
|
||||||
import com.intellij.platform.buildScripts.testFramework.runTestBuild
|
import com.intellij.platform.buildScripts.testFramework.runTestBuild
|
||||||
import com.intellij.platform.buildScripts.testFramework.spanName
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.jetbrains.intellij.build.BuildPaths.Companion.COMMUNITY_ROOT
|
import org.jetbrains.intellij.build.BuildPaths.Companion.COMMUNITY_ROOT
|
||||||
@@ -20,7 +19,7 @@ class IdeaCommunityBuildTest {
|
|||||||
val productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot)
|
val productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot)
|
||||||
runTestBuild(
|
runTestBuild(
|
||||||
homeDir = homePath,
|
homeDir = homePath,
|
||||||
traceSpanName = testInfo.spanName,
|
testInfo = testInfo,
|
||||||
productProperties = productProperties,
|
productProperties = productProperties,
|
||||||
) {
|
) {
|
||||||
it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY) ?: "$homePath/out/classes"
|
it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY) ?: "$homePath/out/classes"
|
||||||
@@ -31,16 +30,17 @@ class IdeaCommunityBuildTest {
|
|||||||
fun jpsStandalone(testInfo: TestInfo) {
|
fun jpsStandalone(testInfo: TestInfo) {
|
||||||
val homePath = PathManager.getHomeDirFor(javaClass)!!
|
val homePath = PathManager.getHomeDirFor(javaClass)!!
|
||||||
runBlocking(Dispatchers.Default) {
|
runBlocking(Dispatchers.Default) {
|
||||||
val productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot)
|
runTestBuild(testInfo, context = {
|
||||||
val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homePath, skipDependencySetup = true)
|
val productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot)
|
||||||
val context = BuildContextImpl.createContext(
|
val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homePath, skipDependencySetup = true, testInfo)
|
||||||
projectHome = homePath,
|
BuildContextImpl.createContext(
|
||||||
productProperties = productProperties,
|
projectHome = homePath,
|
||||||
setupTracer = false,
|
productProperties = productProperties,
|
||||||
options = options,
|
setupTracer = false,
|
||||||
)
|
options = options,
|
||||||
runTestBuild(context = context, traceSpanName = testInfo.spanName) {
|
)
|
||||||
buildCommunityStandaloneJpsBuilder(targetDir = context.paths.artifactDir.resolve("jps"), context = context)
|
}) {
|
||||||
|
buildCommunityStandaloneJpsBuilder(targetDir = it.paths.artifactDir.resolve("jps"), context = it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import kotlinx.collections.immutable.PersistentMap
|
|||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import org.jetbrains.intellij.build.productRunner.IntellijProductRunner
|
import org.jetbrains.intellij.build.productRunner.IntellijProductRunner
|
||||||
import org.jetbrains.jps.model.module.JpsModule
|
import org.jetbrains.jps.model.module.JpsModule
|
||||||
@@ -149,12 +150,27 @@ interface BuildContext : CompilationContext {
|
|||||||
suspend inline fun <T> BuildContext.executeStep(spanBuilder: SpanBuilder,
|
suspend inline fun <T> BuildContext.executeStep(spanBuilder: SpanBuilder,
|
||||||
stepId: String,
|
stepId: String,
|
||||||
crossinline step: suspend CoroutineScope.(Span) -> T): T? {
|
crossinline step: suspend CoroutineScope.(Span) -> T): T? {
|
||||||
if (isStepSkipped(stepId)) {
|
return spanBuilder.useWithScope(Dispatchers.IO) { span ->
|
||||||
spanBuilder.startSpan().addEvent("skip '$stepId' step").end()
|
try {
|
||||||
return null
|
options.buildStepListener.onStart(stepId, messages)
|
||||||
}
|
if (isStepSkipped(stepId)) {
|
||||||
else {
|
span.addEvent("skip '$stepId' step")
|
||||||
return spanBuilder.useWithScope(Dispatchers.IO, step)
|
options.buildStepListener.onSkipping(stepId, messages)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
coroutineScope {
|
||||||
|
step(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (failure: Throwable) {
|
||||||
|
options.buildStepListener.onFailure(stepId, failure, messages)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
options.buildStepListener.onCompletion(stepId, messages)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -478,6 +478,10 @@ data class BuildOptions(
|
|||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
var useReleaseCycleRelatedBundlingRestrictionsForContentReport: Boolean = true
|
var useReleaseCycleRelatedBundlingRestrictionsForContentReport: Boolean = true
|
||||||
|
|
||||||
|
@set:TestOnly
|
||||||
|
@ApiStatus.Internal
|
||||||
|
var buildStepListener: BuildStepListener = BuildStepListener()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val targetOsId = System.getProperty(TARGET_OS_PROPERTY, OS_ALL).lowercase()
|
val targetOsId = System.getProperty(TARGET_OS_PROPERTY, OS_ALL).lowercase()
|
||||||
targetOs = when {
|
targetOs = when {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.intellij.build
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus
|
||||||
|
import org.jetbrains.intellij.build.BuildOptions.Companion.BUILD_STEPS_TO_SKIP_PROPERTY
|
||||||
|
import org.jetbrains.intellij.build.dependencies.TeamCityHelper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* > Not to be confused with [TeamCity build steps](https://www.jetbrains.com/help/teamcity/configuring-build-steps.html)
|
||||||
|
*
|
||||||
|
* Listens to lifecycle events of each build step launched with [org.jetbrains.intellij.build.executeStep].
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
open class BuildStepListener {
|
||||||
|
open suspend fun onStart(stepId: String, messages: BuildMessages) {}
|
||||||
|
open suspend fun onSkipping(stepId: String, messages: BuildMessages) {}
|
||||||
|
open suspend fun onFailure(stepId: String, failure: Throwable, messages: BuildMessages) {
|
||||||
|
val description = buildString {
|
||||||
|
append("'$stepId' build step failed")
|
||||||
|
if (TeamCityHelper.isUnderTeamCity) {
|
||||||
|
append(" (Please don't mute this problem!") // mute scope may be too broad muting similar failures in other build configuration
|
||||||
|
append(" If you really need to ignore it, you may either mark this build as green or add '$stepId' to 'system.${BUILD_STEPS_TO_SKIP_PROPERTY}')")
|
||||||
|
}
|
||||||
|
append(": ")
|
||||||
|
append(failure.stackTraceToString())
|
||||||
|
}
|
||||||
|
messages.reportBuildProblem(description, identity = stepId)
|
||||||
|
}
|
||||||
|
|
||||||
|
open suspend fun onCompletion(stepId: String, messages: BuildMessages) {}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ internal fun CoroutineScope.createStatisticsRecorderBundledMetadataProviderTask(
|
|||||||
val featureUsageStatisticsPropertiesList = context.proprietaryBuildTools.featureUsageStatisticsProperties ?: return null
|
val featureUsageStatisticsPropertiesList = context.proprietaryBuildTools.featureUsageStatisticsProperties ?: return null
|
||||||
return createSkippableJob(
|
return createSkippableJob(
|
||||||
spanBuilder("bundle a default version of feature usage statistics"),
|
spanBuilder("bundle a default version of feature usage statistics"),
|
||||||
taskId = BuildOptions.FUS_METADATA_BUNDLE_STEP,
|
stepId = BuildOptions.FUS_METADATA_BUNDLE_STEP,
|
||||||
context = context
|
context = context
|
||||||
) {
|
) {
|
||||||
for (featureUsageStatisticsProperties in featureUsageStatisticsPropertiesList) {
|
for (featureUsageStatisticsProperties in featureUsageStatisticsPropertiesList) {
|
||||||
|
|||||||
@@ -7,29 +7,23 @@ import com.intellij.util.system.OS
|
|||||||
import io.opentelemetry.api.trace.SpanBuilder
|
import io.opentelemetry.api.trace.SpanBuilder
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.Runnable
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jetbrains.intellij.build.BuildContext
|
import org.jetbrains.intellij.build.BuildContext
|
||||||
import org.jetbrains.intellij.build.CompilationContext
|
import org.jetbrains.intellij.build.CompilationContext
|
||||||
import org.jetbrains.intellij.build.OsFamily
|
import org.jetbrains.intellij.build.OsFamily
|
||||||
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
|
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
|
||||||
|
import org.jetbrains.intellij.build.executeStep
|
||||||
import org.jetbrains.intellij.build.io.copyDir
|
import org.jetbrains.intellij.build.io.copyDir
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
|
||||||
inline fun CoroutineScope.createSkippableJob(spanBuilder: SpanBuilder,
|
inline fun CoroutineScope.createSkippableJob(spanBuilder: SpanBuilder,
|
||||||
taskId: String,
|
stepId: String,
|
||||||
context: BuildContext,
|
context: BuildContext,
|
||||||
crossinline task: suspend () -> Unit): Job? {
|
crossinline task: suspend () -> Unit): Job {
|
||||||
if (context.isStepSkipped(taskId)) {
|
return launch {
|
||||||
spanBuilder.startSpan().addEvent("skip").end()
|
context.executeStep(spanBuilder, stepId) {
|
||||||
return null
|
task()
|
||||||
}
|
|
||||||
else {
|
|
||||||
return launch {
|
|
||||||
spanBuilder.useWithScope {
|
|
||||||
task()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,65 +246,63 @@ internal class DistributionForOsTaskResult(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun buildOsSpecificDistributions(context: BuildContext): List<DistributionForOsTaskResult> {
|
private suspend fun buildOsSpecificDistributions(context: BuildContext): List<DistributionForOsTaskResult> {
|
||||||
if (context.isStepSkipped(BuildOptions.OS_SPECIFIC_DISTRIBUTIONS_STEP)) {
|
return context.executeStep(spanBuilder("build OS-specific distributions"), BuildOptions.OS_SPECIFIC_DISTRIBUTIONS_STEP) {
|
||||||
Span.current().addEvent("skip step", Attributes.of(AttributeKey.stringKey("name"), "build OS-specific distributions"))
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
setLastModifiedTime(context.paths.distAllDir, context)
|
setLastModifiedTime(context.paths.distAllDir, context)
|
||||||
|
|
||||||
if (context.isMacCodeSignEnabled) {
|
if (context.isMacCodeSignEnabled) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
for (file in Files.newDirectoryStream(context.paths.distAllDir).use { stream ->
|
for (file in Files.newDirectoryStream(context.paths.distAllDir).use { stream ->
|
||||||
stream.filter { !it.endsWith("help") && !it.endsWith("license") && !it.endsWith("lib") }
|
stream.filter { !it.endsWith("help") && !it.endsWith("license") && !it.endsWith("lib") }
|
||||||
}) {
|
}) {
|
||||||
launch {
|
launch {
|
||||||
// todo exclude plugins - layoutAdditionalResources should perform codesign -
|
// todo exclude plugins - layoutAdditionalResources should perform codesign -
|
||||||
// that's why we process files and zip in plugins (but not JARs)
|
// that's why we process files and zip in plugins (but not JARs)
|
||||||
// and also kotlin compiler includes JNA
|
// and also kotlin compiler includes JNA
|
||||||
recursivelySignMacBinaries(root = file, context = context)
|
recursivelySignMacBinaries(root = file, context = context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val ideaPropertyFileContent = createIdeaPropertyFile(context)
|
val ideaPropertyFileContent = createIdeaPropertyFile(context)
|
||||||
|
|
||||||
spanBuilder("Adjust executable permissions on common dist").use {
|
spanBuilder("Adjust executable permissions on common dist").use {
|
||||||
val matchers = SUPPORTED_DISTRIBUTIONS.mapNotNull {
|
val matchers = SUPPORTED_DISTRIBUTIONS.mapNotNull {
|
||||||
getOsDistributionBuilder(it.os, null, context)
|
getOsDistributionBuilder(it.os, null, context)
|
||||||
}.flatMap { builder ->
|
}.flatMap { builder ->
|
||||||
JvmArchitecture.entries.flatMap { arch ->
|
JvmArchitecture.entries.flatMap { arch ->
|
||||||
builder.generateExecutableFilesMatchers(includeRuntime = true, arch = arch).keys
|
builder.generateExecutableFilesMatchers(includeRuntime = true, arch = arch).keys
|
||||||
}
|
|
||||||
}
|
|
||||||
updateExecutablePermissions(context.paths.distAllDir, matchers)
|
|
||||||
}
|
|
||||||
|
|
||||||
return supervisorScope {
|
|
||||||
SUPPORTED_DISTRIBUTIONS.mapNotNull { (os, arch) ->
|
|
||||||
if (!context.shouldBuildDistributionForOS(os, arch)) {
|
|
||||||
return@mapNotNull null
|
|
||||||
}
|
|
||||||
|
|
||||||
val builder = getOsDistributionBuilder(os = os, ideaProperties = ideaPropertyFileContent, context = context) ?: return@mapNotNull null
|
|
||||||
|
|
||||||
val stepId = "${os.osId} ${arch.name}"
|
|
||||||
if (context.options.buildStepsToSkip.contains(stepId)) {
|
|
||||||
Span.current().addEvent("skip step", Attributes.of(AttributeKey.stringKey("id"), stepId))
|
|
||||||
return@mapNotNull null
|
|
||||||
}
|
|
||||||
|
|
||||||
async {
|
|
||||||
spanBuilder(stepId).useWithScope {
|
|
||||||
val osAndArchSpecificDistDirectory = getOsAndArchSpecificDistDirectory(osFamily = os, arch = arch, context = context)
|
|
||||||
builder.buildArtifacts(osAndArchSpecificDistPath = osAndArchSpecificDistDirectory, arch = arch)
|
|
||||||
checkClassFiles(root = osAndArchSpecificDistDirectory, context = context, isDistAll = false)
|
|
||||||
DistributionForOsTaskResult(builder = builder, arch = arch, outDir = osAndArchSpecificDistDirectory)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateExecutablePermissions(context.paths.distAllDir, matchers)
|
||||||
}
|
}
|
||||||
}.collectCompletedOrError()
|
|
||||||
|
supervisorScope {
|
||||||
|
SUPPORTED_DISTRIBUTIONS.mapNotNull { (os, arch) ->
|
||||||
|
if (!context.shouldBuildDistributionForOS(os, arch)) {
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = getOsDistributionBuilder(os = os, ideaProperties = ideaPropertyFileContent, context = context) ?: return@mapNotNull null
|
||||||
|
|
||||||
|
val stepId = "${os.osId} ${arch.name}"
|
||||||
|
if (context.options.buildStepsToSkip.contains(stepId)) {
|
||||||
|
Span.current().addEvent("skip step", Attributes.of(AttributeKey.stringKey("id"), stepId))
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
|
||||||
|
async {
|
||||||
|
spanBuilder(stepId).useWithScope {
|
||||||
|
val osAndArchSpecificDistDirectory = getOsAndArchSpecificDistDirectory(osFamily = os, arch = arch, context = context)
|
||||||
|
builder.buildArtifacts(osAndArchSpecificDistPath = osAndArchSpecificDistDirectory, arch = arch)
|
||||||
|
checkClassFiles(root = osAndArchSpecificDistDirectory, context = context, isDistAll = false)
|
||||||
|
DistributionForOsTaskResult(builder = builder, arch = arch, outDir = osAndArchSpecificDistDirectory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.collectCompletedOrError()
|
||||||
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// call only after supervisorScope
|
// call only after supervisorScope
|
||||||
@@ -377,66 +375,71 @@ internal fun collectModulesToCompileForDistribution(context: BuildContext): Muta
|
|||||||
|
|
||||||
private suspend fun compileModulesForDistribution(context: BuildContext): DistributionBuilderState {
|
private suspend fun compileModulesForDistribution(context: BuildContext): DistributionBuilderState {
|
||||||
val compilationTasks = CompilationTasks.create(context)
|
val compilationTasks = CompilationTasks.create(context)
|
||||||
collectModulesToCompileForDistribution(context).let {
|
val moduleNames = collectModulesToCompileForDistribution(context)
|
||||||
compilationTasks.compileModules(moduleNames = it)
|
compilationTasks.compileModules(moduleNames)
|
||||||
}
|
|
||||||
|
|
||||||
val productLayout = context.productProperties.productLayout
|
val productLayout = context.productProperties.productLayout
|
||||||
val pluginsToPublish = getPluginLayoutsByJpsModuleNames(modules = productLayout.pluginModulesToPublish, productLayout = productLayout)
|
val pluginsToPublish = getPluginLayoutsByJpsModuleNames(modules = productLayout.pluginModulesToPublish, productLayout = productLayout)
|
||||||
filterPluginsToPublish(plugins = pluginsToPublish, context = context)
|
filterPluginsToPublish(plugins = pluginsToPublish, context = context)
|
||||||
|
|
||||||
var enabledPluginModules = getEnabledPluginModules(pluginsToPublish = pluginsToPublish, context = context)
|
val enabledPluginModules = getEnabledPluginModules(pluginsToPublish = pluginsToPublish, context = context)
|
||||||
// computed only based on a bundled and plugins to publish lists, compatible plugins are not taken in an account by intention
|
// computed only based on a bundled and plugins to publish lists, compatible plugins are not taken in an account by intention
|
||||||
val projectLibrariesUsedByPlugins = computeProjectLibsUsedByPlugins(enabledPluginModules = enabledPluginModules, context = context)
|
val projectLibrariesUsedByPlugins = computeProjectLibsUsedByPlugins(enabledPluginModules = enabledPluginModules, context = context)
|
||||||
|
|
||||||
if (context.shouldBuildDistributions()) {
|
return context.executeStep(spanBuilder("collecting compatible plugins"), BuildOptions.PROVIDED_MODULES_LIST_STEP) {
|
||||||
if (context.isStepSkipped(BuildOptions.PROVIDED_MODULES_LIST_STEP)) {
|
if (!context.shouldBuildDistributions()) {
|
||||||
Span.current().addEvent("skip collecting compatible plugins because ${BuildOptions.PROVIDED_MODULES_LIST_STEP} was skipped")
|
it.addEvent("skipped, no need to build distributions")
|
||||||
|
return@executeStep null
|
||||||
|
}
|
||||||
|
val providedModuleFile = context.paths.artifactDir.resolve("${context.applicationInfo.productCode}-builtinModules.json")
|
||||||
|
val platform = createPlatformLayout(context = context)
|
||||||
|
val moduleNames = getModulesForPluginsToPublish(platform = platform, pluginsToPublish = pluginsToPublish)
|
||||||
|
compilationTasks.compileModules(moduleNames)
|
||||||
|
|
||||||
|
val builtinModuleData = spanBuilder("build provided module list").useWithScope {
|
||||||
|
Files.deleteIfExists(providedModuleFile)
|
||||||
|
// start the product in headless mode using com.intellij.ide.plugins.BundledPluginsLister
|
||||||
|
context.createProductRunner().runProduct(args = listOf("listBundledPlugins", providedModuleFile.toString()))
|
||||||
|
|
||||||
|
context.productProperties.customizeBuiltinModules(context = context, builtinModulesFile = providedModuleFile)
|
||||||
|
try {
|
||||||
|
val builtinModuleData = readBuiltinModulesFile(file = providedModuleFile)
|
||||||
|
context.builtinModule = builtinModuleData
|
||||||
|
builtinModuleData
|
||||||
|
}
|
||||||
|
catch (_: NoSuchFileException) {
|
||||||
|
throw IllegalStateException("Failed to build provided modules list: $providedModuleFile doesn't exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.notifyArtifactBuilt(artifactPath = providedModuleFile)
|
||||||
|
if (!productLayout.buildAllCompatiblePlugins) {
|
||||||
|
val distState = DistributionBuilderState(platform = platform, pluginsToPublish = pluginsToPublish, context = context)
|
||||||
|
buildProjectArtifacts(platform = distState.platform, enabledPluginModules = enabledPluginModules, compilationTasks = compilationTasks, context = context)
|
||||||
|
distState
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val providedModuleFile = context.paths.artifactDir.resolve("${context.applicationInfo.productCode}-builtinModules.json")
|
|
||||||
val platform = createPlatformLayout(context = context)
|
|
||||||
getModulesForPluginsToPublish(platform = platform, pluginsToPublish = pluginsToPublish).let {
|
|
||||||
compilationTasks.compileModules(moduleNames = it)
|
|
||||||
}
|
|
||||||
|
|
||||||
val builtinModuleData = spanBuilder("build provided module list").useWithScope {
|
|
||||||
Files.deleteIfExists(providedModuleFile)
|
|
||||||
// start the product in headless mode using com.intellij.ide.plugins.BundledPluginsLister
|
|
||||||
context.createProductRunner().runProduct(args = listOf("listBundledPlugins", providedModuleFile.toString()))
|
|
||||||
|
|
||||||
context.productProperties.customizeBuiltinModules(context = context, builtinModulesFile = providedModuleFile)
|
|
||||||
try {
|
|
||||||
val builtinModuleData = readBuiltinModulesFile(file = providedModuleFile)
|
|
||||||
context.builtinModule = builtinModuleData
|
|
||||||
builtinModuleData
|
|
||||||
}
|
|
||||||
catch (_: NoSuchFileException) {
|
|
||||||
throw IllegalStateException("Failed to build provided modules list: $providedModuleFile doesn\'t exist")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.notifyArtifactBuilt(artifactPath = providedModuleFile)
|
|
||||||
if (!productLayout.buildAllCompatiblePlugins) {
|
|
||||||
val distState = DistributionBuilderState(platform = platform, pluginsToPublish = pluginsToPublish, context = context)
|
|
||||||
buildProjectArtifacts(platform = distState.platform, enabledPluginModules = enabledPluginModules, compilationTasks = compilationTasks, context = context)
|
|
||||||
return distState
|
|
||||||
}
|
|
||||||
|
|
||||||
collectCompatiblePluginsToPublish(builtinModuleData = builtinModuleData, result = pluginsToPublish, context = context)
|
collectCompatiblePluginsToPublish(builtinModuleData = builtinModuleData, result = pluginsToPublish, context = context)
|
||||||
filterPluginsToPublish(plugins = pluginsToPublish, context = context)
|
filterPluginsToPublish(plugins = pluginsToPublish, context = context)
|
||||||
|
|
||||||
// update enabledPluginModules to reflect changes in pluginsToPublish - used for buildProjectArtifacts
|
// update enabledPluginModules to reflect changes in pluginsToPublish - used for buildProjectArtifacts
|
||||||
enabledPluginModules = getEnabledPluginModules(pluginsToPublish = pluginsToPublish, context = context)
|
val enabledPluginModules = getEnabledPluginModules(pluginsToPublish = pluginsToPublish, context = context)
|
||||||
|
distributionState(context, pluginsToPublish, projectLibrariesUsedByPlugins, enabledPluginModules)
|
||||||
}
|
}
|
||||||
}
|
} ?: distributionState(context, pluginsToPublish, projectLibrariesUsedByPlugins, enabledPluginModules)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun distributionState(
|
||||||
|
context: BuildContext,
|
||||||
|
pluginsToPublish: Set<PluginLayout>,
|
||||||
|
projectLibrariesUsedByPlugins: SortedSet<ProjectLibraryData>,
|
||||||
|
enabledPluginModules: Set<String>,
|
||||||
|
): DistributionBuilderState {
|
||||||
val platform = createPlatformLayout(projectLibrariesUsedByPlugins = projectLibrariesUsedByPlugins, context = context)
|
val platform = createPlatformLayout(projectLibrariesUsedByPlugins = projectLibrariesUsedByPlugins, context = context)
|
||||||
val distState = DistributionBuilderState(platform = platform, pluginsToPublish = pluginsToPublish, context = context)
|
val distState = DistributionBuilderState(platform = platform, pluginsToPublish = pluginsToPublish, context = context)
|
||||||
distState.getModulesForPluginsToPublish().let {
|
val moduleNames = distState.getModulesForPluginsToPublish()
|
||||||
compilationTasks.compileModules(moduleNames = it)
|
val compilationTasks = CompilationTasks.create(context)
|
||||||
}
|
compilationTasks.compileModules(moduleNames)
|
||||||
|
|
||||||
buildProjectArtifacts(platform = distState.platform, enabledPluginModules = enabledPluginModules, compilationTasks = compilationTasks, context = context)
|
buildProjectArtifacts(platform = distState.platform, enabledPluginModules = enabledPluginModules, compilationTasks = compilationTasks, context = context)
|
||||||
return distState
|
return distState
|
||||||
}
|
}
|
||||||
@@ -553,7 +556,7 @@ private fun CoroutineScope.createMavenArtifactJob(context: BuildContext, distrib
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkProductProperties(context: BuildContextImpl) {
|
private suspend fun checkProductProperties(context: BuildContextImpl) {
|
||||||
checkProductLayout(context)
|
checkProductLayout(context)
|
||||||
|
|
||||||
val properties = context.productProperties
|
val properties = context.productProperties
|
||||||
@@ -604,7 +607,7 @@ private fun checkProductProperties(context: BuildContextImpl) {
|
|||||||
listOfNotNull(macCustomizer.icnsPathForAlternativeIconForEAP),
|
listOfNotNull(macCustomizer.icnsPathForAlternativeIconForEAP),
|
||||||
"productProperties.macCustomizer.icnsPathForAlternativeIconForEAP"
|
"productProperties.macCustomizer.icnsPathForAlternativeIconForEAP"
|
||||||
)
|
)
|
||||||
if (!context.isStepSkipped(BuildOptions.MAC_DMG_STEP)) {
|
context.executeStep(spanBuilder("check .dmg images"), BuildOptions.MAC_DMG_STEP) {
|
||||||
checkMandatoryPath(macCustomizer.dmgImagePath, "productProperties.macCustomizer.dmgImagePath")
|
checkMandatoryPath(macCustomizer.dmgImagePath, "productProperties.macCustomizer.dmgImagePath")
|
||||||
checkPaths(listOfNotNull(macCustomizer.dmgImagePathForEAP), "productProperties.macCustomizer.dmgImagePathForEAP")
|
checkPaths(listOfNotNull(macCustomizer.dmgImagePathForEAP), "productProperties.macCustomizer.dmgImagePathForEAP")
|
||||||
}
|
}
|
||||||
@@ -867,28 +870,30 @@ private fun buildCrossPlatformZip(distResults: List<DistributionForOsTaskResult>
|
|||||||
|
|
||||||
private suspend fun checkClassFiles(root: Path, context: BuildContext, isDistAll: Boolean) {
|
private suspend fun checkClassFiles(root: Path, context: BuildContext, isDistAll: Boolean) {
|
||||||
// version checking patterns are only for dist all (all non-os and non-arch specific files)
|
// version checking patterns are only for dist all (all non-os and non-arch specific files)
|
||||||
if (!isDistAll || context.isStepSkipped(BuildOptions.VERIFY_CLASS_FILE_VERSIONS)) {
|
if (!isDistAll) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val versionCheckerConfig = context.productProperties.versionCheckerConfig
|
context.executeStep(spanBuilder("checkClassFiles"), BuildOptions.VERIFY_CLASS_FILE_VERSIONS) {
|
||||||
val forbiddenSubPaths = context.productProperties.forbiddenClassFileSubPaths
|
val versionCheckerConfig = context.productProperties.versionCheckerConfig
|
||||||
val forbiddenSubPathExceptions = context.productProperties.forbiddenClassFileSubPathExceptions
|
val forbiddenSubPaths = context.productProperties.forbiddenClassFileSubPaths
|
||||||
if (forbiddenSubPaths.isNotEmpty()) {
|
val forbiddenSubPathExceptions = context.productProperties.forbiddenClassFileSubPathExceptions
|
||||||
val forbiddenString = forbiddenSubPaths.let { "(${it.size}): ${it.joinToString()}" }
|
if (forbiddenSubPaths.isNotEmpty()) {
|
||||||
val exceptionsString = forbiddenSubPathExceptions.let { "(${it.size}): ${it.joinToString()}" }
|
val forbiddenString = forbiddenSubPaths.let { "(${it.size}): ${it.joinToString()}" }
|
||||||
Span.current().addEvent("checkClassFiles: forbiddenSubPaths $forbiddenString, exceptions $exceptionsString")
|
val exceptionsString = forbiddenSubPathExceptions.let { "(${it.size}): ${it.joinToString()}" }
|
||||||
}
|
it.addEvent("forbiddenSubPaths $forbiddenString, exceptions $exceptionsString")
|
||||||
else {
|
}
|
||||||
Span.current().addEvent("checkClassFiles: forbiddenSubPaths: EMPTY (no scrambling checks will be done)")
|
else {
|
||||||
}
|
it.addEvent("forbiddenSubPaths: EMPTY (no scrambling checks will be done)")
|
||||||
|
}
|
||||||
|
|
||||||
if (versionCheckerConfig.isNotEmpty() || forbiddenSubPaths.isNotEmpty()) {
|
if (versionCheckerConfig.isNotEmpty() || forbiddenSubPaths.isNotEmpty()) {
|
||||||
checkClassFiles(versionCheckConfig = versionCheckerConfig, forbiddenSubPaths = forbiddenSubPaths, forbiddenSubPathExceptions = forbiddenSubPathExceptions, root = root)
|
checkClassFiles(versionCheckConfig = versionCheckerConfig, forbiddenSubPaths = forbiddenSubPaths, forbiddenSubPathExceptions = forbiddenSubPathExceptions, root = root)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forbiddenSubPaths.isNotEmpty()) {
|
if (forbiddenSubPaths.isNotEmpty()) {
|
||||||
Span.current().addEvent("checkClassFiles: SUCCESS for forbiddenSubPaths at '$root': ${forbiddenSubPaths.joinToString()}")
|
it.addEvent("SUCCESS for forbiddenSubPaths at '$root': ${forbiddenSubPaths.joinToString()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -397,13 +397,9 @@ internal suspend fun buildNonBundledPlugins(
|
|||||||
searchableOptionSet: SearchableOptionSetDescriptor?,
|
searchableOptionSet: SearchableOptionSetDescriptor?,
|
||||||
context: BuildContext,
|
context: BuildContext,
|
||||||
): List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>> {
|
): List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>> {
|
||||||
return spanBuilder("build non-bundled plugins").setAttribute("count", pluginsToPublish.size.toLong()).useWithScope { span ->
|
return context.executeStep(spanBuilder("build non-bundled plugins").setAttribute("count", pluginsToPublish.size.toLong()), BuildOptions.NON_BUNDLED_PLUGINS_STEP) {
|
||||||
if (pluginsToPublish.isEmpty()) {
|
if (pluginsToPublish.isEmpty()) {
|
||||||
return@useWithScope emptyList()
|
return@executeStep emptyList()
|
||||||
}
|
|
||||||
if (context.isStepSkipped(BuildOptions.NON_BUNDLED_PLUGINS_STEP)) {
|
|
||||||
span.addEvent("skip")
|
|
||||||
return@useWithScope emptyList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val nonBundledPluginsArtifacts = context.paths.artifactDir.resolve("${context.applicationInfo.productCode}-plugins")
|
val nonBundledPluginsArtifacts = context.paths.artifactDir.resolve("${context.applicationInfo.productCode}-plugins")
|
||||||
@@ -473,39 +469,44 @@ internal suspend fun buildNonBundledPlugins(
|
|||||||
generatePluginRepositoryMetaFile(list.filter { it.pluginZip.startsWith(autoUploadingDir) }, autoUploadingDir, context)
|
generatePluginRepositoryMetaFile(list.filter { it.pluginZip.startsWith(autoUploadingDir) }, autoUploadingDir, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.isStepSkipped(BuildOptions.VALIDATE_PLUGINS_TO_BE_PUBLISHED)) {
|
validatePlugins(context, pluginSpecs)
|
||||||
for (plugin in pluginSpecs) {
|
|
||||||
launch {
|
|
||||||
validatePlugin(path = plugin.pluginZip, context = context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mappings
|
mappings
|
||||||
|
} ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun validatePlugins(context: BuildContext, pluginSpecs: Collection<PluginRepositorySpec>) {
|
||||||
|
context.executeStep(spanBuilder("plugins validation"), BuildOptions.VALIDATE_PLUGINS_TO_BE_PUBLISHED) { span ->
|
||||||
|
for (plugin in pluginSpecs) {
|
||||||
|
val path = plugin.pluginZip
|
||||||
|
if (Files.notExists(path)) {
|
||||||
|
span.addEvent("doesn't exist, skipped", Attributes.of(AttributeKey.stringKey("path"), "$path"))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
validatePlugin(path, context, span)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun validatePlugin(path: Path, context: BuildContext) {
|
private fun validatePlugin(path: Path, context: BuildContext, span: Span) {
|
||||||
spanBuilder("plugin validation").setAttribute("path", path.toString()).useWithScope { span ->
|
val pluginManager = IdePluginManager.createManager()
|
||||||
if (Files.notExists(path)) {
|
val result = pluginManager.createPlugin(path, validateDescriptor = true)
|
||||||
span.addEvent("path doesn't exist, skipped")
|
// todo fix AddStatisticsEventLogListenerTemporary
|
||||||
return@useWithScope
|
val id = when (result) {
|
||||||
}
|
is PluginCreationSuccess -> result.plugin.pluginId
|
||||||
|
is PluginCreationFail -> (pluginManager.createPlugin(path, validateDescriptor = false) as? PluginCreationSuccess)?.plugin?.pluginId
|
||||||
val pluginManager = IdePluginManager.createManager()
|
}
|
||||||
val result = pluginManager.createPlugin(path, validateDescriptor = true)
|
val problems = context.productProperties.validatePlugin(id, result, context)
|
||||||
// todo fix AddStatisticsEventLogListenerTemporary
|
if (problems.isNotEmpty()) {
|
||||||
val id = when (result) {
|
span.addEvent("failed", Attributes.of(AttributeKey.stringKey("path"), "$path"))
|
||||||
is PluginCreationSuccess -> result.plugin.pluginId
|
context.messages.reportBuildProblem(
|
||||||
is PluginCreationFail -> (pluginManager.createPlugin(path, validateDescriptor = false) as? PluginCreationSuccess)?.plugin?.pluginId
|
problems.joinToString(
|
||||||
}
|
|
||||||
val problems = context.productProperties.validatePlugin(id, result, context)
|
|
||||||
if (problems.isNotEmpty()) {
|
|
||||||
context.messages.reportBuildProblem(problems.joinToString(
|
|
||||||
prefix = "${id ?: path}: ",
|
prefix = "${id ?: path}: ",
|
||||||
separator = ". ",
|
separator = ". ",
|
||||||
), identity = "${id ?: path}")
|
), identity = "${id ?: path}"
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,7 +872,7 @@ private suspend fun scramble(platform: PlatformLayout, context: BuildContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.createBuildBrokenPluginListJob(context: BuildContext): Job? {
|
private fun CoroutineScope.createBuildBrokenPluginListJob(context: BuildContext): Job {
|
||||||
val buildString = context.fullBuildNumber
|
val buildString = context.fullBuildNumber
|
||||||
return createSkippableJob(
|
return createSkippableJob(
|
||||||
spanBuilder("build broken plugin list").setAttribute("buildNumber", buildString),
|
spanBuilder("build broken plugin list").setAttribute("buildNumber", buildString),
|
||||||
@@ -885,7 +886,7 @@ private fun CoroutineScope.createBuildBrokenPluginListJob(context: BuildContext)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.createBuildThirdPartyLibraryListJob(entries: Sequence<DistributionFileEntry>, context: BuildContext): Job? {
|
private fun CoroutineScope.createBuildThirdPartyLibraryListJob(entries: Sequence<DistributionFileEntry>, context: BuildContext): Job {
|
||||||
return createSkippableJob(spanBuilder("generate table of licenses for used third-party libraries"),
|
return createSkippableJob(spanBuilder("generate table of licenses for used third-party libraries"),
|
||||||
BuildOptions.THIRD_PARTY_LIBRARIES_LIST_STEP, context) {
|
BuildOptions.THIRD_PARTY_LIBRARIES_LIST_STEP, context) {
|
||||||
val generator = createLibraryLicensesListGenerator(
|
val generator = createLibraryLicensesListGenerator(
|
||||||
|
|||||||
@@ -121,14 +121,16 @@ class LinuxDistributionBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tarGzPath != null && !context.isStepSkipped(BuildOptions.REPAIR_UTILITY_BUNDLE_STEP)) {
|
if (tarGzPath != null ) {
|
||||||
val tempTar = Files.createTempDirectory(context.paths.tempDir, "tar-")
|
context.executeStep(spanBuilder("bundle repair utility"), BuildOptions.REPAIR_UTILITY_BUNDLE_STEP) {
|
||||||
try {
|
val tempTar = Files.createTempDirectory(context.paths.tempDir, "tar-")
|
||||||
unTar(tarGzPath, tempTar)
|
try {
|
||||||
RepairUtilityBuilder.generateManifest(context, unpackedDistribution = tempTar.resolve(rootDirectoryName), OsFamily.LINUX, arch)
|
unTar(tarGzPath, tempTar)
|
||||||
}
|
RepairUtilityBuilder.generateManifest(context, unpackedDistribution = tempTar.resolve(rootDirectoryName), OsFamily.LINUX, arch)
|
||||||
finally {
|
}
|
||||||
NioFiles.deleteRecursively(tempTar)
|
finally {
|
||||||
|
NioFiles.deleteRecursively(tempTar)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
package org.jetbrains.intellij.build
|
package org.jetbrains.intellij.build
|
||||||
|
|
||||||
import io.opentelemetry.api.common.AttributeKey
|
import io.opentelemetry.api.common.AttributeKey
|
||||||
import io.opentelemetry.api.trace.Span
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
@@ -68,42 +67,38 @@ internal suspend fun buildSearchableOptions(
|
|||||||
context: BuildContext,
|
context: BuildContext,
|
||||||
systemProperties: VmProperties = VmProperties(emptyMap()),
|
systemProperties: VmProperties = VmProperties(emptyMap()),
|
||||||
): SearchableOptionSetDescriptor? {
|
): SearchableOptionSetDescriptor? {
|
||||||
val span = Span.current()
|
return context.executeStep(spanBuilder("building searchable options index"), BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP) { span ->
|
||||||
if (context.isStepSkipped(BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP)) {
|
val targetDirectory = context.paths.searchableOptionDir
|
||||||
span.addEvent("skip building searchable options index")
|
// bundled maven is also downloaded during traverseUI execution in an external process,
|
||||||
return null
|
// making it fragile to call more than one traverseUI at the same time (in the reproducibility test, for example),
|
||||||
|
// so it's pre-downloaded with proper synchronization
|
||||||
|
coroutineScope {
|
||||||
|
launch {
|
||||||
|
BundledMavenDownloader.downloadMaven4Libs(context.paths.communityHomeDirRoot)
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
BundledMavenDownloader.downloadMaven3Libs(context.paths.communityHomeDirRoot)
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
BundledMavenDownloader.downloadMavenDistribution(context.paths.communityHomeDirRoot)
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
BundledMavenDownloader.downloadMavenTelemetryDependencies(context.paths.communityHomeDirRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the product in headless mode using com.intellij.ide.ui.search.TraverseUIStarter.
|
||||||
|
// It'll process all UI elements in the `Settings` dialog and build an index for them.
|
||||||
|
productRunner.runProduct(
|
||||||
|
args = listOf("traverseUI", targetDirectory.toString(), "true"),
|
||||||
|
additionalVmProperties = systemProperties + VmProperties(mapOf("idea.l10n.keys" to "only")),
|
||||||
|
timeout = DEFAULT_TIMEOUT,
|
||||||
|
)
|
||||||
|
|
||||||
|
val index = readSearchableOptionIndex(targetDirectory)
|
||||||
|
span.setAttribute(AttributeKey.longKey("moduleCountWithSearchableOptions"), index.index.size)
|
||||||
|
span.setAttribute(AttributeKey.stringArrayKey("modulesWithSearchableOptions"), index.index.keys.toList())
|
||||||
|
|
||||||
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
val targetDirectory = context.paths.searchableOptionDir
|
|
||||||
// bundled maven is also downloaded during traverseUI execution in an external process,
|
|
||||||
// making it fragile to call more than one traverseUI at the same time (in the reproducibility test, for example),
|
|
||||||
// so it's pre-downloaded with proper synchronization
|
|
||||||
coroutineScope {
|
|
||||||
launch {
|
|
||||||
BundledMavenDownloader.downloadMaven4Libs(context.paths.communityHomeDirRoot)
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
BundledMavenDownloader.downloadMaven3Libs(context.paths.communityHomeDirRoot)
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
BundledMavenDownloader.downloadMavenDistribution(context.paths.communityHomeDirRoot)
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
BundledMavenDownloader.downloadMavenTelemetryDependencies(context.paths.communityHomeDirRoot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the product in headless mode using com.intellij.ide.ui.search.TraverseUIStarter.
|
|
||||||
// It'll process all UI elements in the `Settings` dialog and build an index for them.
|
|
||||||
productRunner.runProduct(
|
|
||||||
args = listOf("traverseUI", targetDirectory.toString(), "true"),
|
|
||||||
additionalVmProperties = systemProperties + VmProperties(mapOf("idea.l10n.keys" to "only")),
|
|
||||||
timeout = DEFAULT_TIMEOUT,
|
|
||||||
)
|
|
||||||
|
|
||||||
val index = readSearchableOptionIndex(targetDirectory)
|
|
||||||
span.setAttribute(AttributeKey.longKey("moduleCountWithSearchableOptions"), index.index.size)
|
|
||||||
span.setAttribute(AttributeKey.stringArrayKey("modulesWithSearchableOptions"), index.index.keys.toList())
|
|
||||||
|
|
||||||
return index
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package com.intellij.platform.buildScripts.testFramework
|
||||||
|
|
||||||
|
import jetbrains.buildServer.messages.serviceMessages.ServiceMessageTypes
|
||||||
|
import org.jetbrains.annotations.ApiStatus
|
||||||
|
import org.jetbrains.intellij.build.BuildMessages
|
||||||
|
import org.jetbrains.intellij.build.BuildStepListener
|
||||||
|
import org.jetbrains.intellij.build.logging.TeamCityBuildMessageLogger.Companion.SpanAwareServiceMessage
|
||||||
|
import org.junit.jupiter.api.TestInfo
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See [BuildStepListener].
|
||||||
|
*
|
||||||
|
* Reports each build step launched with [org.jetbrains.intellij.build.executeStep] as a TeamCity test:
|
||||||
|
* * such a test must be started in its own dedicated [flow](https://www.jetbrains.com/help/teamcity/service-messages.html#Message+FlowId), see [org.jetbrains.intellij.build.executeStep]
|
||||||
|
* * each flow started withing a test should be a transitive subflow of that test's own flow, see [org.jetbrains.intellij.build.logging.TeamCityBuildMessageLogger.withFlow]
|
||||||
|
*
|
||||||
|
* Otherwise, tests will not be correctly displayed in a TeamCity build log.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
open class BuildStepTeamCityListener(testInfo: TestInfo) : BuildStepListener() {
|
||||||
|
private val testName: String = "${testInfo.testClass.get().canonicalName}.${testInfo.testMethod.orElseThrow().name}"
|
||||||
|
|
||||||
|
private fun reportTestEvent(testEvent: String, stepId: String, vararg attributes: Pair<String, String>) {
|
||||||
|
println(SpanAwareServiceMessage(testEvent, "name" to "$testName($stepId)", *attributes))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onStart(stepId: String, messages: BuildMessages) {
|
||||||
|
super.onStart(stepId, messages)
|
||||||
|
reportTestEvent(ServiceMessageTypes.TEST_STARTED, stepId)
|
||||||
|
messages.warning("This test is automatically generated from the build step '$stepId'")
|
||||||
|
messages.warning("To run it locally, please invoke '$testName'")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onSkipping(stepId: String, messages: BuildMessages) {
|
||||||
|
super.onSkipping(stepId, messages)
|
||||||
|
reportTestEvent(ServiceMessageTypes.TEST_IGNORED, stepId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onFailure(stepId: String, failure: Throwable, messages: BuildMessages) {
|
||||||
|
// no need to throw the build step failure, just reporting it to TeamCity as a test failure,
|
||||||
|
// providing an option to mute it without muting the main test
|
||||||
|
reportTestEvent(ServiceMessageTypes.TEST_FAILED, stepId, "message" to "${failure.message}", "details" to failure.stackTraceToString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onCompletion(stepId: String, messages: BuildMessages) {
|
||||||
|
super.onCompletion(stepId, messages)
|
||||||
|
reportTestEvent(ServiceMessageTypes.TEST_FINISHED, stepId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,18 +8,21 @@ import org.jetbrains.intellij.build.ProductProperties
|
|||||||
import org.jetbrains.intellij.build.ProprietaryBuildTools
|
import org.jetbrains.intellij.build.ProprietaryBuildTools
|
||||||
import org.jetbrains.intellij.build.impl.readBuiltinModulesFile
|
import org.jetbrains.intellij.build.impl.readBuiltinModulesFile
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.TestInfo
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that frontend distribution (ex JetBrains Client) described by [frontendProperties] can be built successfully.
|
* Checks that frontend distribution (ex JetBrains Client) described by [frontendProperties] can be built successfully.
|
||||||
*/
|
*/
|
||||||
fun runTestBuildForFrontend(homePath: Path, frontendProperties: ProductProperties, buildTools: ProprietaryBuildTools,
|
fun runTestBuildForFrontend(
|
||||||
traceSpanName: String, softly: SoftAssertions) {
|
homePath: Path, frontendProperties: ProductProperties, buildTools: ProprietaryBuildTools,
|
||||||
|
testInfo: TestInfo, softly: SoftAssertions,
|
||||||
|
) {
|
||||||
runTestBuild(
|
runTestBuild(
|
||||||
homeDir = homePath,
|
homeDir = homePath,
|
||||||
productProperties = frontendProperties,
|
productProperties = frontendProperties,
|
||||||
buildTools = buildTools,
|
buildTools = buildTools,
|
||||||
traceSpanName = traceSpanName,
|
testInfo = testInfo,
|
||||||
onSuccess = { context ->
|
onSuccess = { context ->
|
||||||
verifyBuiltInModules(context.paths.artifactDir.resolve("${context.applicationInfo.productCode}-builtinModules.json"))
|
verifyBuiltInModules(context.paths.artifactDir.resolve("${context.applicationInfo.productCode}-builtinModules.json"))
|
||||||
assertTrue(context.useModularLoader) { "Frontend distribution must use the modular loader, but $frontendProperties doesn't use it" }
|
assertTrue(context.useModularLoader) { "Frontend distribution must use the modular loader, but $frontendProperties doesn't use it" }
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import org.assertj.core.api.SoftAssertions
|
import org.assertj.core.api.SoftAssertions
|
||||||
import org.jetbrains.intellij.build.*
|
import org.jetbrains.intellij.build.*
|
||||||
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
|
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
|
||||||
|
import org.jetbrains.intellij.build.dependencies.TeamCityHelper.isUnderTeamCity
|
||||||
import org.jetbrains.intellij.build.impl.BuildContextImpl
|
import org.jetbrains.intellij.build.impl.BuildContextImpl
|
||||||
import org.jetbrains.intellij.build.impl.buildDistributions
|
import org.jetbrains.intellij.build.impl.buildDistributions
|
||||||
|
import org.jetbrains.intellij.build.telemetry.JaegerJsonSpanExporterManager
|
||||||
import org.jetbrains.intellij.build.telemetry.TraceManager
|
import org.jetbrains.intellij.build.telemetry.TraceManager
|
||||||
import org.jetbrains.intellij.build.telemetry.useWithScope
|
import org.jetbrains.intellij.build.telemetry.useWithScope
|
||||||
import org.junit.jupiter.api.TestInfo
|
import org.junit.jupiter.api.TestInfo
|
||||||
@@ -28,10 +30,10 @@ import java.net.http.HttpConnectTimeoutException
|
|||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, skipDependencySetup: Boolean = false): BuildOptions {
|
fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, skipDependencySetup: Boolean = false, testInfo: TestInfo? = null): BuildOptions {
|
||||||
val outDir = createTestBuildOutDir(productProperties)
|
val outDir = createTestBuildOutDir(productProperties)
|
||||||
val options = BuildOptions(cleanOutDir = false, useCompiledClassesFromProjectOutput = true, jarCacheDir = homeDir.resolve("out/dev-run/jar-cache"))
|
val options = BuildOptions(cleanOutDir = false, useCompiledClassesFromProjectOutput = true, jarCacheDir = homeDir.resolve("out/dev-run/jar-cache"))
|
||||||
customizeBuildOptionsForTest(options = options, outDir = outDir, skipDependencySetup = skipDependencySetup)
|
customizeBuildOptionsForTest(options = options, outDir = outDir, skipDependencySetup = skipDependencySetup, testInfo = testInfo)
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,13 +41,13 @@ fun createTestBuildOutDir(productProperties: ProductProperties): Path {
|
|||||||
return FileUtil.createTempDirectory("test-build-${productProperties.baseFileName}", null, false).toPath()
|
return FileUtil.createTempDirectory("test-build-${productProperties.baseFileName}", null, false).toPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, customizer: (BuildOptions) -> Unit): BuildOptions {
|
private inline fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, testInfo: TestInfo, customizer: (BuildOptions) -> Unit): BuildOptions {
|
||||||
val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir)
|
val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo)
|
||||||
customizer(options)
|
customizer(options)
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
fun customizeBuildOptionsForTest(options: BuildOptions, outDir: Path, skipDependencySetup: Boolean = false) {
|
fun customizeBuildOptionsForTest(options: BuildOptions, outDir: Path, skipDependencySetup: Boolean = false, testInfo: TestInfo?) {
|
||||||
options.skipDependencySetup = skipDependencySetup
|
options.skipDependencySetup = skipDependencySetup
|
||||||
options.isTestBuild = true
|
options.isTestBuild = true
|
||||||
|
|
||||||
@@ -56,11 +58,15 @@ fun customizeBuildOptionsForTest(options: BuildOptions, outDir: Path, skipDepend
|
|||||||
BuildOptions.WIN_SIGN_STEP,
|
BuildOptions.WIN_SIGN_STEP,
|
||||||
BuildOptions.MAC_SIGN_STEP,
|
BuildOptions.MAC_SIGN_STEP,
|
||||||
BuildOptions.MAC_NOTARIZE_STEP,
|
BuildOptions.MAC_NOTARIZE_STEP,
|
||||||
|
BuildOptions.MAC_DMG_STEP,
|
||||||
)
|
)
|
||||||
options.buildUnixSnaps = false
|
options.buildUnixSnaps = false
|
||||||
options.outRootDir = outDir
|
options.outRootDir = outDir
|
||||||
options.useCompiledClassesFromProjectOutput = true
|
options.useCompiledClassesFromProjectOutput = true
|
||||||
options.compilationLogEnabled = false
|
options.compilationLogEnabled = false
|
||||||
|
if (testInfo != null && isUnderTeamCity) {
|
||||||
|
options.buildStepListener = BuildStepTeamCityListener(testInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend inline fun createBuildContext(
|
suspend inline fun createBuildContext(
|
||||||
@@ -78,7 +84,7 @@ suspend inline fun createBuildContext(
|
|||||||
fun runTestBuild(
|
fun runTestBuild(
|
||||||
homePath: Path,
|
homePath: Path,
|
||||||
productProperties: ProductProperties,
|
productProperties: ProductProperties,
|
||||||
traceSpanName: String,
|
testInfo: TestInfo,
|
||||||
buildTools: ProprietaryBuildTools,
|
buildTools: ProprietaryBuildTools,
|
||||||
buildOptionsCustomizer: (BuildOptions) -> Unit = {},
|
buildOptionsCustomizer: (BuildOptions) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
@@ -86,7 +92,7 @@ fun runTestBuild(
|
|||||||
homeDir = homePath,
|
homeDir = homePath,
|
||||||
productProperties = productProperties,
|
productProperties = productProperties,
|
||||||
buildTools = buildTools,
|
buildTools = buildTools,
|
||||||
traceSpanName = traceSpanName,
|
testInfo = testInfo,
|
||||||
isReproducibilityTestAllowed = true,
|
isReproducibilityTestAllowed = true,
|
||||||
buildOptionsCustomizer = buildOptionsCustomizer,
|
buildOptionsCustomizer = buildOptionsCustomizer,
|
||||||
)
|
)
|
||||||
@@ -96,28 +102,29 @@ fun runTestBuild(
|
|||||||
homeDir: Path,
|
homeDir: Path,
|
||||||
productProperties: ProductProperties,
|
productProperties: ProductProperties,
|
||||||
buildTools: ProprietaryBuildTools = ProprietaryBuildTools.DUMMY,
|
buildTools: ProprietaryBuildTools = ProprietaryBuildTools.DUMMY,
|
||||||
traceSpanName: String,
|
testInfo: TestInfo,
|
||||||
isReproducibilityTestAllowed: Boolean = true,
|
isReproducibilityTestAllowed: Boolean = true,
|
||||||
build: suspend (context: BuildContext) -> Unit = { buildDistributions(it) },
|
build: suspend (BuildContext) -> Unit = { buildDistributions(it) },
|
||||||
onSuccess: suspend (context: BuildContext) -> Unit = {},
|
onSuccess: suspend (BuildContext) -> Unit = {},
|
||||||
buildOptionsCustomizer: (BuildOptions) -> Unit = {}
|
buildOptionsCustomizer: (BuildOptions) -> Unit = {}
|
||||||
) = runBlocking(Dispatchers.Default) {
|
) = runBlocking(Dispatchers.Default) {
|
||||||
if (isReproducibilityTestAllowed) {
|
if (isReproducibilityTestAllowed && BuildArtifactsReproducibilityTest.isEnabled) {
|
||||||
val reproducibilityTest = BuildArtifactsReproducibilityTest()
|
val reproducibilityTest = BuildArtifactsReproducibilityTest()
|
||||||
repeat(reproducibilityTest.iterations) { iterationNumber ->
|
repeat(reproducibilityTest.iterations) { iterationNumber ->
|
||||||
launch {
|
launch {
|
||||||
val buildContext = BuildContextImpl.createContext(
|
|
||||||
projectHome = homeDir,
|
|
||||||
productProperties = productProperties,
|
|
||||||
proprietaryBuildTools = buildTools,
|
|
||||||
setupTracer = false,
|
|
||||||
options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, customizer = buildOptionsCustomizer).also {
|
|
||||||
reproducibilityTest.configure(it)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
doRunTestBuild(
|
doRunTestBuild(
|
||||||
context = buildContext,
|
context = {
|
||||||
traceSpanName = "#$iterationNumber",
|
BuildContextImpl.createContext(
|
||||||
|
projectHome = homeDir,
|
||||||
|
productProperties = productProperties,
|
||||||
|
proprietaryBuildTools = buildTools,
|
||||||
|
setupTracer = false,
|
||||||
|
options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo, customizer = buildOptionsCustomizer).also {
|
||||||
|
reproducibilityTest.configure(it)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
traceSpanName = "${testInfo.spanName}#$iterationNumber",
|
||||||
writeTelemetry = false,
|
writeTelemetry = false,
|
||||||
build = { context ->
|
build = { context ->
|
||||||
build(context)
|
build(context)
|
||||||
@@ -130,15 +137,17 @@ fun runTestBuild(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
doRunTestBuild(
|
doRunTestBuild(
|
||||||
context = BuildContextImpl.createContext(
|
context = {
|
||||||
projectHome = homeDir,
|
BuildContextImpl.createContext(
|
||||||
productProperties = productProperties,
|
projectHome = homeDir,
|
||||||
proprietaryBuildTools = buildTools,
|
productProperties = productProperties,
|
||||||
setupTracer = false,
|
proprietaryBuildTools = buildTools,
|
||||||
options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, customizer = buildOptionsCustomizer),
|
setupTracer = false,
|
||||||
),
|
options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo, customizer = buildOptionsCustomizer),
|
||||||
|
)
|
||||||
|
},
|
||||||
writeTelemetry = true,
|
writeTelemetry = true,
|
||||||
traceSpanName = traceSpanName,
|
traceSpanName = testInfo.spanName,
|
||||||
build = { context ->
|
build = { context ->
|
||||||
build(context)
|
build(context)
|
||||||
onSuccess(context)
|
onSuccess(context)
|
||||||
@@ -149,33 +158,30 @@ fun runTestBuild(
|
|||||||
|
|
||||||
// FIXME: test reproducibility
|
// FIXME: test reproducibility
|
||||||
suspend fun runTestBuild(
|
suspend fun runTestBuild(
|
||||||
context: BuildContext,
|
testInfo: TestInfo,
|
||||||
traceSpanName: String,
|
context: suspend () -> BuildContext,
|
||||||
build: suspend (context: BuildContext) -> Unit = { buildDistributions(it) }
|
build: suspend (BuildContext) -> Unit = { buildDistributions(it) }
|
||||||
) {
|
) {
|
||||||
doRunTestBuild(context = context, traceSpanName = traceSpanName, writeTelemetry = true, build = build)
|
doRunTestBuild(context = context, traceSpanName = testInfo.spanName, writeTelemetry = true, build = build)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val defaultLogFactory = Logger.getFactory()
|
private val defaultLogFactory = Logger.getFactory()
|
||||||
|
|
||||||
private suspend fun doRunTestBuild(context: BuildContext, traceSpanName: String?, writeTelemetry: Boolean, build: suspend (context: BuildContext) -> Unit) {
|
private suspend fun doRunTestBuild(context: suspend () -> BuildContext, traceSpanName: String, writeTelemetry: Boolean, build: suspend (context: BuildContext) -> Unit) {
|
||||||
context.cleanupJarCache()
|
var outDir: Path? = null
|
||||||
|
var traceFile: Path? = null
|
||||||
val traceFile = if (writeTelemetry) {
|
|
||||||
val traceFile = TestLoggerFactory.getTestLogDir().resolve("${context.productProperties.baseFileName}-$traceSpanName-trace.json")
|
|
||||||
JaegerJsonSpanExporterManager.setOutput(traceFile, addShutDownHook = false)
|
|
||||||
traceFile
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val outDir = context.paths.buildOutputDir
|
|
||||||
var error: Throwable? = null
|
var error: Throwable? = null
|
||||||
try {
|
try {
|
||||||
spanBuilder(traceSpanName ?: "test build of ${context.productProperties.baseFileName}")
|
spanBuilder(traceSpanName).useWithScope { span ->
|
||||||
.setAttribute("outDir", outDir.toString())
|
val context = context()
|
||||||
.useWithScope { span ->
|
context.cleanupJarCache()
|
||||||
|
outDir = context.paths.buildOutputDir
|
||||||
|
span.setAttribute("outDir", "$outDir")
|
||||||
|
if (writeTelemetry) {
|
||||||
|
traceFile = TestLoggerFactory.getTestLogDir().resolve("${context.productProperties.baseFileName}-$traceSpanName-trace.json").also {
|
||||||
|
JaegerJsonSpanExporterManager.setOutput(it, addShutDownHook = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
build(context)
|
build(context)
|
||||||
val jetBrainsClientMainModule = context.productProperties.embeddedJetBrainsClientMainModule
|
val jetBrainsClientMainModule = context.productProperties.embeddedJetBrainsClientMainModule
|
||||||
@@ -203,7 +209,11 @@ private suspend fun doRunTestBuild(context: BuildContext, traceSpanName: String?
|
|||||||
error = e
|
error = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
finally {
|
||||||
|
// close debug logging to prevent locking of the output directory on Windows
|
||||||
|
context.messages.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
closeKtorClient()
|
closeKtorClient()
|
||||||
@@ -213,16 +223,13 @@ private suspend fun doRunTestBuild(context: BuildContext, traceSpanName: String?
|
|||||||
println("Performance report is written to $traceFile")
|
println("Performance report is written to $traceFile")
|
||||||
}
|
}
|
||||||
|
|
||||||
// close debug logging to prevent locking of output directory on Windows
|
|
||||||
context.messages.close()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden in [org.jetbrains.intellij.build.impl.JpsCompilationRunner.runBuild]
|
* Overridden in [org.jetbrains.intellij.build.impl.JpsCompilationRunner.runBuild]
|
||||||
*/
|
*/
|
||||||
Logger.setFactory(defaultLogFactory)
|
Logger.setFactory(defaultLogFactory)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
NioFiles.deleteRecursively(outDir)
|
outDir?.also(NioFiles::deleteRecursively)
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
System.err.println("cannot cleanup $outDir:")
|
System.err.println("cannot cleanup $outDir:")
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.jetbrains.intellij.build.pycharm
|
|||||||
|
|
||||||
import com.intellij.openapi.application.PathManager
|
import com.intellij.openapi.application.PathManager
|
||||||
import com.intellij.platform.buildScripts.testFramework.runTestBuild
|
import com.intellij.platform.buildScripts.testFramework.runTestBuild
|
||||||
import com.intellij.platform.buildScripts.testFramework.spanName
|
|
||||||
import com.intellij.util.io.Compressor
|
import com.intellij.util.io.Compressor
|
||||||
import org.jetbrains.intellij.build.BuildOptions
|
import org.jetbrains.intellij.build.BuildOptions
|
||||||
import org.jetbrains.intellij.build.dependencies.BuildDependenciesCommunityRoot
|
import org.jetbrains.intellij.build.dependencies.BuildDependenciesCommunityRoot
|
||||||
@@ -42,7 +41,7 @@ class PyCharmCommunityBuildTest {
|
|||||||
val communityHomePath = BuildDependenciesCommunityRoot(homePath.resolve("community"))
|
val communityHomePath = BuildDependenciesCommunityRoot(homePath.resolve("community"))
|
||||||
runTestBuild(
|
runTestBuild(
|
||||||
homeDir = communityHomePath.communityRoot,
|
homeDir = communityHomePath.communityRoot,
|
||||||
traceSpanName = testInfo.spanName,
|
testInfo = testInfo,
|
||||||
productProperties = PyCharmCommunityProperties(communityHomePath.communityRoot),
|
productProperties = PyCharmCommunityProperties(communityHomePath.communityRoot),
|
||||||
) {
|
) {
|
||||||
it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY)
|
it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY)
|
||||||
|
|||||||
Reference in New Issue
Block a user