This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-3363-0a345f202d9233481884f0d7a3ae3a4b6181044b
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git

commit 0669f080668f31d2a9c602b5b774ec40743b5ed4
Author: Russell Spitzer <[email protected]>
AuthorDate: Tue Oct 20 03:23:29 2026 +0000

    feat(transaction): record the Iceberg-Rust writer version information in 
snapshot summaries (#3363)
    
    * feat(transaction): record the Rust writer in snapshot summaries
    
    A commit from iceberg-rust was indistinguishable from any other client that
    omits writer identity. Stamp engine-name, engine-version, and 
iceberg-version
    on every snapshot so mixed-writer tables can attribute the commit.
    
    Generated-by: Cursor Grok 4.7
    
    * Remove the writer-identity comments.
    
    Generated-by: Cursor Grok 4.7
    
    * Keep a caller-supplied engine name and version.
    
    iceberg-version still identifies this library. engine-name and
    engine-version are filled only when the caller did not set them, so an
    embedding engine can record itself through snapshot properties.
    
    Generated-by: Cursor Grok 4.7
    
    * Keep the writer-identity tests on snapshot properties.
    
    A data file and an unrelated property do not affect those keys.
    Also list the new summary constants alphabetically.
    
    Generated-by: Cursor Grok 4.7
    
    * Write only iceberg-version into snapshot summaries.
    
    engine-name and engine-version name the embedding engine, which this
    library does not know. Callers can still set them. iceberg-version
    remains the library identity, matching Java and Go.
    
    Generated-by: Cursor Grok 4.7
    
    * Drop the caller engine-identity snapshot test.
    
    Those keys are ordinary snapshot properties now, so preserving a
    caller value is already covered by the existing property test.
    
    Generated-by: Cursor Grok 4.7
    
    * Stop asserting that engine identity keys are absent.
    
    The snapshot summary no longer writes those keys, so the test only
    checks iceberg-version.
    
    Generated-by: Cursor Grok 4.7
    
    * Update crates/iceberg/src/transaction/append.rs
    
    Co-authored-by: Matt Butrovich <[email protected]>
    
    * Move the iceberg-version summary key next to the other keys.
    
    The transaction path still writes the value. The property name now
    lives with the rest of the summary keys the library defines.
    
    Generated-by: Cursor Grok 4.7
    
    * Set iceberg-version from the snapshot summary module.
    
    The key stays private next to the other summary keys, and the commit
    path calls set_iceberg_version after the totals are computed.
    
    Generated-by: Cursor Grok 4.7
    
    * Restore the blank line before the SnapshotProduceOperation docs.
    
    Co-authored-by: Copilot App <[email protected]>
    
    ---------
    
    Co-authored-by: Matt Butrovich <[email protected]>
    Co-authored-by: Kevin Liu <[email protected]>
    Co-authored-by: Copilot App <[email protected]>
---
 crates/iceberg/src/spec/snapshot_summary.rs |  9 +++++++++
 crates/iceberg/src/transaction/append.rs    | 31 +++++++++++++++++++++++++++++
 crates/iceberg/src/transaction/snapshot.rs  |  8 +++++---
 3 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/crates/iceberg/src/spec/snapshot_summary.rs 
b/crates/iceberg/src/spec/snapshot_summary.rs
index d68a49d14..fdaf27704 100644
--- a/crates/iceberg/src/spec/snapshot_summary.rs
+++ b/crates/iceberg/src/spec/snapshot_summary.rs
@@ -48,6 +48,7 @@ const TOTAL_RECORDS: &str = "total-records";
 const TOTAL_FILE_SIZE: &str = "total-files-size";
 const CHANGED_PARTITION_COUNT_PROP: &str = "changed-partition-count";
 const CHANGED_PARTITION_PREFIX: &str = "partitions.";
+const ICEBERG_VERSION_PROP: &str = "iceberg-version";
 
 /// `SnapshotSummaryCollector` collects and aggregates snapshot update metrics.
 /// It gathers metrics about added or removed data files and manifests, and 
tracks
@@ -330,6 +331,14 @@ where T: PartialOrd + Default + ToString {
     }
 }
 
+pub(crate) fn set_iceberg_version(properties: &mut HashMap<String, String>) {
+    let version = env!("CARGO_PKG_VERSION");
+    properties.insert(
+        ICEBERG_VERSION_PROP.to_string(),
+        format!("Apache Iceberg Rust {version}"),
+    );
+}
+
 pub(crate) fn update_snapshot_summaries(
     summary: Summary,
     previous_summary: Option<&Summary>,
diff --git a/crates/iceberg/src/transaction/append.rs 
b/crates/iceberg/src/transaction/append.rs
index e3e74338c..9c438759b 100644
--- a/crates/iceberg/src/transaction/append.rs
+++ b/crates/iceberg/src/transaction/append.rs
@@ -777,6 +777,37 @@ mod tests {
         );
     }
 
+    #[tokio::test]
+    async fn test_snapshot_summary_records_writer_identity() {
+        let table = make_v2_minimal_table();
+        let tx = Transaction::new(&table);
+
+        let snapshot_properties = HashMap::from([
+            ("key".to_string(), "val".to_string()),
+            ("iceberg-version".to_string(), "caller".to_string()),
+        ]);
+
+        let action = tx
+            .fast_append()
+            .set_snapshot_properties(snapshot_properties);
+        let mut action_commit = commit_with_fresh_state(action, 
&table).await.unwrap();
+        let updates = action_commit.take_updates();
+
+        let new_snapshot = if let TableUpdate::AddSnapshot { snapshot } = 
&updates[0] {
+            snapshot
+        } else {
+            unreachable!()
+        };
+        let props = &new_snapshot.summary().additional_properties;
+        let version = env!("CARGO_PKG_VERSION");
+
+        assert_eq!(
+            props.get("iceberg-version").unwrap(),
+            &format!("Apache Iceberg Rust {version}")
+        );
+        assert_eq!(props.get("key").unwrap(), "val");
+    }
+
     #[tokio::test]
     async fn test_append_snapshot_properties() {
         let table = make_v2_minimal_table();
diff --git a/crates/iceberg/src/transaction/snapshot.rs 
b/crates/iceberg/src/transaction/snapshot.rs
index c30175001..7e4d6fb72 100644
--- a/crates/iceberg/src/transaction/snapshot.rs
+++ b/crates/iceberg/src/transaction/snapshot.rs
@@ -28,7 +28,7 @@ use crate::spec::{
     DataFile, DataFileFormat, FormatVersion, MAIN_BRANCH, ManifestContentType, 
ManifestEntry,
     ManifestFile, ManifestListWriter, ManifestWriter, ManifestWriterBuilder, 
Operation,
     PartitionSpecRef, SchemaRef, Snapshot, SnapshotReference, 
SnapshotRetention,
-    SnapshotSummaryCollector, Struct, StructType, Summary, TableProperties,
+    SnapshotSummaryCollector, Struct, StructType, Summary, TableProperties, 
set_iceberg_version,
     update_snapshot_summaries,
 };
 use crate::table::Table;
@@ -453,11 +453,13 @@ impl<'a> SnapshotProducer<'a> {
             additional_properties,
         };
 
-        update_snapshot_summaries(
+        let mut summary = update_snapshot_summaries(
             summary,
             previous_snapshot.map(|s| s.summary()),
             snapshot_produce_operation.truncate_full_table(),
-        )
+        )?;
+        set_iceberg_version(&mut summary.additional_properties);
+        Ok(summary)
     }
 
     fn generate_manifest_list_file_path(&self, attempt: i64) -> Result<String> 
{

Reply via email to