Skip to content

Commit 64bce2e

Browse files
authored
Layer annotations where not added on files during pushArtifact (#583)
2 parents 2d39685 + 4f14cb8 commit 64bce2e

6 files changed

Lines changed: 76 additions & 17 deletions

File tree

src/main/java/land/oras/Annotations.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,27 @@ public Map<String, String> getFileAnnotations(String key) {
8585
return this.filesAnnotations().getOrDefault(key, new HashMap<>());
8686
}
8787

88+
/**
89+
* Check if there are annotations for a file
90+
* @param key The key
91+
* @return True if there are annotations, false otherwise
92+
*/
93+
public boolean hasFileAnnotations(String key) {
94+
return this.filesAnnotations().containsKey(key);
95+
}
96+
97+
/**
98+
* Create a new annotations record with the given file annotations
99+
* @param key The key of the file annotations
100+
* @param annotations The file annotations
101+
* @return The new annotations record
102+
*/
103+
public Annotations withFileAnnotations(String key, Map<String, String> annotations) {
104+
Map<String, Map<String, String>> newFilesAnnotations = new HashMap<>(this.filesAnnotations());
105+
newFilesAnnotations.put(key, annotations);
106+
return new Annotations(this.configAnnotations(), this.manifestAnnotations(), newFilesAnnotations);
107+
}
108+
88109
/**
89110
* Annotations file format
90111
*/

src/main/java/land/oras/OCI.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.nio.file.Path;
2929
import java.nio.file.StandardCopyOption;
3030
import java.util.ArrayList;
31+
import java.util.LinkedHashMap;
3132
import java.util.LinkedList;
3233
import java.util.List;
3334
import java.util.Map;
@@ -156,7 +157,7 @@ protected List<Layer> collectLayers(T ref, String contentType, boolean includeAl
156157
* @param paths The paths to the files
157158
* @return The layers
158159
*/
159-
protected final List<Layer> pushLayers(T ref, boolean withDigest, LocalPath... paths) {
160+
protected final List<Layer> pushLayers(T ref, Annotations annotations, boolean withDigest, LocalPath... paths) {
160161
List<Layer> layers = new ArrayList<>();
161162
for (LocalPath path : paths) {
162163
try {
@@ -172,15 +173,20 @@ protected final List<Layer> pushLayers(T ref, boolean withDigest, LocalPath... p
172173
? path.getPath().getFileName().toString()
173174
: path.getPath().toString();
174175
LOG.debug("Uploading directory as archive with title: {}", title);
176+
177+
Map<String, String> layerAnnotations = annotations.hasFileAnnotations(title)
178+
? annotations.getFileAnnotations(title)
179+
: new LinkedHashMap<>(Map.of(Const.ANNOTATION_TITLE, title));
180+
181+
// Add oras digest/unpack
182+
layerAnnotations.put(
183+
Const.ANNOTATION_ORAS_CONTENT_DIGEST,
184+
ref.getAlgorithm().digest(tempTar.getPath()));
185+
layerAnnotations.put(Const.ANNOTATION_ORAS_UNPACK, "true");
186+
175187
Layer layer = pushBlob(ref, is)
176188
.withMediaType(path.getMediaType())
177-
.withAnnotations(Map.of(
178-
Const.ANNOTATION_TITLE,
179-
title,
180-
Const.ANNOTATION_ORAS_CONTENT_DIGEST,
181-
ref.getAlgorithm().digest(tempTar.getPath()),
182-
Const.ANNOTATION_ORAS_UNPACK,
183-
"true"));
189+
.withAnnotations(layerAnnotations);
184190
layers.add(layer);
185191
LOG.info("Uploaded directory: {}", layer.getDigest());
186192
}
@@ -190,11 +196,14 @@ protected final List<Layer> pushLayers(T ref, boolean withDigest, LocalPath... p
190196
if (withDigest) {
191197
ref = ref.withDigest(ref.getAlgorithm().digest(path.getPath()));
192198
}
199+
String title = path.getPath().getFileName().toString();
200+
Map<String, String> layerAnnotations = annotations.hasFileAnnotations(title)
201+
? annotations.getFileAnnotations(title)
202+
: Map.of(Const.ANNOTATION_TITLE, title);
203+
193204
Layer layer = pushBlob(ref, is)
194205
.withMediaType(path.getMediaType())
195-
.withAnnotations(Map.of(
196-
Const.ANNOTATION_TITLE,
197-
path.getPath().getFileName().toString()));
206+
.withAnnotations(layerAnnotations);
198207
layers.add(layer);
199208
LOG.info("Uploaded: {}", layer.getDigest());
200209
}
@@ -413,7 +422,7 @@ public abstract Manifest pushArtifact(
413422
public Manifest attachArtifact(T ref, ArtifactType artifactType, Annotations annotations, LocalPath... paths) {
414423

415424
// Push layers
416-
List<Layer> layers = pushLayers(ref, true, paths);
425+
List<Layer> layers = pushLayers(ref, annotations, true, paths);
417426

418427
// Get the subject from the descriptor
419428
Descriptor descriptor = getDescriptor(ref);

src/main/java/land/oras/OCILayout.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public Manifest pushArtifact(
8383
}
8484

8585
// Push layers
86-
List<Layer> layers = pushLayers(ref, true, paths);
86+
List<Layer> layers = pushLayers(ref, annotations, true, paths);
8787

8888
// Push the config like any other blob
8989
Config configToPush = config != null ? config : Config.empty();

src/main/java/land/oras/Registry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ public Manifest pushArtifact(
406406
ContainerRef resolvedRef = containerRef.forRegistry(this).forRegistry(resolvedRegistry);
407407

408408
// Push layers
409-
List<Layer> layers = pushLayers(resolvedRef, false, paths);
409+
List<Layer> layers = pushLayers(resolvedRef, annotations, false, paths);
410410

411411
// Add layer and config
412412
manifest = manifest.withLayers(layers).withConfig(pushedConfig);

src/test/java/land/oras/AnnotationsTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package land.oras;
2222

2323
import static org.junit.jupiter.api.Assertions.assertEquals;
24+
import static org.junit.jupiter.api.Assertions.assertFalse;
25+
import static org.junit.jupiter.api.Assertions.assertTrue;
2426

2527
import java.util.Map;
2628
import org.junit.jupiter.api.Test;
@@ -51,6 +53,14 @@ public void nullAnnotations() {
5153
assertEquals(0, annotations.filesAnnotations().size());
5254
}
5355

56+
@Test
57+
public void shouldAddFileAnnotation() {
58+
Annotations annotations = Annotations.empty().withFileAnnotations("cake.txt", Map.of("fun", "more cream"));
59+
assertEquals("more cream", annotations.getFileAnnotations("cake.txt").get("fun"));
60+
assertTrue(annotations.hasFileAnnotations("cake.txt"));
61+
assertFalse(annotations.hasFileAnnotations("nonexistent.txt"));
62+
}
63+
5464
@Test
5565
public void toJson() {
5666
Annotations annotations = new Annotations(

src/test/java/land/oras/RegistryTest.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,14 +1336,33 @@ void testShouldArtifactWithAnnotations() throws IOException {
13361336
Files.writeString(pomFile, "my pom file");
13371337

13381338
// Push the main OCI artifact
1339-
Annotations annotations = Annotations.ofManifest(Map.of("foo", "bar"));
1339+
Annotations annotations =
1340+
Annotations.ofManifest(Map.of("foo", "bar")).withFileAnnotations("jenkins.png", Map.of("foo", "bar"));
1341+
1342+
// Add image (without title (so it's not unpack) and specific annotation)
13401343
Manifest manifest = registry.pushArtifact(
1341-
containerRef, ArtifactType.from(artifactType), annotations, LocalPath.of(pomFile, "application/xml"));
1344+
containerRef,
1345+
ArtifactType.from(artifactType),
1346+
annotations,
1347+
LocalPath.of(pomFile, "application/xml"),
1348+
LocalPath.of(Path.of("src/test/resources/img/jenkins.png"), "image/png"));
13421349

1343-
// Check annotations
1350+
// Check annotations (manifest)
13441351
assertEquals(2, manifest.getAnnotations().size());
13451352
assertEquals("bar", manifest.getAnnotations().get("foo"));
13461353
assertNotNull(manifest.getAnnotations().get(Const.ANNOTATION_CREATED));
1354+
1355+
// Check annotations (layer 0)
1356+
Layer layer = manifest.getLayers().get(0);
1357+
assertEquals(1, layer.getAnnotations().size());
1358+
assertEquals(
1359+
"pom.xml", layer.getAnnotations().get(Const.ANNOTATION_TITLE), "Title annotation should be pom.xml");
1360+
1361+
// Check annotation (layer 1)
1362+
Layer layer2 = manifest.getLayers().get(1);
1363+
assertEquals(1, layer2.getAnnotations().size());
1364+
assertNull(layer2.getAnnotations().get(Const.ANNOTATION_TITLE), "Title should not be added");
1365+
assertEquals("bar", layer2.getAnnotations().get("foo"), "Custom annotation should be preserved");
13471366
}
13481367

13491368
@Test

0 commit comments

Comments
 (0)