From f17c78a5f8fb35bb1992706e20f495284a0e6f5e Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Mon, 7 Oct 2024 08:39:34 +1300 Subject: [PATCH 1/3] feat: rock push task Add rock push task to simplify local rock builds and testing. --- .../rockcraft/gradle/PushRockcraftTask.java | 35 +++++++++++++++++++ .../rockcraft/gradle/RockcraftPlugin.java | 7 +++- .../rockcraft/builder/RockBuilder.java | 32 +++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 rockcraft-gradle/src/main/java/com/canonical/rockcraft/gradle/PushRockcraftTask.java 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/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java b/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java index 784274a..a05f671 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); + } + } + /** * Builds the rock image * @@ -76,4 +95,17 @@ public static void buildRock(RockProjectSettings settings, RockcraftOptions opti Files.move(source, destination); } } + + private static void copyInDocker(File ociImage, String imageName) 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 " + imageName); + } } From 333835a339f0b3991eefcbb5773413fb1775a514 Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Tue, 8 Oct 2024 09:54:46 +1300 Subject: [PATCH 2/3] fix: tag the image in push rock --- .../canonical/rockcraft/builder/RockBuilder.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) 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 a05f671..25d0ac6 100644 --- a/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java +++ b/rockcraft/src/main/java/com/canonical/rockcraft/builder/RockBuilder.java @@ -62,7 +62,7 @@ public static void pushRock(RockProjectSettings settings, RockcraftOptions optio 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); + copyInDocker(file, imageName, imageVersion); } } @@ -96,7 +96,7 @@ public static void buildRock(RockProjectSettings settings, RockcraftOptions opti } } - private static void copyInDocker(File ociImage, String imageName) throws IOException, InterruptedException { + 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()), @@ -106,6 +106,15 @@ private static void copyInDocker(File ociImage, String imageName) throws IOExcep Process process = pb.start(); int result = process.waitFor(); if (result != 0) - throw new UnsupportedOperationException("Failed to copy " + ociImage.getAbsolutePath() + " to docker image " + imageName); + 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)); } } From 324416ca064e365d2a9ae4d7ed620aa6decf4ebf Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Tue, 8 Oct 2024 10:12:54 +1300 Subject: [PATCH 3/3] test: add smoke test for push --- .../rockcraft/gradle/RockcraftPluginTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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");