├── .github └── workflows │ ├── publish.yml │ └── snapshot.yml ├── .gitignore ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RELEASING.md ├── build.gradle ├── common.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── publish-root.gradle ├── publishing.gradle ├── settings.gradle └── src └── main └── java └── nz └── co └── trademe └── gradle └── includeme ├── IncludeMePlugin.kt ├── model └── IncludeMeProject.kt └── util ├── Constants.kt ├── Extensions.kt ├── Log.kt └── PropertiesHelper.kt /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish: 10 | name: Release build and publish 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out code 14 | uses: actions/checkout@v2 15 | - name: Set up JDK 11 16 | uses: actions/setup-java@v2 17 | with: 18 | distribution: adopt 19 | java-version: 11 20 | 21 | - name: Release build 22 | run: ./gradlew clean build 23 | 24 | # Generates other artifacts 25 | - name: Source jar and dokka 26 | run: ./gradlew androidSourcesJar javadocJar 27 | 28 | # Runs upload, and then closes & releases the repository 29 | - name: Publish to MavenCentral 30 | run: ./gradlew publishReleasePublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository 31 | 32 | env: 33 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 34 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 35 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} 36 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} 37 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 38 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} 39 | -------------------------------------------------------------------------------- /.github/workflows/snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Publish Snapshot builds 2 | 3 | 4 | on: 5 | push: 6 | branches: 7 | - 'release/**' 8 | 9 | jobs: 10 | publish: 11 | name: Snapshot build and publish 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out code 15 | uses: actions/checkout@v2 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v2 18 | with: 19 | distribution: adopt 20 | java-version: 11 21 | - name: Release build 22 | 23 | run: ./gradlew clean build 24 | - name: Source jar and dokka 25 | run: ./gradlew androidSourcesJar javadocJar 26 | - name: Publish to MavenCentral 27 | run: ./gradlew publishReleasePublicationToSonatypeRepository 28 | 29 | 30 | 31 | env: 32 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 33 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 34 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} 35 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} 36 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 37 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} 38 | SNAPSHOT: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | Version 1.0.4 *(28-02-2022)* 5 | ---------------------------- 6 | 7 | * Migration to maven central 8 | 9 | Version 1.0.3 *(26-06-2018)* 10 | ---------------------------- 11 | 12 | * Adds support for kotlin script settings files 13 | 14 | 15 | Version 1.0.2 *(07-06-2018)* 16 | ---------------------------- 17 | 18 | * Fixes searchpath resolution 19 | 20 | 21 | Version 1.0.1 *(19-03-2018)* 22 | ---------------------------- 23 | 24 | * Removes verbose logging 25 | 26 | Version 1.0.0 *(14-03-2018)* 27 | ---------------------------- 28 | 29 | * Initial release -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | @athornz -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We welcome contributions to this repository. 4 | 5 | To avoid wasting anyone's time, ensure you *first discuss the change you wish to make by opening an issue*. 6 | 7 | All contributions must follow the conventions, code style and formatting of this repository. 8 | 9 | Other things to consider: 10 | * all tests should pass 11 | * new features should be accompanied by tests 12 | * breaking changes should be avoided 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Trade Me 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IncludeMe 2 | 3 | IncludeMe is a Gradle plugin that simplifies working with [composite builds.](https://docs.gradle.org/current/userguide/composite_builds.html) 4 | 5 | IncludeMe scans directories for Gradle projects and provides a simple toggle to include a project as a composite build. 6 | 7 | No more trying to remember project paths or editing settings.gradle! 8 | 9 | What are composite builds? 10 | ----- 11 | *From the Gradle documentation:* 12 | 13 | > A composite build is simply a build that includes other builds. In many ways a composite build is similar to a Gradle multi-project build, except that instead of including single projects, complete builds are included. 14 | 15 | Composite builds make it really easy to work with external projects and libraries by including them as if they were a module in the current project. 16 | 17 | Dependency substitution is handled by Gradle, so rather than publishing a library snapshot the project can simple be compiled. 18 | 19 | Usage 20 | ----- 21 | 22 | Apply IncludeMe to the settings.gradle file in your project: 23 | 24 | ```groovy 25 | buildscript { 26 | repositories { 27 | jcenter() 28 | } 29 | 30 | dependencies { 31 | classpath 'nz.co.trademe.includeme:includeme:1.0.4' 32 | } 33 | } 34 | 35 | include ':app' 36 | 37 | apply plugin: 'nz.co.trademe.includeme' 38 | 39 | ``` 40 | 41 | After a Gradle sync, IncludeMe will create a `include.properties` file in the project: 42 | 43 | ``` 44 | myModule=false 45 | myLibrary=false 46 | ``` 47 | 48 | Change the value of these properties (and perform a Gradle sync) to include the project as a composite build. 🎉 49 | 50 | The `include.properties` should be added to `.gitignore`. 51 | 52 | Requirements 53 | ----- 54 | 55 | **Note:** IncludeMe requires Gradle 4.4 or higher. This version of Gradle includes a fix for the buildscript classpath issue with Android projects. 56 | 57 | The warning for this issue has been removed in Android Gradle Plugin 3.1.0, but if using a version below 3.1.0, the following will need to be added to the projects `gradle.properties`: 58 | 59 | ``` 60 | android.enableBuildScriptClasspathCheck=false 61 | ``` 62 | 63 | Search paths 64 | ----- 65 | 66 | IncludeMe will search for Gradle projects in the projects parent directory by default. 67 | 68 | Different search paths (or multiple paths) can be declared in a projects `local.properties`, `gradle.properties` or the users `gradle.properties` file: 69 | 70 | ``` 71 | includeme.searchpaths=~/workspace/projects,~/workspace/libraries 72 | ``` 73 | 74 | Whitelist 75 | ----- 76 | 77 | A project whitelist can also be setup to tell IncludeMe to only look for specific projects: 78 | 79 | ``` 80 | includeme.whitelist=myModule,myLibrary 81 | ``` 82 | 83 | The whitelist should include project directory names. 84 | 85 | 86 | Troubleshooting 87 | ----- 88 | 89 | If you find that IncludeMe is including a project in the build, but Gradle is still compiling the remote dependency rather than the project sources, the included project may not be set up correctly. 90 | 91 | Gradle Composite Builds require that the projects `group` and `name` match the artifact group and name. 92 | 93 | i.e. if the artifact is `com.myawesomecompany:alibrary:1.0.0`, then the library module should be named `alibrary` and the group should be set to `com.myawesomecompany`. 94 | 95 | ### Setting a group 96 | The group for a module or project can be set with the `group` dsl. 97 | 98 | ```groovy 99 | //in build.gradle (library module) 100 | 101 | group = com.myawesomecompany 102 | 103 | ``` 104 | 105 | ### Setting the module/project name 106 | 107 | The project/module name comes from the folder name by default. If you need the project name to be different from the folder name, it can be set in the projects `settings.gradle`. 108 | 109 | ```groovy 110 | //in settings.gradle 111 | 112 | include ':thelibrary' 113 | project(':thelibrary').name = "alibrary" 114 | ``` 115 | 116 | 117 | ## Contributing 118 | 119 | We love contributions, but make sure to checkout `CONTRIBUTING.MD` first! 120 | 121 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | Releasing 2 | ======== 3 | 4 | 1. Change the version in `common.gradle` to a non-SNAPSHOT version. 5 | 2. Update the `CHANGELOG.md` for the impending release. 6 | 3. Update the `README.md` with the new version. 7 | 4. `git commit -am "Prepare for release X.Y.Z."` (where X.Y.Z is the new version) 8 | 5. `./gradlew clean build bintrayUpload`. 9 | 6. Visit [Bintray](https://bintray.com) and publish the artifact. 10 | 7. `git tag -a X.Y.X -m "Version X.Y.Z"` (where X.Y.Z is the new version) 11 | 8. Update the version in `common.gradle` to the next SNAPSHOT version. 12 | 9. `git commit -am "Prepare next development version."` 13 | 10. `git push && git push --tags` 14 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'io.github.gradle-nexus.publish-plugin' 2 | apply plugin: 'org.jetbrains.dokka' 3 | 4 | buildscript { 5 | apply from: 'common.gradle' 6 | 7 | repositories { 8 | maven { url "https://plugins.gradle.org/m2/" } 9 | google() 10 | jcenter() 11 | } 12 | dependencies { 13 | classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$bintray_version" 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' 16 | classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.6.10' 17 | } 18 | } 19 | 20 | 21 | 22 | apply from: "${rootDir}/publish-root.gradle" 23 | 24 | ext { 25 | PUBLISH_VERSION = rootVersionName 26 | ARTIFACT_ID = "includeme" 27 | } 28 | 29 | apply plugin: 'java-gradle-plugin' 30 | apply plugin: 'kotlin' 31 | apply plugin: 'maven-publish' 32 | apply from: 'publishing.gradle' 33 | 34 | gradlePlugin { 35 | plugins { 36 | customPlugin { 37 | id = 'nz.co.trademe.includeme' 38 | implementationClass = 'nz.co.trademe.gradle.includeme.IncludeMePlugin' 39 | } 40 | } 41 | } 42 | 43 | repositories { 44 | google() 45 | jcenter() 46 | } 47 | 48 | 49 | dependencies { 50 | implementation gradleApi() 51 | implementation "com.android.tools.build:gradle:$agp_version" 52 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 53 | 54 | testImplementation'junit:junit:4.12' 55 | } 56 | 57 | 58 | sourceSets { 59 | test { 60 | resources { 61 | srcDir "/src/test/resources" 62 | } 63 | } 64 | } 65 | 66 | task copyTestResources(type: Copy) { 67 | from "${projectDir}/src/test/resources" 68 | into "${buildDir}/classes/test" 69 | } 70 | processTestResources.dependsOn copyTestResources 71 | 72 | compileKotlin { 73 | kotlinOptions.jvmTarget = "1.8" 74 | } 75 | compileTestKotlin { 76 | kotlinOptions.jvmTarget = "1.8" 77 | } 78 | 79 | -------------------------------------------------------------------------------- /common.gradle: -------------------------------------------------------------------------------- 1 | ext.version = "1.0.4" 2 | ext.group = "nz.co.trademe.includeme" 3 | ext.repo = "includeme" 4 | ext.scm = 'https://github.com/TradeMe/IncludeMe.git' 5 | ext.description = 'A Gradle plugin that simplifies working with composite builds' 6 | 7 | ext.connection = 'scm:git:github.com/TradeMe/IncludeMe.git' 8 | ext.developerConnection = 'scm:git:ssh://github.com/TradeMe/IncludeMe.git' 9 | ext.url = 'https://github.com/TradeMe/IncludeMe' 10 | 11 | 12 | ext.bintray_version = '1.7.3' 13 | ext.kotlin_version = '1.5.0' 14 | ext.agp_version = "4.0.1" 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TradeMe/IncludeMe/aaab8011da9c42dc1f1aa9a95ce74460aaa2a435/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Aug 17 08:29:49 NZST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /publish-root.gradle: -------------------------------------------------------------------------------- 1 | 2 | // Create variables with empty default values 3 | ext["signing.keyId"] = '' 4 | ext["signing.password"] = '' 5 | ext["signing.key"] = '' 6 | ext["ossrhUsername"] = '' 7 | ext["ossrhPassword"] = '' 8 | ext["sonatypeStagingProfileId"] = '' 9 | ext["snapshot"] = 'true' 10 | 11 | File secretPropsFile = project.rootProject.file('local.properties') 12 | if (secretPropsFile.exists()) { 13 | // Read local.properties file first if it exists 14 | Properties p = new Properties() 15 | new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) } 16 | p.each { name, value -> ext[name] = value } 17 | } else { 18 | // Use system environment variables 19 | ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME') 20 | ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD') 21 | ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID') 22 | ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') 23 | ext["signing.password"] = System.getenv('SIGNING_PASSWORD') 24 | ext["signing.key"] = System.getenv('SIGNING_KEY') 25 | ext["snapshot"] = System.getenv('SNAPSHOT') 26 | } 27 | 28 | if (Boolean.parseBoolean(snapshot)) { 29 | ext["rootVersionName"] = project.ext.version + "-SNAPSHOT" 30 | } else { 31 | ext["rootVersionName"] = project.ext.version 32 | } 33 | 34 | // Set up Sonatype repository 35 | nexusPublishing { 36 | repositories { 37 | sonatype { 38 | useStaging.set(provider { 39 | !Boolean.parseBoolean(snapshot) 40 | }) 41 | version = rootVersionName 42 | stagingProfileId = sonatypeStagingProfileId 43 | username = ossrhUsername 44 | password = ossrhPassword 45 | nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) 46 | snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /publishing.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'signing' 3 | apply plugin: 'org.jetbrains.dokka' 4 | 5 | task androidSourcesJar(type: Jar) { 6 | archiveClassifier.set('sources') 7 | if (project.plugins.findPlugin("com.android.library")) { 8 | // For Android libraries 9 | from android.sourceSets.main.java.srcDirs 10 | from android.sourceSets.main.kotlin.srcDirs 11 | } else { 12 | from sourceSets.main.java.srcDirs 13 | from sourceSets.main.kotlin.srcDirs 14 | } 15 | 16 | 17 | } 18 | task javadocJar(type: Jar, dependsOn: dokkaJavadoc) { 19 | archiveClassifier.set('javadoc') 20 | from dokkaJavadoc.outputDirectory 21 | } 22 | 23 | artifacts { 24 | archives androidSourcesJar 25 | archives javadocJar 26 | } 27 | 28 | group = project.ext.group 29 | 30 | afterEvaluate { 31 | publishing { 32 | 33 | publications { 34 | release(MavenPublication) { 35 | groupId group 36 | artifactId ARTIFACT_ID 37 | version PUBLISH_VERSION 38 | 39 | if (project.plugins.findPlugin("com.android.library")) { 40 | from components.release 41 | } else { 42 | from components.java 43 | } 44 | 45 | artifact androidSourcesJar 46 | artifact javadocJar 47 | 48 | // metadata 49 | pom { 50 | name = ARTIFACT_ID 51 | description = 'SDK' 52 | url = project.ext.url 53 | licenses { 54 | license { 55 | name = "MIT License" 56 | url = "http://www.opensource.org/licenses/mit-license.php" 57 | } 58 | } 59 | developers { 60 | developer { 61 | id = 'sabinmj' 62 | name = 'Sabin Mulakukodiyan' 63 | email = 'sabin.mulakukodiyan@trademe.co.nz' 64 | } 65 | // Add all other devs here... 66 | } 67 | 68 | // Version control info - if you're using GitHub, follow the 69 | // format as seen here 70 | scm { 71 | connection = project.ext.connection 72 | developerConnection = project.ext.developerConnection 73 | url = project.ext.url 74 | 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | signing { 82 | if (rootProject.ext["signing.keyId"] && rootProject.ext["signing.key"] && rootProject.ext["signing.password"]) { 83 | useInMemoryPgpKeys( 84 | rootProject.ext["signing.keyId"], 85 | rootProject.ext["signing.key"], 86 | rootProject.ext["signing.password"], 87 | ) 88 | sign publishing.publications 89 | 90 | } else { 91 | sign configurations.archives 92 | } 93 | } 94 | java { 95 | sourceCompatibility = JavaVersion.VERSION_1_8 96 | targetCompatibility = JavaVersion.VERSION_1_8 97 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'includeme' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/nz/co/trademe/gradle/includeme/IncludeMePlugin.kt: -------------------------------------------------------------------------------- 1 | package nz.co.trademe.gradle.includeme 2 | 3 | import nz.co.trademe.gradle.includeme.model.IncludeMeProject 4 | import nz.co.trademe.gradle.includeme.model.isEnabled 5 | import nz.co.trademe.gradle.includeme.util.Constants 6 | import nz.co.trademe.gradle.includeme.util.PropertiesHelper 7 | import nz.co.trademe.gradle.includeme.util.isGradleProject 8 | import nz.co.trademe.gradle.includeme.util.log 9 | import nz.co.trademe.gradle.includeme.util.projectDirectory 10 | import org.gradle.api.Plugin 11 | import org.gradle.api.initialization.Settings 12 | import org.gradle.api.plugins.PluginAware 13 | import java.io.File 14 | import java.util.* 15 | 16 | class IncludeMePlugin : Plugin { 17 | 18 | override fun apply(project: PluginAware) { 19 | if (project !is Settings) { 20 | return 21 | } 22 | 23 | val projects = findGradleProjects(project).apply { 24 | log("Found ${this.size} projects to include") 25 | } 26 | 27 | val includeProperties = PropertiesHelper.findIncludeProperties(project.projectDirectory) 28 | 29 | //clear properties 30 | val keysToRemove = includeProperties.keys.toList() - projects.map { it.name } 31 | keysToRemove.onEach { includeProperties.remove(it) } 32 | 33 | projects.onEach { addProjectToIncludeProperties(includeProperties, it) } 34 | 35 | includeProperties.store(File(Constants.INCLUDE_PROPERTIES).outputStream(), null) 36 | 37 | projects.onEach { includeProject(project, it) } 38 | 39 | log("IncludeMe plugin applied") 40 | } 41 | 42 | /** 43 | * Adds an entry into the include.properties file for the given config 44 | */ 45 | private fun addProjectToIncludeProperties(props: Properties, config: IncludeMeProject) { 46 | if (!props.containsKey(config.name)) { 47 | props.setProperty(config.name, false.toString()) 48 | } 49 | } 50 | 51 | /** 52 | * Includes the external project into the current projects build. 53 | * 54 | * This is including a build with Gradle's composite builds API which handles dependency 55 | * resolution also. 56 | */ 57 | private fun includeProject(settings: Settings, config: IncludeMeProject) { 58 | if (config.isEnabled(settings)) { 59 | log("Including ${config.name} as project") 60 | 61 | if (config.directory.exists()) { 62 | settings.includeBuild(config.projectPath) 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * Finds Gradle projects in the search paths. 69 | * 70 | * Filters out projects that aren't on a whitelist. 71 | * 72 | * If no search paths are defined, the parent folder of the project will be used 73 | */ 74 | private fun findGradleProjects(project: Settings): List { 75 | val searchPaths = findSearchPaths(project) 76 | val whitelistedProjects = findWhitelistedProjects(project) 77 | 78 | val gradleProjects = searchPaths.map { 79 | it.listFiles() 80 | .filter { it.isGradleProject() } 81 | .filter { 82 | if (whitelistedProjects.isNotEmpty()) whitelistedProjects.contains(it.name) else true 83 | } 84 | .map { 85 | IncludeMeProject(it.name, it) 86 | } 87 | }.flatten() 88 | 89 | return gradleProjects 90 | } 91 | 92 | /** 93 | * Finds any projects declared in a whitelist 94 | */ 95 | private fun findWhitelistedProjects(settings: Settings): List { 96 | return PropertiesHelper.findAllGradleProperties(settings) 97 | .mapNotNull { 98 | it.getProperty("includeme.whitelist") 99 | } 100 | .map { it.split(",") } 101 | .flatten() 102 | } 103 | 104 | /** 105 | * Finds any declared search paths 106 | */ 107 | private fun findSearchPaths(settings: Settings): List { 108 | val parentSearchPath = listOf(settings.projectDirectory.parentFile?.absolutePath) 109 | 110 | val declaredSearchPaths = PropertiesHelper.findAllGradleProperties(settings) 111 | .mapNotNull { 112 | it.getProperty("includeme.searchpaths") 113 | } 114 | 115 | val searchPaths: List = if (declaredSearchPaths.isEmpty()) parentSearchPath else declaredSearchPaths 116 | 117 | return searchPaths 118 | .mapNotNull { it?.split(",") } 119 | .flatten() 120 | .map { it.replaceFirst("~", System.getProperty("user.home")) } 121 | .map { File(it) } 122 | .filter { it.exists() } 123 | } 124 | 125 | } 126 | 127 | 128 | -------------------------------------------------------------------------------- /src/main/java/nz/co/trademe/gradle/includeme/model/IncludeMeProject.kt: -------------------------------------------------------------------------------- 1 | package nz.co.trademe.gradle.includeme.model 2 | 3 | import nz.co.trademe.gradle.includeme.util.Constants 4 | import nz.co.trademe.gradle.includeme.util.PropertiesHelper 5 | import nz.co.trademe.gradle.includeme.util.projectDirectory 6 | import org.gradle.api.initialization.Settings 7 | import java.io.File 8 | 9 | data class IncludeMeProject(val name: String, val directory: File) { 10 | val projectPath: String = directory.absolutePath 11 | } 12 | 13 | fun IncludeMeProject.isEnabled(plugin: Settings): Boolean { 14 | return plugin.projectDirectory.let { 15 | val includeProperties = PropertiesHelper.readProperties(File(it, Constants.INCLUDE_PROPERTIES)) 16 | includeProperties.keys.contains(name) && includeProperties.getProperty(name).toBoolean() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/nz/co/trademe/gradle/includeme/util/Constants.kt: -------------------------------------------------------------------------------- 1 | package nz.co.trademe.gradle.includeme.util 2 | 3 | class Constants { 4 | companion object { 5 | const val GRADLE_PROPERTIES = "gradle.properties" 6 | const val LOCAL_PROPERTIES = "local.properties" 7 | const val INCLUDE_PROPERTIES = "include.properties" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/java/nz/co/trademe/gradle/includeme/util/Extensions.kt: -------------------------------------------------------------------------------- 1 | package nz.co.trademe.gradle.includeme.util 2 | 3 | import org.gradle.api.initialization.Settings 4 | import java.io.File 5 | 6 | val Settings.projectDirectory: File 7 | get() = rootProject.projectDir 8 | 9 | fun File.isGradleProject(): Boolean { 10 | return File(absolutePath, "settings.gradle").exists() || File(absolutePath, "settings.gradle.kts").exists() 11 | } -------------------------------------------------------------------------------- /src/main/java/nz/co/trademe/gradle/includeme/util/Log.kt: -------------------------------------------------------------------------------- 1 | package nz.co.trademe.gradle.includeme.util 2 | 3 | import nz.co.trademe.gradle.includeme.IncludeMePlugin 4 | import org.gradle.api.logging.Logging 5 | import org.slf4j.Logger 6 | import org.slf4j.LoggerFactory 7 | 8 | val logger: Logger = LoggerFactory.getLogger(IncludeMePlugin::class.simpleName) 9 | 10 | fun log(message: String) { 11 | logger.info(Logging.LIFECYCLE, "[IncludeMe] $message") 12 | } 13 | 14 | fun logI(message: String) { 15 | logger.info("[IncludeMe] $message") 16 | } 17 | 18 | fun logD(message: String) { 19 | logger.debug("[IncludeMe] $message") 20 | } -------------------------------------------------------------------------------- /src/main/java/nz/co/trademe/gradle/includeme/util/PropertiesHelper.kt: -------------------------------------------------------------------------------- 1 | package nz.co.trademe.gradle.includeme.util 2 | 3 | import org.gradle.api.initialization.Settings 4 | import org.gradle.api.invocation.Gradle 5 | import java.io.File 6 | import java.util.* 7 | 8 | class PropertiesHelper private constructor() { 9 | 10 | companion object { 11 | 12 | fun findIncludeProperties(projectDirectory: File): Properties { 13 | return readProperties(File(projectDirectory, Constants.INCLUDE_PROPERTIES)) 14 | } 15 | 16 | fun findUsersGradleProperties(gradle: Gradle): Properties? { 17 | val gradleProperties = File(gradle.gradleUserHomeDir, Constants.GRADLE_PROPERTIES) 18 | 19 | if (gradleProperties.exists()) { 20 | return readProperties(gradleProperties) 21 | } 22 | return null 23 | } 24 | 25 | fun findGradleProperties(projectDirectory: File): Properties? { 26 | val localProperties = File(projectDirectory, Constants.GRADLE_PROPERTIES) 27 | return if (localProperties.exists()) { 28 | readProperties(localProperties) 29 | } else { 30 | null 31 | } 32 | } 33 | 34 | fun findLocalProperties(projectDirectory: File): Properties? { 35 | val localProperties = File(projectDirectory, Constants.LOCAL_PROPERTIES) 36 | return if (localProperties.exists()) { 37 | readProperties(localProperties) 38 | } else { 39 | null 40 | } 41 | } 42 | 43 | fun findAllGradleProperties(settings: Settings): List { 44 | return listOfNotNull(findUsersGradleProperties(settings.gradle), findLocalProperties(settings.projectDirectory), findGradleProperties(settings.projectDirectory)) 45 | } 46 | 47 | fun readProperties(file: File): Properties { 48 | return Properties().apply { 49 | if (file.exists()) load(file.inputStream()) 50 | } 51 | } 52 | 53 | } 54 | } --------------------------------------------------------------------------------