// Copyright (C) 2023 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[init_scripts]]
= Initialization Scripts

Initialization scripts are scripts that run before the build script is executed.
They allow you to customize the build environment or configure settings early in the build.

Initialization scripts can be useful for setting up common configurations, such as repositories, plugins, or custom tasks, across multiple projects.

[[sec:basic_usage]]
== Using an init script

Initialization scripts, also called _init scripts_, are similar to other scripts in Gradle.
Initialization scripts run before the build starts.

They are useful for various purposes:

* Setting up enterprise-wide configurations (e.g., custom plugin locations)
* Configuring properties based on the environment (e.g., developer's machine vs. CI server)
* Providing user-specific information (e.g., authentication credentials)
* Defining machine-specific details (e.g., JDK locations)
* Registering build listeners (e.g., external tools that wish to listen to Gradle events might find this helpful)
* Registering loggers (e.g., customize how Gradle logs the events that it generates)

One main <<sharing_build_logic_between_subprojects.adoc#sec:using_buildsrc,limitation of init scripts>> is that they cannot access classes in the `buildSrc` project.

[[sec:using_an_init_script]]
== Invoking an init script

There are several ways to invoke an init script (in order of priority):

1. *Specify a file on the command line* with the option `-I` or `--init-script` followed by the path to the script.
+
The command line option can appear more than once, each time adding another init script. The build will fail if any files specified on the command line do not exist.
2. *Put a file called `init.gradle(.kts)`* in the `__$<<directory_layout.adoc#dir:gradle_user_home,GRADLE_USER_HOME>>__/` directory.
3. *Put a file called `init.gradle(.kts)`* in the `__$<<directory_layout.adoc#dir:gradle_user_home,GRADLE_USER_HOME>>__/init.d/` directory.
4. *Put a file called `init.gradle(.kts)`* in the `$<<installation.adoc#sec:linux_macos_users_2,__GRADLE_HOME__>>/init.d/` directory.
+
This lets you package a custom Gradle distribution containing custom build logic and plugins. You can combine this with the <<gradle_wrapper.adoc#gradle_wrapper_reference,Gradle wrapper>> to make custom logic available to all builds in your enterprise.

If more than one init script is found, they will all be executed in the order specified above.

Scripts in a given directory are executed in alphabetical order.
For example, a tool can specify an init script on the command line and another in the home directory to define the environment.
Both scripts will run when Gradle is executed.

[[sec:writing_an_init_script]]
== Writing an init script

Like a Gradle build script, an init script is a Groovy or Kotlin script.
Each init script has a link:{groovyDslPath}/org.gradle.api.invocation.Gradle.html[Gradle] instance associated with it.
Any property reference and method call in the init script will be delegated to this `Gradle` instance.

Each init script implements the link:{groovyDslPath}/org.gradle.api.Script.html[Script] interface.

[NOTE]
====
When writing init scripts, pay attention to the scope of the reference you are trying to access.
For example, properties loaded from `gradle.properties` are available on `Settings` or `Project` instances but not on the `Gradle` one.
====

[[sec:configuring_projects_from_an_init_script]]
=== Configuring projects from an init script

You can use an init script to configure the projects in the build.
This works similarly to configuring projects in a multi-project build.

The following sample shows how to perform extra configuration from an init script _before_ the projects are evaluated:

====
include::sample[dir="snippets/initScripts/configurationInjection/groovy",files="build.gradle[];init.gradle[]"]
include::sample[dir="snippets/initScripts/configurationInjection/kotlin",files="build.gradle.kts[];init.gradle.kts[]"]
====

This sample uses this feature to configure an additional repository to be used only for specific environments.

[source.multi-language-sample,kotlin]
----
> gradle --init-script init.gradle.kts -q showRepos
include::{snippetsPath}/initScripts/configurationInjection/tests-common/initScriptConfiguration.out[]
----
[source.multi-language-sample,groovy]
----
> gradle --init-script init.gradle -q showRepos
include::{snippetsPath}/initScripts/configurationInjection/tests-common/initScriptConfiguration.out[]
----

[[sec:custom_classpath]]
== Adding external dependencies

Init scripts can also declare dependencies with the `initscript()` method, passing in a closure that declares the init script classpath.

Declaring external dependencies for an init script:

====
include::sample[dir="snippets/initScripts/externalDependency/kotlin",files="init.gradle.kts[tags=declare-classpath]"]
include::sample[dir="snippets/initScripts/externalDependency/groovy",files="init.gradle[tags=declare-classpath]"]
====

The closure passed to the `initscript()` method configures a link:{javadocPath}/org/gradle/api/initialization/dsl/ScriptHandler.html[ScriptHandler] instance.
You declare the init script classpath by adding dependencies to the `classpath` configuration.

This is the same way you declare, for example, the Java compilation classpath.
You can use any of the dependency types described in <<declaring_dependencies.adoc#declaring-basic-dependencies,Declaring Dependencies>>, except project dependencies.

Having declared the init script classpath, you can use the classes in your init script as you would any other classes on the classpath.
The following example adds to the previous example and uses classes from the init script classpath.

An init script with external dependencies:

====
include::sample[dir="snippets/initScripts/externalDependency/kotlin",files="init.gradle.kts[tags=all];build.gradle.kts[]"]
include::sample[dir="snippets/initScripts/externalDependency/groovy",files="init.gradle[tags=all];build.gradle[]"]
====

[source.multi-language-sample,kotlin]
----
> gradle --init-script init.gradle.kts -q doNothing
include::{snippetsPath}/initScripts/externalDependency/tests-common/externalInitDependency.out[]
----
[source.multi-language-sample,groovy]
----
> gradle --init-script init.gradle -q doNothing
include::{snippetsPath}/initScripts/externalDependency/tests-common/externalInitDependency.out[]
----

[[sec:init_script_plugins]]
== Applying plugins

Plugins can be applied to init scripts like a Gradle build script or a Gradle settings file.

Using plugins in init scripts:

====
include::sample[dir="snippets/initScripts/plugins/kotlin",files="init.gradle.kts[tags=init-script-plugin];build.gradle.kts[tag=show-repos-task]"]
include::sample[dir="snippets/initScripts/plugins/groovy",files="init.gradle[tags=init-script-plugin];build.gradle[tag=show-repos-task]"]
====

[source.multi-language-sample,kotlin]
----
> gradle --init-script init.gradle.kts -q showRepositories
include::{snippetsPath}/initScripts/plugins/tests-common/usePluginsInInitScripts.out[]
----
[source.multi-language-sample,groovy]
----
> gradle --init-script init.gradle -q showRepositories
include::{snippetsPath}/initScripts/plugins/tests-common/usePluginsInInitScripts.out[]
----

The plugin in the init script ensures that only a specified repository is used when running the build.

When applying plugins within the init script, Gradle instantiates the plugin and calls the plugin instance's link:{javadocPath}/org/gradle/api/Plugin.html#apply-T-[Plugin.apply(T)] method.

The `gradle` object is passed as a parameter, which can be used to configure all aspects of a build. Of course, the applied plugin can be resolved as an external dependency as described in <<#sec:custom_classpath,External dependencies for the init script>>
