diff --git a/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/PushRockcraftTask.java b/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/PushRockcraftTask.java new file mode 100644 index 0000000..eec92be --- /dev/null +++ b/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/PushRockcraftTask.java @@ -0,0 +1,35 @@ +package com.canonical.rockcraft.gradle; + +import com.canonical.rockcraft.builder.RockBuilder; +import com.canonical.rockcraft.builder.RockcraftOptions; +import org.gradle.api.tasks.TaskAction; + +import javax.inject.Inject; +import java.io.IOException; + +/** + * This task pushes rock image to the local docker + */ +public class PushRockcraftTask extends AbstractRockcraftTask { + + /** + * Constructs PushRockcraftTask + * + * @param options - rockcraft options + */ + @Inject + public PushRockcraftTask(RockcraftOptions options) { + super(options); + } + + /** + * The task action + * + * @throws IOException - IO error while writing rockcraft.yaml + * @throws InterruptedException - rockcraft process was aborted + */ + @TaskAction + public void pushRock() throws IOException, InterruptedException { + RockBuilder.buildRock(RockSettingsFactory.createRockProjectSettings(getProject()), getOptions()); + } +} diff --git a/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/RockcraftPlugin.java b/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/RockcraftPlugin.java index b268223..30afa0b 100644 --- a/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/RockcraftPlugin.java +++ b/rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/RockcraftPlugin.java @@ -42,6 +42,7 @@ public RockcraftPlugin() { /** * Applies the plugin + * * @param project The target object */ public void apply(Project project) { @@ -78,9 +79,13 @@ public void apply(Project project) { if (tasks.isEmpty()) throw new UnsupportedOperationException("Rockcraft plugin requires bootJar or jar task"); - project.getTasks().register("build-rock", BuildRockcraftTask.class, options); + TaskProvider push = project.getTasks().register("push-rock", PushRockcraftTask.class, options); + TaskProvider build = project.getTasks().register("build-rock", BuildRockcraftTask.class, options); TaskProvider create = project.getTasks().register("create-rock", CreateRockcraftTask.class, options); + project.getTasks().getByName("push-rock") + .dependsOn(build); + project.getTasks().getByName("build-rock") .dependsOn(create); diff --git a/rockcraft-gradle/src/test/java/com/canonical/rockcraft/gradle/RockcraftPluginTest.java b/rockcraft-gradle/src/test/java/com/canonical/rockcraft/gradle/RockcraftPluginTest.java index 5abf82d..4af8af0 100644 --- a/rockcraft-gradle/src/test/java/com/canonical/rockcraft/gradle/RockcraftPluginTest.java +++ b/rockcraft-gradle/src/test/java/com/canonical/rockcraft/gradle/RockcraftPluginTest.java @@ -36,6 +36,17 @@ void buildRockTest() throws IOException { assertEquals(TaskOutcome.SUCCESS, getLastTaskOutcome(result)); // the build needs to succeed } + /** + * Make a separate test for pushing, so that it could be excluded in docker-less + * scenarios + * @throws IOException + */ + @Test + void pushRockTest() throws IOException { + BuildResult result = runBuild("push-rock"); + assertEquals(TaskOutcome.SUCCESS, getLastTaskOutcome(result)); // the build needs to succeed + } + @Test void validRockcraftYaml() throws IOException { runBuild("create-rock"); diff --git a/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java b/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java index 784274a..25d0ac6 100644 --- a/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java +++ b/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java @@ -47,6 +47,25 @@ public static void checkRockcraft() throws InterruptedException, IOException { throw new UnsupportedOperationException("Please install rockcraft 'snap install rockcraft'."); } + /** + * Pushes rock image to the docker + * + * @param settings - rockcraft project settings + * @throws IOException - IO error while writing rockcraft.yaml + * @throws InterruptedException - rockcraft process was aborted + */ + @SuppressWarnings("unchecked") + public static void pushRock(RockProjectSettings settings, RockcraftOptions options) throws InterruptedException, IOException { + Yaml yaml = new Yaml(); + Map rockcraft = (Map) yaml.load(new FileReader(settings.getRockOutput().resolve(IRockcraftNames.ROCKCRAFT_YAML).toFile())); + String imageName = String.valueOf(rockcraft.get(IRockcraftNames.ROCKCRAFT_NAME)); + String imageVersion = String.valueOf(rockcraft.get(IRockcraftNames.ROCKCRAFT_VERSION)); + Path rockDestPath = settings.getRockOutput().resolve(IRockcraftNames.ROCK_OUTPUT); + for (File file : rockDestPath.toFile().listFiles((dir, file) -> file.endsWith(".rock"))) { + copyInDocker(file, imageName, imageVersion); + } + } + /** * Builds the rock image * @@ -76,4 +95,26 @@ public static void buildRock(RockProjectSettings settings, RockcraftOptions opti Files.move(source, destination); } } + + private static void copyInDocker(File ociImage, String imageName, String imageVersion) throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder("rockcraft.skopeo", + "copy", + String.format("oci-archive:%s", ociImage.getAbsolutePath()), + String.format("docker-daemon:%s:latest", imageName)) + .directory(ociImage.getParentFile()) + .inheritIO(); + Process process = pb.start(); + int result = process.waitFor(); + if (result != 0) + throw new UnsupportedOperationException("Failed to copy " + ociImage.getAbsolutePath() + " to docker image " + String.format("%s:latest", imageName)); + + pb = new ProcessBuilder("docker", "tag", imageName, + String.format("%s:%s", imageName, imageVersion)) + .directory(ociImage.getParentFile()) + .inheritIO(); + process = pb.start(); + result = process.waitFor(); + if (result != 0) + throw new UnsupportedOperationException("Failed to tag " + String.format("%s:%s", imageName, imageVersion)); + } }