/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.gradle.plugins.defaults.tasks; import com.liferay.gradle.plugins.baseline.BaselinePlugin; import com.liferay.gradle.plugins.change.log.builder.BuildChangeLogTask; import com.liferay.gradle.plugins.change.log.builder.ChangeLogBuilderPlugin; import com.liferay.gradle.plugins.defaults.internal.util.FileUtil; import com.liferay.gradle.plugins.defaults.internal.util.GradleUtil; import com.liferay.gradle.util.Validator; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.file.FileCollection; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskContainer; import org.gradle.util.GUtil; import org.gradle.util.VersionNumber; /** * @author Andrea Di Giorgi */ public class WriteArtifactPublishCommandsTask extends DefaultTask { public static final String IGNORED_MESSAGE_PATTERN = "artifact:ignore"; public WriteArtifactPublishCommandsTask() { String firstOnlyString = GradleUtil.getTaskPrefixedProperty( this, "first"); if (Validator.isNotNull(firstOnlyString)) { _firstOnly = Boolean.parseBoolean(firstOnlyString); } _gradleDaemon = true; String gradleDaemonString = GradleUtil.getTaskPrefixedProperty( this, "daemon"); if (Validator.isNotNull(gradleDaemonString)) { _gradleDaemon = Boolean.parseBoolean(gradleDaemonString); } Project project = getProject(); _gradleDir = GradleUtil.getRootDir(project.getRootProject(), "gradlew"); } @Input @Optional public File getArtifactPropertiesFile() { return GradleUtil.toFile(getProject(), _artifactPropertiesFile); } @Input @Optional public String getFirstPublishExcludedTaskName() { return GradleUtil.toString(_firstPublishExcludedTaskName); } @Input public File getGradleDir() { return GradleUtil.toFile(getProject(), _gradleDir); } @Input public String getLowestPublishedVersion() { return GradleUtil.toString(_lowestPublishedVersion); } @Input public File getOutputDir() { return GradleUtil.toFile(getProject(), _outputDir); } @Input public Map<String, FileCollection> getPrepNextCommitFiles() { Project project = getProject(); Map<String, FileCollection> prepNextCommitFileCollections = new LinkedHashMap<>(); for (Map.Entry<String, Set<Object>> entry : _prepNextCommitFiles.entrySet()) { prepNextCommitFileCollections.put( entry.getKey(), project.files(entry.getValue())); } return prepNextCommitFileCollections; } @Input public FileCollection getPrepNextFiles() { Project project = getProject(); return project.files(_prepNextFiles); } public boolean isFirstOnly() { return _firstOnly; } @Input public boolean isForcedCache() { return _forcedCache; } @Input public boolean isGradleDaemon() { return _gradleDaemon; } public WriteArtifactPublishCommandsTask prepNextCommitFile( String message, File file) { Set<Object> files = _prepNextCommitFiles.get(message); if (files == null) { files = new HashSet<>(); _prepNextCommitFiles.put(message, files); } files.add(file); return this; } public WriteArtifactPublishCommandsTask prepNextFiles( Iterable<?> prepNextFiles) { GUtil.addToCollection(_prepNextFiles, prepNextFiles); return this; } public WriteArtifactPublishCommandsTask prepNextFiles( Object... prepNextFiles) { return prepNextFiles(Arrays.asList(prepNextFiles)); } public void setArtifactPropertiesFile(Object artifactPropertiesFile) { _artifactPropertiesFile = artifactPropertiesFile; } public void setFirstOnly(boolean firstOnly) { _firstOnly = firstOnly; } public void setFirstPublishExcludedTaskName( Object firstPublishExcludedTaskName) { _firstPublishExcludedTaskName = firstPublishExcludedTaskName; } public void setForcedCache(boolean forcedCache) { _forcedCache = forcedCache; } public void setGradleDaemon(boolean gradleDaemon) { _gradleDaemon = gradleDaemon; } public void setGradleDir(Object gradleDir) { _gradleDir = gradleDir; } public void setLowestPublishedVersion(Object lowestPublishedVersion) { _lowestPublishedVersion = lowestPublishedVersion; } public void setOutputDir(Object outputDir) { _outputDir = outputDir; } public void setPrepNextFiles(Iterable<?> prepNextFiles) { _prepNextFiles.clear(); prepNextFiles(prepNextFiles); } public void setPrepNextFiles(Object... prepNextFiles) { setPrepNextFiles(Arrays.asList(prepNextFiles)); } @TaskAction public void writeArtifactPublishCommands() throws IOException { _writeArtifactPublishCommandsStep1(); _writeArtifactPublishCommandsStep2(); _writeArtifactPublishCommandsStep3(); if (isFirstOnly()) { throw new GradleException(); } } private void _addPrepNextCommitCommands( List<String> commands, String message, Iterable<File> files, boolean checkExistence) { boolean prepNext = false; for (File file : files) { if (checkExistence && !file.exists()) { continue; } prepNext = true; commands.add("git add " + _getRelativePath(file)); } if (!checkExistence || prepNext) { commands.add( _getGitCommitCommand(message, false, true, !checkExistence)); } } private void _addPublishCommands( List<String> commands, boolean firstPublish) { // Publish snapshot commands.add( _getGradleCommand( BasePlugin.UPLOAD_ARCHIVES_TASK_NAME, "-P" + GradleUtil.SNAPSHOT_PROPERTY_NAME)); // Publish release String[] arguments = new String[0]; if (firstPublish) { Task task = _getTask(getFirstPublishExcludedTaskName()); if (task != null) { arguments = new String[] {"-x", task.getPath()}; } } commands.add( _getGradleCommand(BasePlugin.UPLOAD_ARCHIVES_TASK_NAME, arguments)); // Commit "prep next" _addPrepNextCommitCommands( commands, "prep next", getPrepNextFiles(), true); // Other "prep next" commits Map<String, FileCollection> prepNextCommitFileCollections = getPrepNextCommitFiles(); for (Map.Entry<String, FileCollection> entry : prepNextCommitFileCollections.entrySet()) { _addPrepNextCommitCommands( commands, entry.getKey(), entry.getValue(), false); } // Commit "artifact properties" File artifactPropertiesFile = getArtifactPropertiesFile(); if (artifactPropertiesFile != null) { commands.add("git add " + _getRelativePath(artifactPropertiesFile)); commands.add( _getGitCommitCommand( "artifact properties", false, true, false)); } // Commit other changed files commands.add(_getGitCommitCommand("apply", true, false, true)); } private String _getGitCommitCommand( String message, boolean all, boolean ignored, boolean quiet) { StringBuilder sb = new StringBuilder(); Project project = getProject(); if (all) { sb.append("(git diff --quiet || "); } else if (quiet) { sb.append("(git diff --cached --quiet || "); } sb.append("git commit "); if (all) { sb.append("--all "); } sb.append("--message=\""); if (ignored) { sb.append(IGNORED_MESSAGE_PATTERN); sb.append(' '); } sb.append(project.getName()); sb.append(' '); sb.append(project.getVersion()); sb.append(' '); sb.append(message); sb.append('"'); if (all || quiet) { sb.append(')'); } return sb.toString(); } private String _getGradleCommand(String taskName, String... arguments) { Task task = GradleUtil.getTask(getProject(), taskName); return _getGradleCommand(task, arguments); } private String _getGradleCommand(Task task, String... arguments) { StringBuilder sb = new StringBuilder(); sb.append(_getGradleRelativePath()); sb.append(' '); sb.append(task.getPath()); if (isGradleDaemon()) { sb.append(" --daemon"); } if (isForcedCache() && !BaselinePlugin.BASELINE_TASK_NAME.equals(task.getName())) { sb.append(" -Dforced.cache.enabled=true"); } for (String argument : arguments) { sb.append(' '); sb.append(argument); } return sb.toString(); } private File _getGradleFile() { return new File(getGradleDir(), "gradlew"); } private String _getGradleRelativePath() { return _getRelativePath(_getGradleFile()); } private BufferedWriter _getOutputBufferedWriter(int step) throws IOException { File dir = getOutputDir(); Path dirPath = dir.toPath(); Files.createDirectories(dirPath); return Files.newBufferedWriter( dirPath.resolve(getName() + "-step" + step + ".sh"), StandardCharsets.UTF_8, StandardOpenOption.APPEND, StandardOpenOption.CREATE); } private String _getRelativePath(Object object) { Project project = getProject(); File file = project.file(object); Project rootProject = project.getRootProject(); return rootProject.relativePath(file); } private Task _getTask(String name) { if (Validator.isNull(name)) { return null; } Project project = getProject(); TaskContainer taskContainer = project.getTasks(); return taskContainer.findByName(name); } private boolean _isPublished() { Project project = getProject(); String version = String.valueOf(project.getVersion()); VersionNumber versionNumber = VersionNumber.parse(version); VersionNumber lowestPublishedVersionNumber = VersionNumber.parse( getLowestPublishedVersion()); if (versionNumber.compareTo(lowestPublishedVersionNumber) > 0) { return true; } return false; } private void _writeArtifactPublishCommandsStep1() throws IOException { Task baselineTask = _getTask(BaselinePlugin.BASELINE_TASK_NAME); if (baselineTask == null) { return; } Project project = baselineTask.getProject(); try (BufferedWriter bufferedWriter = _getOutputBufferedWriter(1)) { // Move to the root directory bufferedWriter.write("cd "); bufferedWriter.write( FileUtil.getAbsolutePath(project.getRootDir())); // Baseline bufferedWriter.write(" && "); bufferedWriter.write(_getGradleCommand(baselineTask)); bufferedWriter.write(System.lineSeparator()); } } private void _writeArtifactPublishCommandsStep2() throws IOException { Task baselineTask = _getTask(BaselinePlugin.BASELINE_TASK_NAME); if (baselineTask == null) { return; } Project project = getProject(); try (BufferedWriter bufferedWriter = _getOutputBufferedWriter(2)) { // Comment bufferedWriter.write("# "); // Move to the root directory bufferedWriter.write("cd "); bufferedWriter.write( FileUtil.getAbsolutePath(project.getRootDir())); // Baseline bufferedWriter.write(" && "); bufferedWriter.write( _getGradleCommand( baselineTask, "-D" + baselineTask.getName() + ".ignoreFailures=true")); bufferedWriter.write(" && "); bufferedWriter.write( "git add --all " + _getRelativePath(project.getProjectDir())); bufferedWriter.write(" && "); bufferedWriter.write( _getGitCommitCommand("packageinfo", false, false, true)); bufferedWriter.write(System.lineSeparator()); } } private void _writeArtifactPublishCommandsStep3() throws IOException { List<String> commands = new ArrayList<>(); Project project = getProject(); // Move to the root directory commands.add("cd " + FileUtil.getAbsolutePath(project.getRootDir())); // Publish if the artifact has never been published if (!_isPublished()) { _addPublishCommands(commands, true); } // Change log BuildChangeLogTask buildChangeLogTask = (BuildChangeLogTask)_getTask( ChangeLogBuilderPlugin.BUILD_CHANGE_LOG_TASK_NAME); if (buildChangeLogTask != null) { commands.add(_getGradleCommand(buildChangeLogTask)); commands.add( "git add " + _getRelativePath(buildChangeLogTask.getChangeLogFile())); commands.add(_getGitCommitCommand("change log", false, true, true)); } // Baseline Task baselineTask = _getTask(BaselinePlugin.BASELINE_TASK_NAME); if (baselineTask != null) { commands.add(_getGradleCommand(baselineTask)); commands.add( "git add --all " + _getRelativePath(project.getProjectDir())); commands.add( _getGitCommitCommand("packageinfo", false, false, true)); } // Publish the artifact since there will either be change log or // baseline changes if ((baselineTask != null) || (buildChangeLogTask != null)) { _addPublishCommands(commands, false); } try (BufferedWriter bufferedWriter = _getOutputBufferedWriter(3)) { for (int i = 0; i < commands.size(); i++) { if (i > 0) { bufferedWriter.write(" && "); } bufferedWriter.write(commands.get(i)); } bufferedWriter.write(System.lineSeparator()); } } private Object _artifactPropertiesFile; private boolean _firstOnly; private Object _firstPublishExcludedTaskName; private boolean _forcedCache = true; private boolean _gradleDaemon; private Object _gradleDir; private Object _lowestPublishedVersion = "1.0.0"; private Object _outputDir; private final Map<String, Set<Object>> _prepNextCommitFiles = new LinkedHashMap<>(); private final Set<Object> _prepNextFiles = new LinkedHashSet<>(); }