From 41e46de336f9a79d813963614d6019fdd272d8c0 Mon Sep 17 00:00:00 2001 From: Gary Hale Date: Wed, 3 Sep 2025 12:40:19 -0400 Subject: [PATCH 01/11] Update to latest Gradle nightly and latest version of unified plugins --- build-logic/plugins/build.gradle.dcl | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 45457 -> 45632 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build-logic/plugins/build.gradle.dcl b/build-logic/plugins/build.gradle.dcl index cce765f..9391677 100644 --- a/build-logic/plugins/build.gradle.dcl +++ b/build-logic/plugins/build.gradle.dcl @@ -2,7 +2,7 @@ javaGradlePlugin { description = "Declarative plugins containing custom software types for the gradle-client project." dependencies { - api("org.gradle.experimental.kmp-ecosystem:org.gradle.experimental.kmp-ecosystem.gradle.plugin:0.1.45") + api("org.gradle.experimental.kmp-ecosystem:org.gradle.experimental.kmp-ecosystem.gradle.plugin:0.1.46") api("org.jetbrains.kotlin.multiplatform:org.jetbrains.kotlin.multiplatform.gradle.plugin:2.2.0") api("org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin:2.2.0") api("org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:2.2.0") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75ab801e22807dde59e12a8735a34077..53dfafe38f9fbed2186f5c17f22c0fec2f2f6223 100644 GIT binary patch delta 4530 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 Zlc=#x0&1O;0j(9246-f;Yoq`G004E@V+H^K diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 72039fc..73b778a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-9.2.0-branch-sigushkinDeclarativeComposability-20250818215312+0000-bin.zip +distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-9.2.0-20250903110058+0000-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From e7201cfd8b518f8735fe7a8832c6221e50406d8f Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 9 Sep 2025 17:14:02 +0100 Subject: [PATCH 02/11] Display error messages from the DCL analyzer in popups --- build-logic/gradle.properties | 1 + .../client/core/gradle/dcl/DocumentUtils.kt | 12 +++- .../client/core/gradle/dcl/ErrorUtil.kt | 59 +++++++++++++++++++ .../client/ui/composables/SourcesColumn.kt | 24 ++++++-- .../org/gradle/client/ui/composables/Texts.kt | 55 ++++++++++++++--- .../connected/actions/GetDeclarativeSchema.kt | 2 +- .../GetDeclarativeDocuments.kt | 31 +++++++--- .../GetDeclarativeDocumentsModel.kt | 9 +++ .../ModelTreeRendering.kt | 44 +++++++++----- 9 files changed, 198 insertions(+), 39 deletions(-) create mode 100644 build-logic/gradle.properties create mode 100644 gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt diff --git a/build-logic/gradle.properties b/build-logic/gradle.properties new file mode 100644 index 0000000..110c610 --- /dev/null +++ b/build-logic/gradle.properties @@ -0,0 +1 @@ +org.gradle.kotlin.dsl.dcl=true \ No newline at end of file diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/DocumentUtils.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/DocumentUtils.kt index 9aeda49..b932868 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/DocumentUtils.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/DocumentUtils.kt @@ -21,10 +21,16 @@ fun DeclarativeDocument.relevantRange(): IntRange { return IntRange(first.sourceData.indexRange.first, last.sourceData.indexRange.last) } -fun DocumentWithResolution.errorRanges(): List = +data class ErrorData( + val range: IntRange, + val documentNode: DeclarativeDocument.Node, + val resolution: DocumentResolution.UnsuccessfulResolution +) + +fun DocumentWithResolution.errorRanges(): List = resolutionContainer.collectToMap(document).entries .filter { it.value is DocumentResolution.UnsuccessfulResolution } - .map { it.key.sourceData.indexRange } + .map { ErrorData(it.key.sourceData.indexRange, it.key, it.value as DocumentResolution.UnsuccessfulResolution) } fun DeclarativeDocument.nodeAt(fileIdentifier: String, offset: Int): DeclarativeDocument.DocumentNode? { var node: DeclarativeDocument.DocumentNode? = null @@ -155,5 +161,5 @@ internal fun DocumentResolutionContainer.isUnresolvedBase(node: DeclarativeDocum is DeclarativeDocument.DocumentNode -> data(node) is DeclarativeDocument.ValueNode -> data(node) } - return resolution is DocumentResolution.UnsuccessfulResolution && resolution.reasons != listOf(UnresolvedBase) + return resolution is DocumentResolution.UnsuccessfulResolution && resolution.reasons == listOf(UnresolvedBase) } diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt new file mode 100644 index 0000000..a49bb56 --- /dev/null +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt @@ -0,0 +1,59 @@ +package org.gradle.client.core.gradle.dcl + +import org.gradle.internal.declarativedsl.dom.AmbiguousName +import org.gradle.internal.declarativedsl.dom.BlockMismatch +import org.gradle.internal.declarativedsl.dom.CrossScopeAccess +import org.gradle.internal.declarativedsl.dom.DeclarativeDocument +import org.gradle.internal.declarativedsl.dom.DocumentResolution +import org.gradle.internal.declarativedsl.dom.IllegalAugmentedAssignment +import org.gradle.internal.declarativedsl.dom.IsError +import org.gradle.internal.declarativedsl.dom.NonEnumValueNamedReference +import org.gradle.internal.declarativedsl.dom.NotAssignable +import org.gradle.internal.declarativedsl.dom.OpaqueValueInIdentityKey +import org.gradle.internal.declarativedsl.dom.SyntaxError +import org.gradle.internal.declarativedsl.dom.UnresolvedBase +import org.gradle.internal.declarativedsl.dom.UnresolvedName +import org.gradle.internal.declarativedsl.dom.UnresolvedSignature +import org.gradle.internal.declarativedsl.dom.UnresolvedValueUsed +import org.gradle.internal.declarativedsl.dom.UnsupportedKotlinFeature +import org.gradle.internal.declarativedsl.dom.UnsupportedSyntax +import org.gradle.internal.declarativedsl.dom.ValueTypeMismatch + +@Suppress("CyclomaticComplexMethod") +fun userFriendlyErrorMessages( + node: DeclarativeDocument.Node, + unsuccessfulResolution: DocumentResolution.UnsuccessfulResolution +): List = unsuccessfulResolution.reasons.flatMap { reason -> + when (reason) { + AmbiguousName -> listOf("Ambiguous name") + BlockMismatch -> if (node is DeclarativeDocument.DocumentNode.ElementNode) { + if (node.content.isEmpty()) + listOf("Block expected for element ${node.name}") + else listOf("Block not expected for element ${node.name}") + } else listOf("Block mismatch") + + CrossScopeAccess -> listOf("Cross-scope access") + + IsError -> if (node is DeclarativeDocument.DocumentNode.ErrorNode) { + node.errors.map { error -> + when (error) { + is SyntaxError -> "Syntax error: ${error.parsingError.message}" + is UnsupportedKotlinFeature -> + "Unsupported language feature: ${error.unsupportedConstruct.languageFeature}" + is UnsupportedSyntax -> "Unsupported syntax: ${error.cause}" + } + } + } else listOf("Syntax error") + + OpaqueValueInIdentityKey -> listOf("Opaque value passed as identity key") + UnresolvedName -> listOf("Unresolved name") + UnresolvedSignature -> listOf("Unresolved function signature") + IllegalAugmentedAssignment -> listOf("Illegal augmented assignment") + NotAssignable -> listOf("Cannot assign property") + UnresolvedValueUsed -> listOf("Assigned value is not resolved") + ValueTypeMismatch -> listOf("Value type mismatch") + NonEnumValueNamedReference -> listOf("Illegal named reference. Only enum entries can be referenced by name") + + UnresolvedBase -> emptyList() + } +} \ No newline at end of file diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/SourcesColumn.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/SourcesColumn.kt index 2d91f78..c436384 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/SourcesColumn.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/SourcesColumn.kt @@ -18,6 +18,8 @@ import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration +import org.gradle.client.core.gradle.dcl.ErrorData +import org.gradle.client.core.gradle.dcl.userFriendlyErrorMessages import org.gradle.client.ui.connected.actions.declarativedocuments.HighlightingEntry import org.gradle.client.ui.theme.spacing import org.gradle.client.ui.theme.transparency @@ -26,7 +28,8 @@ internal data class SourceFileViewInput( val fileIdentifier: String, val fileContent: String, val relevantIndicesRange: IntRange?, - val errorRanges: List, + val allErrorRanges: List, + val selectedErrorRanges: List, val highlightedSourceRange: List ) @@ -50,7 +53,7 @@ internal fun SourcesColumn( val highlightedString = sourceFileAnnotatedString( highlightedRangeOrNull, - sourceFileViewInput.errorRanges, + sourceFileViewInput.allErrorRanges.map { it.range }, sourceFileViewInput.fileContent ) @@ -61,7 +64,8 @@ internal fun SourcesColumn( SourceFileData( identifier, highlightedString, - relevantHighlightedString + relevantHighlightedString, + sourceFileViewInput.selectedErrorRanges ) } } @@ -71,6 +75,7 @@ internal fun SourcesColumn( data.relativePath, data.annotatedSource, data.trimmedSource, + data.selectedErrorRanges, onClick ) MaterialTheme.spacing.VerticalLevel4() @@ -82,7 +87,8 @@ internal fun SourcesColumn( private data class SourceFileData( val relativePath: String, val annotatedSource: AnnotatedString, - val trimmedSource: TrimmedText? + val trimmedSource: TrimmedText?, + val selectedErrorRanges: List ) private fun sourceFileAnnotatedString( @@ -109,8 +115,13 @@ private fun SourceFileTitleAndText( fileRelativePath: String, highlightedSource: AnnotatedString, trimmedSource: TrimmedText?, + selectedErrors: List?, onClick: (String, Int) -> Unit ) { + val errorPopupText = selectedErrors?.takeIf { it.isNotEmpty() }?.let { + it.flatMap { userFriendlyErrorMessages(it.documentNode, it.resolution) }.joinToString("\n") + } + if (trimmedSource != null) { var isTrimmed by remember { mutableStateOf(true) } @@ -130,7 +141,8 @@ private fun SourceFileTitleAndText( MaterialTheme.spacing.VerticalLevel2() CodeBlock( Modifier.fillMaxWidth(), - if (isTrimmed) trimmedSource.annotatedString else highlightedSource + if (isTrimmed) trimmedSource.annotatedString else highlightedSource, + errorPopupText ) { clickOffset -> val originalOffset = if (isTrimmed) trimmedSource.mapIndexToIndexInOriginalText(clickOffset) @@ -141,7 +153,7 @@ private fun SourceFileTitleAndText( } else { TitleMedium(fileRelativePath) MaterialTheme.spacing.VerticalLevel4() - CodeBlock(Modifier.fillMaxWidth(), highlightedSource) { clickOffset -> + CodeBlock(Modifier.fillMaxWidth(), highlightedSource, errorPopupText) { clickOffset -> onClick(fileRelativePath, clickOffset) } } diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt index b73256b..5dc8d3a 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt @@ -1,16 +1,32 @@ package org.gradle.client.ui.composables +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.ClickableText +import androidx.compose.foundation.text2.input.maxLengthInChars import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp import org.gradle.client.ui.theme.spacing import org.gradle.client.ui.theme.transparency @@ -81,23 +97,48 @@ fun HeadlineSmall(text: String, modifier: Modifier = Modifier) { fun CodeBlock( modifier: Modifier = Modifier, code: AnnotatedString, + popup: String?, onClick: (Int) -> Unit = {}, ) { + var boxSize by remember { mutableStateOf(IntSize.Zero) } Surface( tonalElevation = MaterialTheme.spacing.level1, color = MaterialTheme.colorScheme.surface, contentColor = MaterialTheme.colorScheme.onSurface, shape = MaterialTheme.shapes.extraSmall, - modifier = modifier + modifier = modifier.onSizeChanged { boxSize = it } ) { - ClickableText( - text = code, - modifier = Modifier.padding(MaterialTheme.spacing.level2), - style = MaterialTheme.typography.labelMedium.copy(fontFamily = FontFamily.Monospace), - onClick = onClick, - ) + Box { + ClickableText( + text = code, + modifier = Modifier.padding(MaterialTheme.spacing.level2), + style = MaterialTheme.typography.labelMedium.copy(fontFamily = FontFamily.Monospace), + onClick = onClick, + ) + Box( + modifier = + Modifier + .padding(bottom = 8.dp) + .background(MaterialTheme.colorScheme.background) + .width(boxSize.width.toDp() - 8.dp) + .align(Alignment.BottomCenter) + .shadow(2.dp) + .animateContentSize() + ) { + if (popup != null) { + Text( + text = popup, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.padding(8.dp) + ) + } + } + } } } +@Composable +fun Int.toDp() = with(LocalDensity.current) { this@toDp.toDp() } + fun Modifier.semiTransparentIfNull(any: Any?) = if (any == null) alpha(MaterialTheme.transparency.HALF) else this diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetDeclarativeSchema.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetDeclarativeSchema.kt index 72b7f41..2543556 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetDeclarativeSchema.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetDeclarativeSchema.kt @@ -41,7 +41,7 @@ class GetDeclarativeSchema : GetModelAction { val description = buildString { appendDescription(hashSetOf(), model.projectSchema, softwareTypeSchema) } - CodeBlock(Modifier.fillMaxWidth(), buildAnnotatedString { append(description) }) + CodeBlock(Modifier.fillMaxWidth(), buildAnnotatedString { append(description) }, null) } private val indentChars = " " diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt index add3a2f..5f7e666 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt @@ -8,6 +8,10 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.PointerIcon import androidx.compose.ui.input.pointer.pointerHoverIcon +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.gradle.client.build.action.GetResolvedDomAction import org.gradle.client.build.model.ResolvedDomPrerequisites import org.gradle.client.core.gradle.dcl.* @@ -24,10 +28,7 @@ import org.gradle.client.ui.theme.spacing import org.gradle.internal.declarativedsl.analysis.TypeRefContext import org.gradle.internal.declarativedsl.dom.DeclarativeDocument import org.gradle.internal.declarativedsl.dom.data.collectToMap -import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayNodeOrigin.FromOverlay -import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayNodeOrigin.FromUnderlay -import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayNodeOrigin.MergedElements -import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayNodeOrigin.MergedProperties +import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayNodeOrigin.* import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayOriginContainer import org.gradle.internal.declarativedsl.dom.resolution.DocumentResolutionContainer import org.gradle.internal.declarativedsl.evaluator.main.AnalysisDocumentUtils.resolvedDocument @@ -35,6 +36,7 @@ import org.gradle.internal.declarativedsl.evaluator.runner.stepResultOrPartialRe import org.gradle.tooling.BuildAction import org.jetbrains.skiko.Cursor import java.io.File +import kotlin.time.Duration.Companion.seconds class GetDeclarativeDocuments : GetModelAction.GetCompositeModelAction { @@ -196,6 +198,8 @@ class GetDeclarativeDocuments : GetModelAction.GetCompositeModelAction()) + private val _reportedErrors = mutableStateOf(emptyMap>()) private fun readDocumentFile() = _selectedDocument.value.takeIf { it.canRead() }?.readText().orEmpty() private fun readSettingsFile() = model.settingsFile.takeIf { it.canRead() }?.readText().orEmpty() @@ -29,13 +31,20 @@ internal class GetDeclarativeDocumentsModel(private val model: ResolvedDomPrereq fun isViewingSettings() = selectedDocument.value == model.settingsFile val highlightedSourceRangeByFileId: State> get() = _highlightedSourceRangeByFileId + val reportedErrors: State>> get() = _reportedErrors fun clearHighlighting() { _highlightedSourceRangeByFileId.value = emptyList() + _reportedErrors.value = emptyMap() } fun setHighlightingRanges(entries: List) { _highlightedSourceRangeByFileId.value = entries + _reportedErrors.value = emptyMap() + } + + fun reportErrors(errorsByFileId: Map>) { + _reportedErrors.value = errorsByFileId } fun selectDocument(file: File) { diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/ModelTreeRendering.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/ModelTreeRendering.kt index 68f1619..9baa2cc 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/ModelTreeRendering.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/ModelTreeRendering.kt @@ -233,6 +233,9 @@ internal class ModelTreeRendering( } else { if (propertyNodes.size > 1) { propertyNodes.forEach { propertyNode -> + val itemDecoration = maybeInvalidDecoration( + resolutionContainer.data(propertyNode) !is PropertyAssignmentResolved + ) WithDecoration(propertyNode, highlightingTarget = DOCUMENT_NODE) { Column { if (propertyNode.hasValuePresentation()) { @@ -243,7 +246,7 @@ internal class ModelTreeRendering( PropertyAssignmentOrAugmentationItem( propertyNode, representativeNode, - maybeInvalidDecoration + itemDecoration ) } } @@ -499,6 +502,31 @@ internal fun highlightingForAllDocumentNodesByModelNode( is DeclarativeDocument.DocumentNode -> overlayOriginContainer.data(node) is DeclarativeDocument.ValueNode -> overlayOriginContainer.data(node) } + + val shadowedValueNodes = run { + val propertyNodes = when (origin) { + is MergedProperties -> + (origin.effectivePropertiesFromUnderlay + origin.effectivePropertiesFromOverlay).toList() + is FromUnderlay -> listOf(origin.documentNode) + is FromOverlay -> listOf(origin.documentNode) + is MergedElements -> emptyList() + } + + val valuePresentation = if (node is PropertyNode) + findValuePresenter(resolutionContainer, typeRefContext, node) + else null + + valuePresentation?.jointAssignedValuesPresentation( + propertyNodes.filterIsInstance(), + resolutionContainer + )?.flatMap { + it.value.valueNodeEntries + .filter { item -> !item.isEffectiveItem } + .map { item -> item.fullValueNode } + } + } + + return when (origin) { is FromOverlay, is FromUnderlay -> listOf(node.highlightAs(EFFECTIVE, MODEL_NODE)) @@ -512,20 +540,6 @@ internal fun highlightingForAllDocumentNodesByModelNode( // In addition to the full property nodes that are shadowed according to the DOM overlay, // if there is an element comprehension for this property, // also highlight the shadowed elements: - val shadowedValueNodes = run { - val valuePresentation = if (node is PropertyNode) - findValuePresenter(resolutionContainer, typeRefContext, node) - else null - - valuePresentation?.jointAssignedValuesPresentation( - (origin.effectivePropertiesFromUnderlay + origin.effectivePropertiesFromOverlay).toList(), - resolutionContainer - )?.flatMap { - it.value.valueNodeEntries - .filter { item -> !item.isEffectiveItem } - .map { item -> item.fullValueNode } - } - } (origin.effectivePropertiesFromOverlay + origin.effectivePropertiesFromUnderlay).map { it.highlightAs(EFFECTIVE, MODEL_NODE) From b76e07685853c32739b64d62818e6bf518246ef2 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Thu, 18 Sep 2025 22:12:13 +0300 Subject: [PATCH 03/11] Add features and project types info to the document view --- gradle-client/build.gradle.dcl | 6 ++-- .../client/core/gradle/dcl/ErrorUtil.kt | 2 +- .../org/gradle/client/ui/composables/Texts.kt | 11 +++++++ .../GetDeclarativeDocuments.kt | 7 ++-- .../ModelTreeRendering.kt | 32 +++++++++++++++++++ 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/gradle-client/build.gradle.dcl b/gradle-client/build.gradle.dcl index 38923a7..0d8c2e8 100644 --- a/gradle-client/build.gradle.dcl +++ b/gradle-client/build.gradle.dcl @@ -36,9 +36,9 @@ kotlinApplication { implementation("org.slf4j:slf4j-api:2.0.14") implementation("ch.qos.logback:logback-classic:1.5.6") - implementation("org.gradle:gradle-declarative-dsl-core:9.0-milestone-1") - implementation("org.gradle:gradle-declarative-dsl-evaluator:9.0-milestone-1") - implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.0-milestone-1") + implementation("org.gradle:gradle-declarative-dsl-core:9.2.0-milestone-1") + implementation("org.gradle:gradle-declarative-dsl-evaluator:9.2.0-milestone-1") + implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.2.0-milestone-1") runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.8.1") diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt index a49bb56..e15b649 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/core/gradle/dcl/ErrorUtil.kt @@ -56,4 +56,4 @@ fun userFriendlyErrorMessages( UnresolvedBase -> emptyList() } -} \ No newline at end of file +} diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt index 5dc8d3a..421ba20 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/composables/Texts.kt @@ -1,3 +1,5 @@ +@file:Suppress("TooManyFunctions") + package org.gradle.client.ui.composables import androidx.compose.animation.animateContentSize @@ -57,6 +59,15 @@ fun TitleSmall(text: String, modifier: Modifier = Modifier) { ) } +@Composable +fun TitleSmall(text: AnnotatedString, modifier: Modifier = Modifier) { + Text( + modifier = modifier, + text = text, + style = MaterialTheme.typography.titleSmall, + ) +} + @Composable fun BodyMedium(text: String, modifier: Modifier = Modifier) { Text( diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt index 5f7e666..7f7c27e 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/declarativedocuments/GetDeclarativeDocuments.kt @@ -27,6 +27,7 @@ import org.gradle.client.ui.connected.actions.declarativedocuments.HighlightingT import org.gradle.client.ui.theme.spacing import org.gradle.internal.declarativedsl.analysis.TypeRefContext import org.gradle.internal.declarativedsl.dom.DeclarativeDocument +import org.gradle.internal.declarativedsl.dom.DocumentResolution.ElementResolution.SuccessfulElementResolution import org.gradle.internal.declarativedsl.dom.data.collectToMap import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayNodeOrigin.* import org.gradle.internal.declarativedsl.dom.operations.overlay.OverlayOriginContainer @@ -164,7 +165,7 @@ class GetDeclarativeDocuments : GetModelAction.GetCompositeModelAction + metadata as SoftwareFeatureOrigin + TitleSmall( + buildAnnotatedString { + val isProjectType = metadata.targetDefinitionClassName == "org.gradle.api.Project" + val featureKind = when { + isProjectType -> "" + else -> "feature " + } + append("(${featureKind}from plugin ") + withStyle(style = SpanStyle(fontFamily = FontFamily.Monospace)) { + append("${metadata.ecosystemPluginId}") + } + append(")") + }, + modifier = modifier.padding(start = indentDp) + ) + } + } + @Composable private fun PropertyInfo( From f37c786b8d92534e669f08d6bc2f7123079da153 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Thu, 18 Sep 2025 22:55:53 +0300 Subject: [PATCH 04/11] Refactor model actions into grouped collections --- .../client/ui/connected/ConnectedComponent.kt | 31 +++++++++++++------ .../client/ui/connected/ConnectedContent.kt | 30 +++++++++++------- .../gradle/client/ui/GradleClientUiTest.kt | 12 ++++--- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt index cd06cd9..256f8fe 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt @@ -45,6 +45,11 @@ sealed interface Outcome { data class Failure(val exception: Exception) : Outcome } +data class ModelActionGroup( + val name: String, + val modelActions: List> +) + class ConnectedComponent( context: ComponentContext, private val appDispatchers: AppDispatchers, @@ -55,15 +60,20 @@ class ConnectedComponent( private val mutableModel = MutableValue(ConnectionModel.Connecting) val model: Value = mutableModel - val modelActions = listOf( - GetBuildEnvironment(), - GetGradleBuild(), - GetGradleProject(), - GetDeclarativeSchema(), - GetDeclarativeDocuments(), - GetKotlinBaseDslScriptModel(), - GetResilientGradleBuild(), - GetResilientKotlinDslScriptsModel(), + val modelActionGroups = listOf( + ModelActionGroup( + "Build and project", + listOf(GetBuildEnvironment(), GetGradleBuild(), GetGradleProject()) + ), + ModelActionGroup( + "Declarative Gradle", + listOf(GetDeclarativeSchema(), GetDeclarativeDocuments()) + ), + ModelActionGroup( + "Kotlin DSL", + listOf(GetKotlinBaseDslScriptModel(), GetResilientGradleBuild(), GetResilientKotlinDslScriptsModel()) + ) + ) private val scope = coroutineScope(appDispatchers.main + SupervisorJob()) @@ -203,7 +213,8 @@ class ConnectedComponent( @Suppress("UNCHECKED_CAST") fun actionFor(model: T): GetModelAction? = - modelActions.find { it.modelType.java.isAssignableFrom(model::class.java) } as? GetModelAction + modelActionGroups.flatMap { it.modelActions } + .find { it.modelType.java.isAssignableFrom(model::class.java) } as? GetModelAction fun onCloseClicked() { onFinished() diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedContent.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedContent.kt index 5928729..d539a84 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedContent.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedContent.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.arkivanov.decompose.extensions.compose.subscribeAsState import org.gradle.client.ui.composables.FailureContent import org.gradle.client.ui.composables.Loading @@ -63,17 +64,24 @@ private fun ConnectedMainContent(component: ConnectedComponent, model: Connectio modifier = Modifier.padding(sheetPadding), left = { // Actions - component.modelActions.forEach { action -> - Row( - modifier = Modifier.fillMaxWidth().selectable( - selected = false, - onClick = { component.getModel(action) } - ).padding(MaterialTheme.spacing.level1), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.level1) - ) { - Icon(Icons.Default.PlayCircle, action.displayName) - Text(action.displayName, style = MaterialTheme.typography.bodyMedium) + component.modelActionGroups.forEachIndexed { index, group -> + if (index != 0) { + HorizontalDivider(Modifier.padding(top = 4.dp, bottom = 4.dp)) + } + Row { TitleMedium(group.name) } + + group.modelActions.forEach { action -> + Row( + modifier = Modifier.fillMaxWidth().selectable( + selected = false, + onClick = { component.getModel(action) } + ).padding(MaterialTheme.spacing.level1), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.level1) + ) { + Icon(Icons.Default.PlayCircle, action.displayName) + Text(action.displayName, style = MaterialTheme.typography.bodyMedium) + } } } }, diff --git a/gradle-client/src/jvmTest/kotlin/org/gradle/client/ui/GradleClientUiTest.kt b/gradle-client/src/jvmTest/kotlin/org/gradle/client/ui/GradleClientUiTest.kt index f6fed7b..b3397e9 100644 --- a/gradle-client/src/jvmTest/kotlin/org/gradle/client/ui/GradleClientUiTest.kt +++ b/gradle-client/src/jvmTest/kotlin/org/gradle/client/ui/GradleClientUiTest.kt @@ -16,6 +16,7 @@ import org.gradle.client.core.database.sqldelight.SqlDriverFactory import org.gradle.client.ui.connected.ConnectionModel import org.gradle.client.ui.connected.Outcome import org.gradle.client.ui.fixtures.AbstractUiTest +import org.gradle.internal.operations.BuildOperationDescriptor.displayName import org.gradle.tooling.model.gradle.GradleBuild import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.CoreMatchers.instanceOf @@ -26,7 +27,7 @@ import org.junit.Test class GradleClientUiTest : AbstractUiTest() { @Test fun gradleClientTest() = runTest { - runDesktopComposeUiTest(800, 600) { + runDesktopComposeUiTest(1280, 1024) { appDirs.logApplicationDirectories() val sqlDriverFactory = SqlDriverFactory(appDirs) val sqlDriver = sqlDriverFactory.createDriver() @@ -104,8 +105,10 @@ class GradleClientUiTest : AbstractUiTest() { instanceOf(ConnectionModel.Connecting::class.java) ) advanceUntilIdle() - connected.component.modelActions.map { it.displayName }.forEach { actionName -> - onNodeWithText(actionName).assertIsDisplayed() + connected.component.modelActionGroups.forEach { group -> + group.modelActions.map { it.displayName }.forEach { actionName -> + onNodeWithText(actionName).assertIsDisplayed() + } } takeScreenshot("connected") @@ -115,7 +118,8 @@ class GradleClientUiTest : AbstractUiTest() { instanceOf(Outcome.None::class.java) ) onNodeWithText( - connected.component.modelActions.single { it.modelType == GradleBuild::class }.displayName + connected.component.modelActionGroups.flatMap { it.modelActions } + .single { it.modelType == GradleBuild::class }.displayName ).performClick() // Displays model From a1aaa4c242c336676cb22c6f904e17d9b0821313 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Thu, 18 Sep 2025 23:19:16 +0300 Subject: [PATCH 05/11] Move the `GetResilientGradleBuild` to the "Build and project" group --- .../org/gradle/client/ui/connected/ConnectedComponent.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt index 256f8fe..c42b043 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/ConnectedComponent.kt @@ -63,7 +63,7 @@ class ConnectedComponent( val modelActionGroups = listOf( ModelActionGroup( "Build and project", - listOf(GetBuildEnvironment(), GetGradleBuild(), GetGradleProject()) + listOf(GetBuildEnvironment(), GetGradleBuild(), GetResilientGradleBuild(), GetGradleProject()) ), ModelActionGroup( "Declarative Gradle", @@ -71,7 +71,7 @@ class ConnectedComponent( ), ModelActionGroup( "Kotlin DSL", - listOf(GetKotlinBaseDslScriptModel(), GetResilientGradleBuild(), GetResilientKotlinDslScriptsModel()) + listOf(GetKotlinBaseDslScriptModel(), GetResilientKotlinDslScriptsModel()) ) ) From 47a70b9e2637dbaac4e7e798b63ea86b44481297 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Fri, 19 Sep 2025 21:01:36 +0300 Subject: [PATCH 06/11] Update Gradle wrapper and dependencies to `9.2.0-milestone-2` --- gradle-client/build.gradle.dcl | 8 ++++---- .../ui/connected/actions/GetKotlinBaseDslScriptModel.kt | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gradle-client/build.gradle.dcl b/gradle-client/build.gradle.dcl index 0d8c2e8..a9331ff 100644 --- a/gradle-client/build.gradle.dcl +++ b/gradle-client/build.gradle.dcl @@ -19,7 +19,7 @@ kotlinApplication { implementation(project(":build-action")) implementation(project(":mutations-demo")) - implementation("org.gradle:gradle-tooling-api:9.1.0-20250805104018+0000") + implementation("org.gradle:gradle-tooling-api:9.2.0-milestone-2") implementation("com.arkivanov.decompose:decompose:3.0.0") implementation("com.arkivanov.decompose:extensions-compose:3.0.0") @@ -36,9 +36,9 @@ kotlinApplication { implementation("org.slf4j:slf4j-api:2.0.14") implementation("ch.qos.logback:logback-classic:1.5.6") - implementation("org.gradle:gradle-declarative-dsl-core:9.2.0-milestone-1") - implementation("org.gradle:gradle-declarative-dsl-evaluator:9.2.0-milestone-1") - implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.2.0-milestone-1") + implementation("org.gradle:gradle-declarative-dsl-core:9.2.0-milestone-2") + implementation("org.gradle:gradle-declarative-dsl-evaluator:9.2.0-milestone-2") + implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.2.0-milestone-2") runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.8.1") diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetKotlinBaseDslScriptModel.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetKotlinBaseDslScriptModel.kt index 33c40b2..505a011 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetKotlinBaseDslScriptModel.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetKotlinBaseDslScriptModel.kt @@ -11,7 +11,7 @@ import org.gradle.client.ui.composables.horizontalScrollContent import org.gradle.client.ui.theme.spacing import org.gradle.tooling.BuildAction import org.gradle.tooling.BuildController -import org.gradle.tooling.model.kotlin.dsl.KotlinDslBaseScriptModel +import org.gradle.tooling.model.dsl.KotlinDslBaseScriptModel class GetKotlinBaseDslScriptModel : GetModelAction.GetCompositeModelAction { @@ -36,7 +36,7 @@ class GetKotlinBaseDslScriptModel : GetModelAction.GetCompositeModelAction Date: Fri, 19 Sep 2025 21:11:26 +0300 Subject: [PATCH 07/11] Update the rest of the Gradle libs to `9.2.0-milestone-2` --- build-action/build.gradle.dcl | 4 ++-- mutations-demo/build.gradle.dcl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build-action/build.gradle.dcl b/build-action/build.gradle.dcl index f7c70fc..9d3d539 100644 --- a/build-action/build.gradle.dcl +++ b/build-action/build.gradle.dcl @@ -2,7 +2,7 @@ javaLibrary { javaVersion = 8 dependencies { - implementation("org.gradle:gradle-tooling-api:9.0-milestone-1") - implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.0-milestone-1") + implementation("org.gradle:gradle-tooling-api:9.2.0-milestone-2") + implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.2.0-milestone-2") } } diff --git a/mutations-demo/build.gradle.dcl b/mutations-demo/build.gradle.dcl index 28d8a4e..1c75715 100644 --- a/mutations-demo/build.gradle.dcl +++ b/mutations-demo/build.gradle.dcl @@ -1,5 +1,5 @@ kotlinJvmLibrary { dependencies { - implementation("org.gradle:gradle-declarative-dsl-core:9.0-milestone-1") + implementation("org.gradle:gradle-declarative-dsl-core:9.2.0-milestone-2") } } From 9df325db71a2f42f60ee664e99c493d579136f82 Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Tue, 23 Sep 2025 09:21:20 +0200 Subject: [PATCH 08/11] Update wrapper JAR --- gradle/wrapper/gradle-wrapper.jar | Bin 45632 -> 45633 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 53dfafe38f9fbed2186f5c17f22c0fec2f2f6223..f8e1ee3125fe0768e9a76ee977ac089eb657005e 100644 GIT binary patch delta 36441 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8d0acc6..3586065 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-9.2.0-milestone-2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-milestone-2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From ed405a7241253c0fd12f9b7b8716177f842140cc Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Tue, 23 Sep 2025 09:55:56 +0200 Subject: [PATCH 09/11] Fix proguard --- gradle-client/build.gradle.dcl | 1 + gradle-client/proguard-desktop.pro | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/gradle-client/build.gradle.dcl b/gradle-client/build.gradle.dcl index a9331ff..86bedba 100644 --- a/gradle-client/build.gradle.dcl +++ b/gradle-client/build.gradle.dcl @@ -39,6 +39,7 @@ kotlinApplication { implementation("org.gradle:gradle-declarative-dsl-core:9.2.0-milestone-2") implementation("org.gradle:gradle-declarative-dsl-evaluator:9.2.0-milestone-2") implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.2.0-milestone-2") + implementation("org.jspecify:jspecify:1.0.0") runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.8.1") diff --git a/gradle-client/proguard-desktop.pro b/gradle-client/proguard-desktop.pro index 3247c99..53872a8 100644 --- a/gradle-client/proguard-desktop.pro +++ b/gradle-client/proguard-desktop.pro @@ -41,6 +41,7 @@ -dontwarn org.jetbrains.kotlin.cli.jvm.javac.** -dontwarn org.jetbrains.kotlin.com.intellij.** -dontwarn org.jetbrains.kotlin.javac.** +-dontwarn org.jetbrains.kotlin.io.** -dontwarn org.checkerframework.** # ========================================================================= @@ -65,6 +66,9 @@ # Coroutines -keep class kotlinx.coroutines.swing.SwingDispatcherFactory +# JSpecify +-keep class org.jspecify.** { *; } + # Logging -keep class org.slf4j.** { *; } -keep class ch.qos.logback.** { *; } From 287b2deeb64312d9b6d70017c4ff49b5d0ede34d Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Tue, 23 Sep 2025 10:00:08 +0200 Subject: [PATCH 10/11] Remove CI dependency-submission.yml --- .github/workflows/dependency-submission.yml | 23 --------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/workflows/dependency-submission.yml diff --git a/.github/workflows/dependency-submission.yml b/.github/workflows/dependency-submission.yml deleted file mode 100644 index 91af11d..0000000 --- a/.github/workflows/dependency-submission.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Dependency Submission -on: - push: - branches: - - main -permissions: - contents: write -jobs: - validate_wrapper: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 - submit_dependency_graph: - needs: validate_wrapper - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - - uses: gradle/actions/dependency-submission@v3 From d91e5f70e0c77f4228e7467413015aa7369dc7a6 Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Tue, 23 Sep 2025 10:00:33 +0200 Subject: [PATCH 11/11] Use recent Gradle Github Action --- .github/workflows/ci.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d298e7..017fd5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,25 +2,18 @@ name: CI on: push jobs: - validate_wrapper: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 - check: - needs: validate_wrapper strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: distribution: temurin java-version: 17 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 with: add-job-summary: on-failure add-job-summary-as-pr-comment: on-failure