/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.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. */ // This verifies local git repository's status. import org.eclipse.jgit.api.* import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.eclipse.jgit.errors.* import java.nio.file.FileVisitResult import java.nio.file.Files import java.nio.file.SimpleFileVisitor import java.nio.file.Path import java.nio.file.attribute.BasicFileAttributes buildscript { repositories { mavenCentral() } dependencies { classpath "org.eclipse.jgit:org.eclipse.jgit:${scriptDepVersions['jgit']}" } } configure(rootProject) { task gitStatus() { doFirst { try { def repository = new FileRepositoryBuilder() .setWorkTree(rootProject.projectDir) .setMustExist(true) .build() def ref = repository.findRef("HEAD").getObjectId() project.ext.gitRev = ref.name() project.ext.gitRevShort = ref.abbreviate(8).name() project.ext.gitStatus = new Git(repository).status().call() } catch (RepositoryNotFoundException | NoWorkTreeException e) { project.ext.gitRev = "(not a git checkout)" project.ext.gitRevShort = "(not a git checkout)" project.ext.gitStatus = null } catch (NotSupportedException e) { throw new GradleException("jgit does not support git repository version at this location: ${dir}", e) } } } // Verify git working copy does not have any unstaged modified files. task checkWorkingCopyClean() { dependsOn gitStatus doFirst { def status = rootProject.ext.gitStatus if (status == null) { if (file("${rootProject.projectDir}/.git").exists()) { // Ignore git worktree branches until jgit supports them. logger.warn("WARNING: git worktrees are not supported by jgit (won't check dirty files): ${rootProject.projectDir}") } else { // Ignore the check. This isn't a git checkout. logger.warn("WARNING: Directory is not a valid git checkout (won't check dirty files): ${rootProject.projectDir}") } } else { // git ignores any folders which are empty (this includes folders with recursively empty sub-folders). def untrackedNonEmptyFolders = status.untrackedFolders.findAll { path -> File location = file("${rootProject.projectDir}/${path}") boolean hasFiles = false Files.walkFileTree(location.toPath(), new SimpleFileVisitor() { @Override FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { hasFiles = true // Terminate early. return FileVisitResult.TERMINATE } }) return hasFiles } def offenders = [ // Exclude staged changes. These are fine in precommit. // "(added)": status.added, // "(changed)": status.changed, // "(removed)": status.removed, "(conflicting)": status.conflicting, "(missing)": status.missing, "(modified)": status.modified, "(untracked)": status.untracked, "(untracked non-empty dir)": untrackedNonEmptyFolders ].collectMany { fileStatus, files -> files.collect {file -> " - ${file} ${fileStatus}" } }.sort() if (offenders) { def checkProp = "validation.git.failOnModified" def shouldFail = Boolean.valueOf(propertyOrDefault(checkProp, true)) def message = "Working copy is not a clean git checkout" + (shouldFail ? " (skip with -P${checkProp}=false)" : "") + ", offending files:\n${offenders.join("\n")}" if (shouldFail) { throw new GradleException(message) } else { logger.lifecycle("NOTE: ${message}") } } } } } }