@@ -64,19 +64,24 @@ def update_files(build_file)
6464 cwd = File . join ( temp_dir , base_path ( build_file ) )
6565
6666 has_local_script = File . exist? ( File . join ( cwd , "./gradlew" ) )
67- command_parts = %w( --no-daemon --stacktrace ) + command_args ( target_requirements )
68- command = Shellwords . join ( [ has_local_script ? "./gradlew" : "gradle" ] + command_parts )
6967
7068 Dir . chdir ( cwd ) do
7169 FileUtils . chmod ( "+x" , "./gradlew" ) if has_local_script
7270
7371 properties_file = File . join ( cwd , "gradle/wrapper/gradle-wrapper.properties" )
74- validate_option = get_validate_distribution_url_option ( properties_file )
72+ validate_distribution , network_timeout = read_wrapper_options ( properties_file )
7573 env = { "JAVA_OPTS" => proxy_args . join ( " " ) } # set proxy for gradle execution
7674
75+ command_parts = %w( --no-daemon --stacktrace ) + command_args ( target_requirements , network_timeout )
76+
77+ # There is no guarantee that the `gradlew` script is present on the project,
78+ # if it's not, we fall back to system Gradle
79+ command = Shellwords . join ( [ has_local_script ? "./gradlew" : "gradle" ] + command_parts )
80+
7781 begin
78- # first attempt: run the wrapper task via the local gradle wrapper (if present)
79- # `gradle-wrapper.jar` might be too old to run on host's Java version
82+ # first attempt: run the wrapper task via the local Gradle wrapper (if present)
83+ # `gradle-wrapper.jar` might be too old to run on host's Java version or
84+ # the `gradlew` script may be corrupted, so we try and fall back to system Gradle before giving up
8085 SharedHelpers . run_shell_command ( command , cwd : cwd , env : env )
8186 rescue SharedHelpers ::HelperSubprocessFailed => e
8287 raise e unless has_local_script # already field with system one, there is no point to retry
@@ -90,7 +95,7 @@ def update_files(build_file)
9095 end
9196
9297 # Restore previous validateDistributionUrl option if it existed
93- override_validate_distribution_url_option ( properties_file , validate_option )
98+ override_validate_distribution_url_option ( properties_file , validate_distribution )
9499
95100 update_files_content ( temp_dir , local_files , updated_files )
96101 rescue SharedHelpers ::HelperSubprocessFailed => e
@@ -111,8 +116,9 @@ def target_file?(file)
111116 @target_files . any? { |r | "/#{ file . name } " . end_with? ( r ) }
112117 end
113118
114- sig { params ( requirements : T ::Array [ T ::Hash [ Symbol , T . untyped ] ] ) . returns ( T ::Array [ String ] ) }
115- def command_args ( requirements )
119+ # rubocop:disable Metrics/PerceivedComplexity
120+ sig { params ( requirements : T ::Array [ T ::Hash [ Symbol , T . untyped ] ] , network_timeout : T . nilable ( String ) ) . returns ( T ::Array [ String ] ) }
121+ def command_args ( requirements , network_timeout )
116122 version = T . let ( requirements [ 0 ] &.[]( :requirement ) , String )
117123 checksum = T . let ( requirements [ 1 ] &.[]( :requirement ) , String ) if dependency . requirements . size > 1
118124 distribution_url = T . let ( requirements [ 0 ] &.[]( :source ) , T ::Hash [ Symbol , String ] ) [ :url ]
@@ -133,6 +139,24 @@ def command_args(requirements)
133139 # See https://github.com/dependabot/dependabot-core/issues/14036
134140 args += %w( --no-validate-url )
135141
142+ # Gradle builds can be very complex, and our current Gradle parsing is limited.
143+ # To keep `./gradlew wrapper` running reliably, we generate a minimal build that omits the
144+ # project’s build scripts and customizations. As a result, any `tasks.wrapper {}` DSL configuration
145+ # defined in the original project is not applied.
146+ #
147+ # This approach, combined with https://github.com/gradle/gradle/issues/36172 where the wrapper task
148+ # relies on hardcoded defaults instead of reading from `gradle-wrapper.properties`, causes
149+ # `networkTimeout` customizations to be reset to the default value on every Dependabot pull request.
150+ #
151+ # This change mitigates the issue by reading the existing value and passing it explicitly to the
152+ # `wrapper` command, ensuring any custom `networkTimeout` setting is preserved.
153+ #
154+ # In future iterations, we may consider parsing the full Gradle build and extracting only the
155+ # wrapper-related customizations so the project-specific `tasks.wrapper {}` behavior is retained.
156+ # Alternatively, if Gradle addresses the upstream issue, we can revert to using the default minimal
157+ # build without needing explicit configuration.
158+ args += %W( --network-timeout #{ network_timeout } ) if network_timeout
159+
136160 args += %W( --distribution-type #{ distribution_type } ) if distribution_type
137161 args += %W( --gradle-distribution-sha256-sum #{ checksum } ) if checksum
138162 args
@@ -183,12 +207,15 @@ def populate_temp_directory(temp_dir)
183207 end
184208 end
185209
186- sig { params ( properties_file : T . any ( Pathname , String ) ) . returns ( T . nilable ( String ) ) }
187- def get_validate_distribution_url_option ( properties_file )
188- return nil unless File . exist? ( properties_file )
210+ sig { params ( properties_file : T . any ( Pathname , String ) ) . returns ( T :: Array [ T . nilable ( String ) ] ) }
211+ def read_wrapper_options ( properties_file )
212+ return [ nil , nil ] unless File . exist? ( properties_file )
189213
190214 properties_content = File . read ( properties_file )
191- properties_content . match ( /^validateDistributionUrl=(.*)$/ ) &.captures &.first
215+ validate_distribution = properties_content . match ( /^validateDistributionUrl=(.*)$/ ) &.captures &.first
216+ network_timeout = properties_content . match ( /^networkTimeout=(.*)$/ ) &.captures &.first
217+
218+ [ validate_distribution , network_timeout ]
192219 end
193220
194221 sig { params ( properties_file : T . any ( Pathname , String ) , value : T . nilable ( String ) ) . void }
@@ -203,7 +230,6 @@ def override_validate_distribution_url_option(properties_file, value)
203230 File . write ( properties_file , updated_content )
204231 end
205232
206- # rubocop:disable Metrics/PerceivedComplexity
207233 sig { returns ( T ::Array [ String ] ) }
208234 def proxy_args
209235 http_proxy = ENV . fetch ( "HTTP_PROXY" , nil )
0 commit comments