From 3857ca8dff01030e13de83319e7eef00878a37b0 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Fri, 13 Jun 2025 09:30:15 +0200 Subject: [PATCH] [build script tests] check that cross-platform distribution builds successfully for IDEA Community We had several cases in the past when Installers build failed because of problems with the cross-platform distribution. Now IdeaCommunityBuildTest will check that it builds successfully. This additional step takes noticeable time, so currently it isn't enabled for build tests of other products. An additional BuildOptions.WINDOWS_ARTIFACTS_STEP is added to allow skipping building all Windows artifacts, including .zip archive. GitOrigin-RevId: d248f233c683d4d4b55cebf19025d3b4704e148f --- .../intellij/build/IdeaCommunityBuildTest.kt | 4 +-- .../jetbrains/intellij/build/BuildOptions.kt | 3 ++ .../build/impl/WindowsDistributionBuilder.kt | 5 ++- .../testFramework/buildScriptTestUtils.kt | 36 ++++++++++++++----- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/build/tests/testSrc/org/jetbrains/intellij/build/IdeaCommunityBuildTest.kt b/build/tests/testSrc/org/jetbrains/intellij/build/IdeaCommunityBuildTest.kt index 303716cea0ba..de23f91f033f 100644 --- a/build/tests/testSrc/org/jetbrains/intellij/build/IdeaCommunityBuildTest.kt +++ b/build/tests/testSrc/org/jetbrains/intellij/build/IdeaCommunityBuildTest.kt @@ -11,7 +11,6 @@ import org.jetbrains.intellij.build.BuildPaths.Companion.COMMUNITY_ROOT import org.jetbrains.intellij.build.impl.BuildContextImpl import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInfo -import kotlin.io.path.Path class IdeaCommunityBuildTest { @Test @@ -22,6 +21,7 @@ class IdeaCommunityBuildTest { homeDir = COMMUNITY_ROOT.communityRoot, testInfo = testInfo, productProperties = productProperties, + buildCrossPlatformDistribution = true, ) { it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY) ?: "$homePath/out/classes" } @@ -33,7 +33,7 @@ class IdeaCommunityBuildTest { runBlocking(Dispatchers.Default) { runTestBuild(testInfo, context = { val productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot) - val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homePath, skipDependencySetup = true, testInfo) + val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homePath, skipDependencySetup = true, testInfo = testInfo) BuildContextImpl.createContext( projectHome = homePath, productProperties = productProperties, diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/BuildOptions.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/BuildOptions.kt index a19b13a9307e..666470a0e7ec 100644 --- a/platform/build-scripts/src/org/jetbrains/intellij/build/BuildOptions.kt +++ b/platform/build-scripts/src/org/jetbrains/intellij/build/BuildOptions.kt @@ -172,6 +172,9 @@ data class BuildOptions( /** Build Linux tar.gz artifact without bundled Runtime. */ const val LINUX_TAR_GZ_WITHOUT_BUNDLED_RUNTIME_STEP: String = "linux_tar_gz_without_jre" + /** Build Windows artifacts: .zip archive and .exe installer. */ + const val WINDOWS_ARTIFACTS_STEP: String = "windows_artifacts" + /** Build *.exe installer for Windows distribution. If skipped, only the .zip archive will be produced. */ const val WINDOWS_EXE_INSTALLER_STEP: String = "windows_exe_installer" diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.kt index 93fce19c198d..46a26aaacc10 100644 --- a/platform/build-scripts/src/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.kt +++ b/platform/build-scripts/src/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.kt @@ -13,7 +13,6 @@ import io.opentelemetry.api.trace.Span import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.NonCancellable -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit @@ -144,7 +143,7 @@ internal class WindowsDistributionBuilder( } copyFileToDir(vcRtDll, osAndArchSpecificDistPath.resolve("bin")) - val (zipWithJbrPath, exePath) = coroutineScope { + val (zipWithJbrPath, exePath) = context.executeStep(spanBuilder("build Windows artefacts"), stepId = BuildOptions.WINDOWS_ARTIFACTS_STEP) { var zipWithJbrPath: Path? = null var exePath: Path? = null @@ -175,7 +174,7 @@ internal class WindowsDistributionBuilder( } zipWithJbrPath to exePath - } + } ?: (null to null) if (zipWithJbrPath != null && exePath != null) { if (context.options.isInDevelopmentMode) { diff --git a/platform/build-scripts/testFramework/src/com/intellij/platform/buildScripts/testFramework/buildScriptTestUtils.kt b/platform/build-scripts/testFramework/src/com/intellij/platform/buildScripts/testFramework/buildScriptTestUtils.kt index 011ff3813ee7..4888bc7cd815 100644 --- a/platform/build-scripts/testFramework/src/com/intellij/platform/buildScripts/testFramework/buildScriptTestUtils.kt +++ b/platform/build-scripts/testFramework/src/com/intellij/platform/buildScripts/testFramework/buildScriptTestUtils.kt @@ -35,7 +35,14 @@ import java.net.http.HttpConnectTimeoutException import java.nio.file.Files import java.nio.file.Path -fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, skipDependencySetup: Boolean = false, testInfo: TestInfo? = null): BuildOptions { +fun createBuildOptionsForTest( + productProperties: ProductProperties, + homeDir: Path, + skipDependencySetup: Boolean = false, + buildCrossPlatformDistribution: Boolean = false, + testInfo: TestInfo? = null, +): BuildOptions { + val outDir = createTestBuildOutDir(productProperties) val options = BuildOptions( cleanOutDir = false, @@ -43,7 +50,7 @@ fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Pat jarCacheDir = homeDir.resolve("out/dev-run/jar-cache"), buildDateInSeconds = getDevModeOrTestBuildDateInSeconds(), ) - customizeBuildOptionsForTest(options = options, outDir = outDir, skipDependencySetup = skipDependencySetup, testInfo = testInfo) + customizeBuildOptionsForTest(options = options, outDir = outDir, skipDependencySetup = skipDependencySetup, buildCrossPlatformDistribution = buildCrossPlatformDistribution, testInfo = testInfo) return options } @@ -51,25 +58,35 @@ fun createTestBuildOutDir(productProperties: ProductProperties): Path { return Files.createTempDirectory("test-build-${productProperties.baseFileName}") } -private inline fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, testInfo: TestInfo, customizer: (BuildOptions) -> Unit): BuildOptions { - val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo) +private inline fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, testInfo: TestInfo, buildCrossPlatformDistribution: Boolean, customizer: (BuildOptions) -> Unit): BuildOptions { + val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo, buildCrossPlatformDistribution = buildCrossPlatformDistribution) customizer(options) return options } -fun customizeBuildOptionsForTest(options: BuildOptions, outDir: Path, skipDependencySetup: Boolean = false, testInfo: TestInfo?) { +fun customizeBuildOptionsForTest(options: BuildOptions, outDir: Path, skipDependencySetup: Boolean = false, buildCrossPlatformDistribution: Boolean = false, testInfo: TestInfo?) { options.skipDependencySetup = skipDependencySetup options.isTestBuild = true options.buildStepsToSkip += listOf( BuildOptions.LIBRARY_URL_CHECK_STEP, BuildOptions.TEAMCITY_ARTIFACTS_PUBLICATION_STEP, - BuildOptions.OS_SPECIFIC_DISTRIBUTIONS_STEP, BuildOptions.LINUX_TAR_GZ_WITHOUT_BUNDLED_RUNTIME_STEP, BuildOptions.WIN_SIGN_STEP, BuildOptions.MAC_SIGN_STEP, BuildOptions.MAC_NOTARIZE_STEP, BuildOptions.MAC_DMG_STEP, ) + if (buildCrossPlatformDistribution) { + //to build cross-platform distribution, we need to copy OS-specific files, but there is no need to build actual OS-specific archives + options.buildStepsToSkip += listOf( + BuildOptions.LINUX_ARTIFACTS_STEP, + BuildOptions.MAC_ARTIFACTS_STEP, + BuildOptions.WINDOWS_ARTIFACTS_STEP, + ) + } + else { + options.buildStepsToSkip += listOf(BuildOptions.OS_SPECIFIC_DISTRIBUTIONS_STEP) + } options.buildUnixSnaps = false options.outRootDir = outDir options.useCompiledClassesFromProjectOutput = true @@ -114,6 +131,7 @@ fun runTestBuild( buildTools: ProprietaryBuildTools = ProprietaryBuildTools.DUMMY, isReproducibilityTestAllowed: Boolean = true, checkIntegrityOfEmbeddedFrontend: Boolean = true, + buildCrossPlatformDistribution: Boolean = false, build: suspend (BuildContext) -> Unit = { buildDistributions(context = it) }, onSuccess: suspend (BuildContext) -> Unit = {}, buildOptionsCustomizer: (BuildOptions) -> Unit = {} @@ -128,7 +146,8 @@ fun runTestBuild( productProperties, setupTracer = false, buildTools, - createBuildOptionsForTest(productProperties, homeDir, testInfo, buildOptionsCustomizer).also { + createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo, + buildCrossPlatformDistribution = buildCrossPlatformDistribution, customizer = buildOptionsCustomizer).also { reproducibilityTest.configure(it) } ), @@ -151,7 +170,8 @@ fun runTestBuild( productProperties = productProperties, setupTracer = false, proprietaryBuildTools = buildTools, - options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo, customizer = buildOptionsCustomizer), + options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo, + buildCrossPlatformDistribution = buildCrossPlatformDistribution, customizer = buildOptionsCustomizer), ), writeTelemetry = true, checkIntegrityOfEmbeddedFrontend = checkIntegrityOfEmbeddedFrontend,