Skip to content

Conversation

@yihua
Copy link
Contributor

@yihua yihua commented Dec 31, 2019

What is the purpose of the pull request

Add CSV Source support for Hudi Delta Streamer

Brief change log

Verify this pull request

This change added tests and can be verified as follows:

Committer checklist

  • Has a corresponding JIRA in PR title & commit

  • Commit message is descriptive of the change

  • CI is green

  • Necessary doc changes done or have another open PR

  • For large changes, please consider breaking it into sub-tasks under an umbrella JIRA.

@vinothchandar
Copy link
Member

is this still WIP?

@yihua
Copy link
Contributor Author

yihua commented Jan 1, 2020

@vinothchandar I'm adding unit test cases.

@leesf leesf self-requested a review January 4, 2020 00:26
@bvaradar
Copy link
Contributor

bvaradar commented Jan 6, 2020

@yihua : Please ping me once the PR is ready for review.

Thanks,
Balaji.V

@yihua yihua force-pushed the HUDI-76-deltastreamer-csv-source branch 6 times, most recently from c73b7e9 to f37bd95 Compare January 15, 2020 01:54
@yihua yihua force-pushed the HUDI-76-deltastreamer-csv-source branch from f37bd95 to 03f37c4 Compare January 19, 2020 07:22
@yihua yihua changed the title [HUDI-76][WIP] Add CSV Source support for Hudi Delta Streamer [HUDI-76] Add CSV Source support for Hudi Delta Streamer Jan 19, 2020
@yihua
Copy link
Contributor Author

yihua commented Jan 19, 2020

@bvaradar This PR is ready for review.

@leesf @vinothchandar Feel free to also review this PR. I'm not sure if we can merge this PR by the release cut. If not, we can add this feature to the next release.

Thanks @UZi5136225 for helping test the functionality of this PR and reporting the issue of corrupt data generated from DeltaStreamer with text files (CSV format with no header line). The latter has been fix in another PR.

@yihua
Copy link
Contributor Author

yihua commented Jan 19, 2020

TestCsvDFSSource will be added once #1239 is merged.

@yihua yihua force-pushed the HUDI-76-deltastreamer-csv-source branch from e68ad87 to f9bf397 Compare January 19, 2020 19:20
@vinothchandar
Copy link
Member

@yihua are you targeting this for the next release still

@yihua
Copy link
Contributor Author

yihua commented Jan 20, 2020

@vinothchandar From my side, the code change is ready. I'm not sure if it can be reviewed and merged in time. I'm fine with pushing this to v0.6.0.

@yihua
Copy link
Contributor Author

yihua commented Jan 20, 2020

@bvaradar @leesf Could any of you review this PR by EOD?

@yihua
Copy link
Contributor Author

yihua commented Jan 26, 2020

@bvaradar I added more javadoc and checked that Spark CSV supports timestamp-type fields.

@vinothchandar vinothchandar self-assigned this Feb 5, 2020
@vinothchandar
Copy link
Member

cc @pratyakshsharma could you help review this?

@pratyakshsharma
Copy link
Contributor

@vinothchandar ack.

@vinothchandar
Copy link
Member

cc @nsivabalan could you take over in case @pratyakshsharma is busy..

@pratyakshsharma
Copy link
Contributor

@vinothchandar will review it by EOD today. :)

@nsivabalan
Copy link
Contributor

Sure. go ahead. I also plan to review it sometime. but will let you be the primary reviewer.

@vinothchandar
Copy link
Member

@nsivabalan Please shepherd this across the finish line :)

@nsivabalan
Copy link
Contributor

Sure. Will take care.

@yihua yihua force-pushed the HUDI-76-deltastreamer-csv-source branch from bb188f2 to e23adf4 Compare February 26, 2020 07:30
Copy link
Contributor Author

@yihua yihua left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pratyakshsharma Thanks for the review! Good catches on the nits. I've addressed them.

@nsivabalan The PR is ready for a final pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for CSV format, the nested schema is not well supported. So to test CSV source, we need to generate the test CSV data with a flattened schema.

Copy link
Contributor

@nsivabalan nsivabalan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments. Will merge once addressed.

@nsivabalan
Copy link
Contributor

One question about using nested schema. Can you remind me what happens if someone passes in a nested schema for CsvDeltaStreamer?

@nsivabalan
Copy link
Contributor

@yihua : Can we get this across the line.

@yihua
Copy link
Contributor Author

yihua commented Mar 10, 2020

Sorry for the delay. I'll get to this PR this week.

@yihua
Copy link
Contributor Author

yihua commented Mar 11, 2020

One question about using nested schema. Can you remind me what happens if someone passes in a nested schema for CsvDeltaStreamer?

I used some code below to test the nested schema for CSV reader in Spark. It throws the following exception, which means that Spark CSV source does not support nested schema currently.

In most cases, the CSV schemas should be flattened. It depends on Spark's behavior whether nested schema is supported for CSV source (in the future nested schema may be supported for CSV). So we don't enforce the check in our Hudi code.

org.apache.spark.sql.AnalysisException: CSV data source does not support struct<amount:double,currency:string> data type.;

	at org.apache.spark.sql.execution.datasources.DataSourceUtils$$anonfun$verifySchema$1.apply(DataSourceUtils.scala:69)
	at org.apache.spark.sql.execution.datasources.DataSourceUtils$$anonfun$verifySchema$1.apply(DataSourceUtils.scala:67)
	at scala.collection.Iterator$class.foreach(Iterator.scala:891)
	at scala.collection.AbstractIterator.foreach(Iterator.scala:1334)
	at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
	at org.apache.spark.sql.types.StructType.foreach(StructType.scala:99)
	at org.apache.spark.sql.execution.datasources.DataSourceUtils$.verifySchema(DataSourceUtils.scala:67)
	at org.apache.spark.sql.execution.datasources.DataSourceUtils$.verifyReadSchema(DataSourceUtils.scala:41)
	at org.apache.spark.sql.execution.datasources.DataSource.resolveRelation(DataSource.scala:400)
	at org.apache.spark.sql.DataFrameReader.loadV1Source(DataFrameReader.scala:223)
	at org.apache.spark.sql.DataFrameReader.load(DataFrameReader.scala:211)
	at org.apache.spark.sql.DataFrameReader.load(DataFrameReader.scala:188)
	at org.apache.hudi.utilities.sources.CsvDFSSource.fromFiles(CsvDFSSource.java:120)
	at org.apache.hudi.utilities.sources.CsvDFSSource.fetchNextBatch(CsvDFSSource.java:93)
	at org.apache.hudi.utilities.sources.RowSource.fetchNewData(RowSource.java:43)
	at org.apache.hudi.utilities.sources.Source.fetchNext(Source.java:73)
	at org.apache.hudi.utilities.deltastreamer.SourceFormatAdapter.fetchNewDataInAvroFormat(SourceFormatAdapter.java:66)
	at org.apache.hudi.utilities.deltastreamer.DeltaSync.readFromSource(DeltaSync.java:317)
	at org.apache.hudi.utilities.deltastreamer.DeltaSync.syncOnce(DeltaSync.java:226)
	at org.apache.hudi.utilities.deltastreamer.HoodieDeltaStreamer.sync(HoodieDeltaStreamer.java:121)
	at org.apache.hudi.utilities.TestHoodieDeltaStreamer.testCsvDFSSourceWithNestedSchema(TestHoodieDeltaStreamer.java:812)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

Appendix: a simple diff for testing nested CSV schema:

diff --git a/hudi-utilities/null/parquetFiles/.1.parquet.crc b/hudi-utilities/null/parquetFiles/.1.parquet.crc
new file mode 100644
index 00000000..f48941c4
Binary files /dev/null and b/hudi-utilities/null/parquetFiles/.1.parquet.crc differ
diff --git a/hudi-utilities/null/parquetFiles/1.parquet b/hudi-utilities/null/parquetFiles/1.parquet
new file mode 100644
index 00000000..7780cb89
Binary files /dev/null and b/hudi-utilities/null/parquetFiles/1.parquet differ
diff --git a/hudi-utilities/src/main/java/org/apache/hudi/utilities/deltastreamer/DeltaSync.java b/hudi-utilities/src/main/java/org/apache/hudi/utilities/deltastreamer/DeltaSync.java
index 4b69d223..e2921a5f 100644
--- a/hudi-utilities/src/main/java/org/apache/hudi/utilities/deltastreamer/DeltaSync.java
+++ b/hudi-utilities/src/main/java/org/apache/hudi/utilities/deltastreamer/DeltaSync.java
@@ -21,7 +21,6 @@ package org.apache.hudi.utilities.deltastreamer;
 import org.apache.hudi.AvroConversionUtils;
 import org.apache.hudi.DataSourceUtils;
 import org.apache.hudi.client.HoodieWriteClient;
-import org.apache.hudi.keygen.KeyGenerator;
 import org.apache.hudi.client.WriteStatus;
 import org.apache.hudi.common.model.HoodieCommitMetadata;
 import org.apache.hudi.common.model.HoodieRecord;
@@ -40,6 +39,7 @@ import org.apache.hudi.exception.HoodieException;
 import org.apache.hudi.hive.HiveSyncConfig;
 import org.apache.hudi.hive.HiveSyncTool;
 import org.apache.hudi.index.HoodieIndex;
+import org.apache.hudi.keygen.KeyGenerator;
 import org.apache.hudi.utilities.UtilHelpers;
 import org.apache.hudi.utilities.deltastreamer.HoodieDeltaStreamer.Operation;
 import org.apache.hudi.utilities.exception.HoodieDeltaStreamerException;
@@ -332,6 +332,7 @@ public class DeltaSync implements Serializable {
     }
 
     JavaRDD<GenericRecord> avroRDD = avroRDDOptional.get();
+    List<GenericRecord> r = avroRDD.collect();
     JavaRDD<HoodieRecord> records = avroRDD.map(gr -> {
       HoodieRecordPayload payload = DataSourceUtils.createPayload(cfg.payloadClassName, gr,
           (Comparable) DataSourceUtils.getNestedFieldVal(gr, cfg.sourceOrderingField, false));
diff --git a/hudi-utilities/src/main/java/org/apache/hudi/utilities/sources/RowSource.java b/hudi-utilities/src/main/java/org/apache/hudi/utilities/sources/RowSource.java
index 9e289f10..6f0cc8f8 100644
--- a/hudi-utilities/src/main/java/org/apache/hudi/utilities/sources/RowSource.java
+++ b/hudi-utilities/src/main/java/org/apache/hudi/utilities/sources/RowSource.java
@@ -41,6 +41,7 @@ public abstract class RowSource extends Source<Dataset<Row>> {
   @Override
   protected final InputBatch<Dataset<Row>> fetchNewData(Option<String> lastCkptStr, long sourceLimit) {
     Pair<Option<Dataset<Row>>, String> res = fetchNextBatch(lastCkptStr, sourceLimit);
+    Row[] x = (Row[]) res.getKey().get().collect();
     return res.getKey().map(dsr -> {
       SchemaProvider rowSchemaProvider = new RowBasedSchemaProvider(dsr.schema());
       return new InputBatch<>(res.getKey(), res.getValue(), rowSchemaProvider);
diff --git a/hudi-utilities/src/test/java/org/apache/hudi/utilities/TestHoodieDeltaStreamer.java b/hudi-utilities/src/test/java/org/apache/hudi/utilities/TestHoodieDeltaStreamer.java
index 43f76904..46761703 100644
--- a/hudi-utilities/src/test/java/org/apache/hudi/utilities/TestHoodieDeltaStreamer.java
+++ b/hudi-utilities/src/test/java/org/apache/hudi/utilities/TestHoodieDeltaStreamer.java
@@ -19,7 +19,6 @@
 package org.apache.hudi.utilities;
 
 import org.apache.hudi.DataSourceWriteOptions;
-import org.apache.hudi.keygen.SimpleKeyGenerator;
 import org.apache.hudi.common.HoodieTestDataGenerator;
 import org.apache.hudi.common.model.HoodieCommitMetadata;
 import org.apache.hudi.common.model.HoodieTableType;
@@ -33,11 +32,12 @@ import org.apache.hudi.common.util.FSUtils;
 import org.apache.hudi.common.util.Option;
 import org.apache.hudi.common.util.TypedProperties;
 import org.apache.hudi.config.HoodieCompactionConfig;
-import org.apache.hudi.exception.TableNotFoundException;
 import org.apache.hudi.exception.HoodieException;
+import org.apache.hudi.exception.TableNotFoundException;
 import org.apache.hudi.hive.HiveSyncConfig;
 import org.apache.hudi.hive.HoodieHiveClient;
 import org.apache.hudi.hive.MultiPartKeysValueExtractor;
+import org.apache.hudi.keygen.SimpleKeyGenerator;
 import org.apache.hudi.utilities.deltastreamer.HoodieDeltaStreamer;
 import org.apache.hudi.utilities.deltastreamer.HoodieDeltaStreamer.Operation;
 import org.apache.hudi.utilities.schema.FilebasedSchemaProvider;
@@ -101,6 +101,7 @@ public class TestHoodieDeltaStreamer extends UtilitiesTestBase {
   private static final String PROPS_FILENAME_TEST_SOURCE = "test-source.properties";
   private static final String PROPS_FILENAME_TEST_INVALID = "test-invalid.properties";
   private static final String PROPS_FILENAME_TEST_CSV = "test-csv-dfs-source.properties";
+  private static final String PROPS_FILENAME_TEST_CSV_NESTED = "test-csv-dfs-source-nested.properties";
   private static final String PROPS_FILENAME_TEST_PARQUET = "test-parquet-dfs-source.properties";
   private static final String PARQUET_SOURCE_ROOT = dfsBasePath + "/parquetFiles";
   private static final int PARQUET_NUM_RECORDS = 5;
@@ -728,7 +729,51 @@ public class TestHoodieDeltaStreamer extends UtilitiesTestBase {
       csvProps.setProperty("hoodie.deltastreamer.csv.header", Boolean.toString(hasHeader));
     }
 
-    UtilitiesTestBase.Helpers.savePropsToDFS(csvProps, dfs, dfsBasePath + "/" + PROPS_FILENAME_TEST_CSV);
+    UtilitiesTestBase.Helpers
+        .savePropsToDFS(csvProps, dfs, dfsBasePath + "/" + PROPS_FILENAME_TEST_CSV);
+
+    String path = sourceRoot + "/1.csv";
+    HoodieTestDataGenerator dataGenerator = new HoodieTestDataGenerator();
+    UtilitiesTestBase.Helpers.saveCsvToDFS(
+        hasHeader, sep,
+        Helpers.jsonifyRecords(dataGenerator.generateInserts("000", CSV_NUM_RECORDS, true)),
+        dfs, path);
+  }
+
+  private void prepareCsvDFSSourceNested(
+      boolean hasHeader, char sep, boolean useSchemaProvider, boolean hasTransformer)
+      throws IOException {
+    String sourceRoot = dfsBasePath + "/csvFiles";
+    String recordKeyField = (hasHeader || useSchemaProvider) ? "_row_key" : "_c0";
+
+    // Properties used for testing delta-streamer with CSV source
+    TypedProperties csvProps = new TypedProperties();
+    csvProps.setProperty("include", "base.properties");
+    csvProps.setProperty("hoodie.datasource.write.recordkey.field", recordKeyField);
+    csvProps.setProperty("hoodie.datasource.write.partitionpath.field", "not_there");
+    if (useSchemaProvider) {
+      csvProps.setProperty("hoodie.deltastreamer.schemaprovider.source.schema.file",
+          dfsBasePath + "/source.avsc");
+      if (hasTransformer) {
+        csvProps.setProperty("hoodie.deltastreamer.schemaprovider.target.schema.file",
+            dfsBasePath + "/target.avsc");
+      }
+    }
+    csvProps.setProperty("hoodie.deltastreamer.source.dfs.root", sourceRoot);
+
+    if (sep != ',') {
+      if (sep == '\t') {
+        csvProps.setProperty("hoodie.deltastreamer.csv.sep", "\\t");
+      } else {
+        csvProps.setProperty("hoodie.deltastreamer.csv.sep", Character.toString(sep));
+      }
+    }
+    if (hasHeader) {
+      csvProps.setProperty("hoodie.deltastreamer.csv.header", Boolean.toString(hasHeader));
+    }
+
+    UtilitiesTestBase.Helpers
+        .savePropsToDFS(csvProps, dfs, dfsBasePath + "/" + PROPS_FILENAME_TEST_CSV_NESTED);
 
     String path = sourceRoot + "/1.csv";
     HoodieTestDataGenerator dataGenerator = new HoodieTestDataGenerator();
@@ -739,7 +784,8 @@ public class TestHoodieDeltaStreamer extends UtilitiesTestBase {
   }
 
   private void testCsvDFSSource(
-      boolean hasHeader, char sep, boolean useSchemaProvider, String transformerClassName) throws Exception {
+      boolean hasHeader, char sep, boolean useSchemaProvider, String transformerClassName)
+      throws Exception {
     prepareCsvDFSSource(hasHeader, sep, useSchemaProvider, transformerClassName != null);
     String tableBasePath = dfsBasePath + "/test_csv_table" + testNum;
     String sourceOrderingField = (hasHeader || useSchemaProvider) ? "timestamp" : "_c0";
@@ -753,6 +799,25 @@ public class TestHoodieDeltaStreamer extends UtilitiesTestBase {
     testNum++;
   }
 
+  @Test
+  public void testCsvDFSSourceWithNestedSchema() throws Exception {
+    prepareCsvDFSSourceNested(true, ',', true, false);
+    String tableBasePath = dfsBasePath + "/test_csv_table" + testNum;
+    String sourceOrderingField = "timestamp";
+    HoodieDeltaStreamer deltaStreamer =
+        new HoodieDeltaStreamer(TestHelpers.makeConfig(
+            tableBasePath, Operation.INSERT, CsvDFSSource.class.getName(),
+            null, PROPS_FILENAME_TEST_CSV_NESTED, false,
+            true, 1000, false, null, null, sourceOrderingField), jsc);
+    deltaStreamer.sync();
+
+    Row[] x = (Row[]) sqlContext.read().format("org.apache.hudi")
+        .load(tableBasePath + "/*/*.parquet")
+        .collect();
+    TestHelpers.assertRecordCount(CSV_NUM_RECORDS, tableBasePath + "/*/*.parquet", sqlContext);
+    testNum++;
+  }
+
   @Test
   public void testCsvDFSSourceWithHeaderWithoutSchemaProviderAndNoTransformer() throws Exception {
     // The CSV files have header, the columns are separated by ',', the default separator

@yihua yihua force-pushed the HUDI-76-deltastreamer-csv-source branch from e23adf4 to fb6bc0b Compare March 11, 2020 06:14
Copy link
Contributor Author

@yihua yihua left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nsivabalan Thanks for the review. Please take another look.

@codecov-io
Copy link

codecov-io commented Mar 11, 2020

Codecov Report

Merging #1165 into master will increase coverage by 0.04%.
The diff coverage is 100.00%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1165      +/-   ##
============================================
+ Coverage     67.69%   67.74%   +0.04%     
- Complexity      243      253      +10     
============================================
  Files           338      339       +1     
  Lines         16371    16396      +25     
  Branches       1672     1676       +4     
============================================
+ Hits          11083    11108      +25     
  Misses         4548     4548              
  Partials        740      740              
Impacted Files Coverage Δ Complexity Δ
...rg/apache/hudi/utilities/sources/CsvDFSSource.java 100.00% <100.00%> (ø) 10.00 <10.00> (?)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 23afe7a...cf765df. Read the comment docs.

@nsivabalan
Copy link
Contributor

@yihua : LGTM. Can you squash the commits. I will merge after that.

@nsivabalan
Copy link
Contributor

nsivabalan commented Mar 15, 2020

@vinothchandar : do you think we can have a blog on deltastreamer with csv?

@yihua
Copy link
Contributor Author

yihua commented Mar 16, 2020

I plan to write one after this is merged.

@yihua yihua force-pushed the HUDI-76-deltastreamer-csv-source branch from fb6bc0b to cf765df Compare March 16, 2020 02:04
@yihua
Copy link
Contributor Author

yihua commented Mar 16, 2020

@nsivabalan Done squashing the commits.

@vinothchandar
Copy link
Member

yes.. lets please do a blog!

@nsivabalan
Copy link
Contributor

I don't see an option to merge the PR. Is it that @leesf is yet to approve? or do I need to request permission or something ?

@leesf
Copy link
Contributor

leesf commented Mar 17, 2020

I don't see an option to merge the PR. Is it that @leesf is yet to approve? or do I need to request permission or something ?

@nsivabalan Please refer to this wiki to get github write access to the repository. https://cwiki.apache.org/confluence/display/HUDI/Committer+On-boarding+Guide

@nsivabalan
Copy link
Contributor

nsivabalan commented Mar 19, 2020

@leesf : Thanks. I got the permission now.

@nsivabalan nsivabalan merged commit a752b7b into apache:master Mar 19, 2020
@leesf
Copy link
Contributor

leesf commented Mar 19, 2020

@leesf : Thanks. I got the permission now.

You are welcome and a nice shot. just one minor tip, please merge(squash & merge / rebase & merge) with [HUDI-xxx] at the begining of commit. :)

@nsivabalan
Copy link
Contributor

got it, sure.

@vinothchandar
Copy link
Member

@leesf this has happened enough times now, that we probably need a Code Review guide as well? wdyt

@leesf
Copy link
Contributor

leesf commented Mar 20, 2020

@leesf this has happened enough times now, that we probably need a Code Review guide as well? wdyt

Agree, I would like to update https://cwiki.apache.org/confluence/display/HUDI/Committer+On-boarding+Guide to add Code Review guide for new committers, wdyt?

@vinothchandar
Copy link
Member

I feel it can go on the contributing guide.. Code reviews are also contributing :) .. either way is fine by me.. Draft something and share on the mailing list?

@leesf
Copy link
Contributor

leesf commented Mar 20, 2020

I feel it can go on the contributing guide.. Code reviews are also contributing :) .. either way is fine by me.. Draft something and share on the mailing list?

Sure, will draft when get a chance.

vamsikarnika pushed a commit to vamsikarnika/hudi that referenced this pull request Jan 30, 2025
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants