Repository: googleapis/java-storage (java)

Issue:
add support for OLM Prefix/Suffix
We need to add support for the new LifecycleCondition field options `matchesPrefix` and `matchesSuffix`. Both of these will be a list of strings.

request (internal): [go/prefix-suffix-client-library-request](http://go/prefix-suffix-client-library-request)
nodejs-storage example: https://github.com/googleapis/nodejs-storage/pull/1847

Please wait for my approval before merging/releasing this so we can coordinate around release dates.

Pull request description:
feat: Prefix/Suffix Matches Lifecycle Condition
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
- [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/java-storage/issues/new/choose) before writing your code!  That way we can discuss the change, evaluate designs, and agree on the general idea
- [ ] Ensure the tests and linter pass
- [ ] Code coverage does not decrease (if any source code was changed)
- [ ] Appropriate docs were updated (if necessary)

Fixes #1345 ☕️

If you write sample code, please follow the [samples format](
https://github.com/GoogleCloudPlatform/java-docs-samples/blob/main/SAMPLE_FORMAT.md).


Patch:
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
index 16d80247..02990680 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
@@ -446,7 +446,9 @@ public class BucketInfo implements Serializable {
           && condition.getDaysSinceNoncurrentTime() == null
           && condition.getNoncurrentTimeBefore() == null
           && condition.getCustomTimeBefore() == null
-          && condition.getDaysSinceCustomTime() == null) {
+          && condition.getDaysSinceCustomTime() == null
+          && condition.getMatchesPrefix() == null
+          && condition.getMatchesSuffix() == null) {
         log.warning(
             "Creating a lifecycle condition with no supported conditions:\n"
                 + this
@@ -527,7 +529,9 @@ public class BucketInfo implements Serializable {
                   lifecycleCondition.getCustomTimeBefore() == null
                       ? null
                       : new DateTime(true, lifecycleCondition.getCustomTimeBefore().getValue(), 0))
-              .setDaysSinceCustomTime(lifecycleCondition.getDaysSinceCustomTime());
+              .setDaysSinceCustomTime(lifecycleCondition.getDaysSinceCustomTime())
+              .setMatchesPrefix(lifecycleCondition.getMatchesPrefix())
+              .setMatchesSuffix(lifecycleCondition.getMatchesSuffix());
 
       rule.setCondition(condition);
 
@@ -604,6 +608,8 @@ public class BucketInfo implements Serializable {
       private final DateTime noncurrentTimeBefore;
       private final DateTime customTimeBefore;
       private final Integer daysSinceCustomTime;
+      private final List<String> matchesPrefix;
+      private final List<String> matchesSuffix;
 
       private LifecycleCondition(Builder builder) {
         this.age = builder.age;
@@ -615,6 +621,8 @@ public class BucketInfo implements Serializable {
         this.noncurrentTimeBefore = builder.noncurrentTimeBefore;
         this.customTimeBefore = builder.customTimeBefore;
         this.daysSinceCustomTime = builder.daysSinceCustomTime;
+        this.matchesPrefix = builder.matchesPrefix;
+        this.matchesSuffix = builder.matchesSuffix;
       }
 
       public Builder toBuilder() {
@@ -627,7 +635,9 @@ public class BucketInfo implements Serializable {
             .setDaysSinceNoncurrentTime(this.daysSinceNoncurrentTime)
             .setNoncurrentTimeBefore(this.noncurrentTimeBefore)
             .setCustomTimeBefore(this.customTimeBefore)
-            .setDaysSinceCustomTime(this.daysSinceCustomTime);
+            .setDaysSinceCustomTime(this.daysSinceCustomTime)
+            .setMatchesPrefix(this.matchesPrefix)
+            .setMatchesSuffix(this.matchesSuffix);
       }
 
       public static Builder newBuilder() {
@@ -646,6 +656,8 @@ public class BucketInfo implements Serializable {
             .add("noncurrentTimeBefore", noncurrentTimeBefore)
             .add("customTimeBefore", customTimeBefore)
             .add("daysSinceCustomTime", daysSinceCustomTime)
+            .add("matchesPrefix", matchesPrefix)
+            .add("matchesSuffix", matchesSuffix)
             .toString();
       }
 
@@ -691,6 +703,14 @@ public class BucketInfo implements Serializable {
         return daysSinceCustomTime;
       }
 
+      public List<String> getMatchesPrefix() {
+        return matchesPrefix;
+      }
+
+      public List<String> getMatchesSuffix() {
+        return matchesSuffix;
+      }
+
       /** Builder for {@code LifecycleCondition}. */
       public static class Builder {
         private Integer age;
@@ -702,6 +722,8 @@ public class BucketInfo implements Serializable {
         private DateTime noncurrentTimeBefore;
         private DateTime customTimeBefore;
         private Integer daysSinceCustomTime;
+        private List<String> matchesPrefix;
+        private List<String> matchesSuffix;
 
         private Builder() {}
 
@@ -800,6 +822,24 @@ public class BucketInfo implements Serializable {
           return this;
         }
 
+        /**
+         * Sets the list of prefixes. If any prefix matches the beginning of the object’s name, this
+         * portion of the condition is satisfied for that object.
+         */
+        public Builder setMatchesPrefix(List<String> matchesPrefix) {
+          this.matchesPrefix = matchesPrefix != null ? ImmutableList.copyOf(matchesPrefix) : null;
+          return this;
+        }
+
+        /**
+         * Sets the list of suffixes. If any suffix matches the end of the object’s name, this
+         * portion of the condition is satisfied for that object.
+         */
+        public Builder setMatchesSuffix(List<String> matchesSuffix) {
+          this.matchesSuffix = matchesSuffix != null ? ImmutableList.copyOf(matchesSuffix) : null;
+          return this;
+        }
+
         /** Builds a {@code LifecycleCondition} object. * */
         public LifecycleCondition build() {
           return new LifecycleCondition(this);


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
index 96eeb38e..e05d9747 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
@@ -365,6 +365,8 @@ public class BucketInfoTest {
                     .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
                     .setCustomTimeBefore(new DateTime(System.currentTimeMillis()))
                     .setDaysSinceCustomTime(30)
+                    .setMatchesSuffix(Collections.singletonList("-suffix"))
+                    .setMatchesPrefix(Collections.singletonList("prefix-"))
                     .build())
             .toPb();
     assertEquals(StorageClass.COLDLINE.toString(), lifecycleRule.getAction().getStorageClass());
@@ -375,6 +377,8 @@ public class BucketInfoTest {
     assertEquals(StorageClass.COLDLINE.toString(), lifecycleRule.getAction().getStorageClass());
     assertEquals(30, lifecycleRule.getCondition().getDaysSinceCustomTime().intValue());
     assertNotNull(lifecycleRule.getCondition().getCustomTimeBefore());
+    assertEquals("prefix-", lifecycleRule.getCondition().getMatchesPrefix().get(0));
+    assertEquals("-suffix", lifecycleRule.getCondition().getMatchesSuffix().get(0));
     assertTrue(
         LifecycleRule.fromPb(lifecycleRule).getAction() instanceof SetStorageClassLifecycleAction);