From 4eef8d5a5351ee97005aea4b746f3117d9cddbec Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Wed, 10 May 2023 09:20:10 +0200 Subject: [PATCH 1/2] Separate tag in the Docker API tag call Closes gh-35358 --- .../buildpack/platform/docker/DockerApi.java | 11 +++++++- .../platform/docker/type/ImageReference.java | 14 +++++++++- .../platform/docker/DockerApiTests.java | 13 +++++++++- .../docker/type/ImageReferenceTests.java | 26 +++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java index eee724006b96..0f806c8b6ddb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java @@ -65,6 +65,7 @@ * @author Phillip Webb * @author Scott Frederick * @author Rafael Ceccone + * @author Moritz Halbritter * @since 2.3.0 */ public class DockerApi { @@ -346,7 +347,15 @@ public Image inspect(ImageReference reference) throws IOException { public void tag(ImageReference sourceReference, ImageReference targetReference) throws IOException { Assert.notNull(sourceReference, "SourceReference must not be null"); Assert.notNull(targetReference, "TargetReference must not be null"); - URI uri = buildUrl("/images/" + sourceReference + "/tag", "repo", targetReference.toString()); + String tag = targetReference.getTag(); + URI uri; + if (tag == null) { + uri = buildUrl("/images/" + sourceReference + "/tag", "repo", targetReference.toString()); + } + else { + uri = buildUrl("/images/" + sourceReference + "/tag", "repo", + targetReference.inTaglessForm().toString(), "tag", tag); + } http().post(uri).close(); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java index c2a3d7aae08d..3f07f53166e1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ * * @author Phillip Webb * @author Scott Frederick + * @author Moritz Halbritter * @since 2.3.0 * @see ImageName */ @@ -153,6 +154,17 @@ public ImageReference inTaggedForm() { return new ImageReference(this.name, (this.tag != null) ? this.tag : LATEST, null); } + /** + * Return an {@link ImageReference} without the tag. + * @return the image reference in tagless form + */ + public ImageReference inTaglessForm() { + if (this.tag == null) { + return this; + } + return new ImageReference(this.name, null, this.digest); + } + /** * Return an {@link ImageReference} containing either a tag or a digest. If neither * the digest nor the tag has been defined then tag {@code latest} is used. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java index 8410e401b7e4..f974129c89f0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java @@ -75,6 +75,7 @@ * @author Phillip Webb * @author Scott Frederick * @author Rafael Ceccone + * @author Moritz Halbritter */ @ExtendWith(MockitoExtension.class) class DockerApiTests { @@ -419,7 +420,17 @@ void tagWhenTargetIsNullThrowsException() { void tagTagsImage() throws Exception { ImageReference sourceReference = ImageReference.of("localhost:5000/ubuntu"); ImageReference targetReference = ImageReference.of("localhost:5000/ubuntu:tagged"); - URI tagURI = new URI(IMAGES_URL + "/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu%3Atagged"); + URI tagURI = new URI(IMAGES_URL + "/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu&tag=tagged"); + given(http().post(tagURI)).willReturn(emptyResponse()); + this.api.tag(sourceReference, targetReference); + then(http()).should().post(tagURI); + } + + @Test + void tagRenamesImage() throws Exception { + ImageReference sourceReference = ImageReference.of("localhost:5000/ubuntu"); + ImageReference targetReference = ImageReference.of("localhost:5000/ubuntu-2"); + URI tagURI = new URI(IMAGES_URL + "/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu-2"); given(http().post(tagURI)).willReturn(emptyResponse()); this.api.tag(sourceReference, targetReference); then(http()).should().post(tagURI); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java index b5ad72e1ef7d..7c0c7918e827 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java @@ -29,6 +29,7 @@ * * @author Phillip Webb * @author Scott Frederick + * @author Moritz Halbritter */ class ImageReferenceTests { @@ -272,4 +273,29 @@ void equalsAndHashCode() { assertThat(r1).isEqualTo(r1).isEqualTo(r2).isNotEqualTo(r3); } + @Test + void withDigest() { + ImageReference reference = ImageReference.of("docker.io/library/ubuntu:bionic"); + ImageReference updated = reference + .withDigest("sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + assertThat(updated).hasToString( + "docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + } + + @Test + void inTaglessFormWithDigest() { + ImageReference reference = ImageReference + .of("docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + ImageReference updated = reference.inTaglessForm(); + assertThat(updated).hasToString( + "docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + } + + @Test + void inTaglessForm() { + ImageReference reference = ImageReference.of("docker.io/library/ubuntu:bionic"); + ImageReference updated = reference.inTaglessForm(); + assertThat(updated).hasToString("docker.io/library/ubuntu"); + } + } From d00e070cdb0247d7050ccdd58041d5fd04789de3 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Wed, 10 May 2023 09:20:10 +0200 Subject: [PATCH 2/2] Separate tag in the Docker API tag call Closes gh-35358 --- .../buildpack/platform/docker/DockerApi.java | 11 +++++++- .../platform/docker/type/ImageReference.java | 14 +++++++++- .../platform/docker/DockerApiTests.java | 13 +++++++++- .../docker/type/ImageReferenceTests.java | 26 +++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java index eee724006b96..0f806c8b6ddb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java @@ -65,6 +65,7 @@ * @author Phillip Webb * @author Scott Frederick * @author Rafael Ceccone + * @author Moritz Halbritter * @since 2.3.0 */ public class DockerApi { @@ -346,7 +347,15 @@ public Image inspect(ImageReference reference) throws IOException { public void tag(ImageReference sourceReference, ImageReference targetReference) throws IOException { Assert.notNull(sourceReference, "SourceReference must not be null"); Assert.notNull(targetReference, "TargetReference must not be null"); - URI uri = buildUrl("/images/" + sourceReference + "/tag", "repo", targetReference.toString()); + String tag = targetReference.getTag(); + URI uri; + if (tag == null) { + uri = buildUrl("/images/" + sourceReference + "/tag", "repo", targetReference.toString()); + } + else { + uri = buildUrl("/images/" + sourceReference + "/tag", "repo", + targetReference.inTaglessForm().toString(), "tag", tag); + } http().post(uri).close(); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java index c2a3d7aae08d..3f07f53166e1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ * * @author Phillip Webb * @author Scott Frederick + * @author Moritz Halbritter * @since 2.3.0 * @see ImageName */ @@ -153,6 +154,17 @@ public ImageReference inTaggedForm() { return new ImageReference(this.name, (this.tag != null) ? this.tag : LATEST, null); } + /** + * Return an {@link ImageReference} without the tag. + * @return the image reference in tagless form + */ + public ImageReference inTaglessForm() { + if (this.tag == null) { + return this; + } + return new ImageReference(this.name, null, this.digest); + } + /** * Return an {@link ImageReference} containing either a tag or a digest. If neither * the digest nor the tag has been defined then tag {@code latest} is used. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java index 009379f85427..2bb460b85cd1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java @@ -75,6 +75,7 @@ * @author Phillip Webb * @author Scott Frederick * @author Rafael Ceccone + * @author Moritz Halbritter */ @ExtendWith(MockitoExtension.class) class DockerApiTests { @@ -419,7 +420,17 @@ void tagWhenTargetIsNullThrowsException() { void tagTagsImage() throws Exception { ImageReference sourceReference = ImageReference.of("localhost:5000/ubuntu"); ImageReference targetReference = ImageReference.of("localhost:5000/ubuntu:tagged"); - URI tagURI = new URI(IMAGES_URL + "/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu%3Atagged"); + URI tagURI = new URI(IMAGES_URL + "/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu&tag=tagged"); + given(http().post(tagURI)).willReturn(emptyResponse()); + this.api.tag(sourceReference, targetReference); + then(http()).should().post(tagURI); + } + + @Test + void tagRenamesImage() throws Exception { + ImageReference sourceReference = ImageReference.of("localhost:5000/ubuntu"); + ImageReference targetReference = ImageReference.of("localhost:5000/ubuntu-2"); + URI tagURI = new URI(IMAGES_URL + "/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu-2"); given(http().post(tagURI)).willReturn(emptyResponse()); this.api.tag(sourceReference, targetReference); then(http()).should().post(tagURI); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java index 97fa86d1d1ae..61940e44c8e5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java @@ -29,6 +29,7 @@ * * @author Phillip Webb * @author Scott Frederick + * @author Moritz Halbritter */ class ImageReferenceTests { @@ -272,4 +273,29 @@ void equalsAndHashCode() { assertThat(r1).isEqualTo(r1).isEqualTo(r2).isNotEqualTo(r3); } + @Test + void withDigest() { + ImageReference reference = ImageReference.of("docker.io/library/ubuntu:bionic"); + ImageReference updated = reference + .withDigest("sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + assertThat(updated).hasToString( + "docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + } + + @Test + void inTaglessFormWithDigest() { + ImageReference reference = ImageReference + .of("docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + ImageReference updated = reference.inTaglessForm(); + assertThat(updated).hasToString( + "docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"); + } + + @Test + void inTaglessForm() { + ImageReference reference = ImageReference.of("docker.io/library/ubuntu:bionic"); + ImageReference updated = reference.inTaglessForm(); + assertThat(updated).hasToString("docker.io/library/ubuntu"); + } + }