Skip to content

v0.59.0

Latest

Choose a tag to compare

@kmoneil kmoneil released this 24 Oct 19:19
Immutable release. Only release title and notes can be modified.

Everything a console's bucket and object pages show, and renames without a copy (#311): a bucket's Autoclass, CORS rules, website, access logging, IP filter and replication; an object's custom time and download link; and Object.moveTo, which renames an object within its bucket in one atomic step. No breaking change: every field is new and has a default. The default user agents changed.

var info = try gcs.bucket("my-site").get();
defer info.deinit();
if (info.value.autoclass) |a| if (a.enabled) {
    std.debug.print("Autoclass, down to {s}\n", .{a.terminal_storage_class.?});
};
for (info.value.cors) |rule| std.debug.print("CORS for {d} origins\n", .{rule.origins.len});

var read = try gcs.bucket("my-site").object("reports/draft.pdf").get(.{});
defer read.deinit();
var moved = try gcs.bucket("my-site").object("reports/draft.pdf").moveTo("reports/final.pdf", .{
    .if_source_generation_match = read.value.generation, // move only the object read
    .preconditions = .does_not_exist, // replace nothing
});
defer moved.deinit();
Name What it carries
BucketInfo autoclass (Autoclass), cors (CorsRules, in the bucket's order), website (Website), logging (AccessLogging), ip_filter (IpFilter: whether it is enforced, its public ranges and VPC sources, its two allowances), rpo (Rpo) and data_locations (a configurable dual-region's two regions). Read, not set
ObjectInfo custom_time, media_link and time_storage_class_updated
UploadOptions, MetadataUpdate custom_time, what lifecycle rules count from, checked as RFC 3339 before sending
Object.moveTo, MoveOptions A move within one bucket: the source's four conditions and the destination's preconditions

What production showed

Measured on 2026-10-24 in a test project, with every bucket made for the measurement deleted after:

  • A move leaves nothing behind, not even a noncurrent version in a versioned bucket. The moved object is a new generation at metageneration 1 and keeps its metadata, custom time and access control list. A hierarchical bucket makes the folders the new name needs.
  • A NotMatch that hits is a 304, error.NotModified here. A Match beside a NotMatch on one field, and a move onto its own name, are refused, so this library refuses them before sending.
  • A move pinned with if_source_generation_match is safe to repeat. A repeat that meets 404 or 412 after a lost answer reads the source: gone, the destination is answered; still there, the failure stands; another generation, the failure says the move may have happened.
  • listBuckets gives an IP filter without its ranges, and a caller without storage.buckets.getIpFilter reads the bucket with no filter at all, so ip_filter null means "none, or not yours to see".
  • A regional bucket has no rpo; logging without a prefix gets the bucket's own name; a custom time can move later, never earlier, and is never removed.
  • An empty website page is refused, and a CORS rule with nothing in it is dropped. The library's own fake had these two wrong until the production run found them.

Testing

The internal fake behind the storage tests takes these settings at a bucket's create as production answered them, refusals in production's words, and lists a project's buckets. Its tests replay the measured creates and compare the answers with production's recorded ones, CORS and the website as raw JSON too. Two gated production tests hold the real service to the same answers: GCP_TEST_BUCKET_SETTINGS=1 for the settings, and the move suite, which includes a pinned move whose answer is lost. Against an emulator, which has no move, moveTo reads both ends, judges the conditions itself, then copies and deletes, with a warning that this is not atomic.

The guides: Settings read and not set and Moves. New examples: gcs_bucket prints a bucket's settings page, and gcs_mv is a small mv.

The changelog has each module's entry.

zig fetch --save git+https://github.com/kmoneil/zig-gcp#v0.59.0