diff --git a/.github/workflows/README.md b/.github/workflows/README.md
index 8a8791e711..3db3dab1b2 100644
--- a/.github/workflows/README.md
+++ b/.github/workflows/README.md
@@ -38,8 +38,8 @@ is a `workflow_call` reusable invoked from the umbrella.
(PR+push) (PR+push) (PR+push)
| | |
v v v
- spark_3_4 / spark_4_1 iceberg_1_8 / 1_9
- (push or PR + label) (push only)
+ spark_3_4 / spark_4_1 / spark_4_2 iceberg_1_8 / 1_9
+ (push or PR + label) (push only)
reusable workflows invoked via `uses:`:
pr_build_linux.yml spark_sql_test_reusable.yml
@@ -62,6 +62,7 @@ is a `workflow_call` reusable invoked from the umbrella.
| `spark_4_0` | PR or push, paths matched | Spark 4.0 sources |
| `spark_3_4` | push, **or** PR with `run-spark-3.4-tests` label | Spark 3.4 sources |
| `spark_4_1` | push, **or** PR with `run-spark-4.1-tests` label | Spark 4.1 sources |
+| `spark_4_2` | push, **or** PR with `run-spark-4.2-tests` label | Spark 4.2 sources |
| `iceberg_1_10` | PR or push, paths matched | Iceberg sources |
| `iceberg_1_8` | push only | Iceberg sources |
| `iceberg_1_9` | push only | Iceberg sources |
@@ -86,14 +87,14 @@ umbrella doesn't watch, or operate independently of the rest of CI:
## Reusable workflows (called by `ci.yml`)
-| File | Called from `ci.yml` job(s) |
-| --------------------------------- | -------------------------------------------------- |
-| `pr_build_linux.yml` | `pr_build_linux` |
-| `pr_build_macos.yml` | `pr_build_macos` |
-| `pr_benchmark_check.yml` | `pr_benchmark_check` |
-| `docs.yaml` | `docs` |
-| `spark_sql_test_reusable.yml` | `spark_3_4`, `spark_3_5`, `spark_4_0`, `spark_4_1` |
-| `iceberg_spark_test_reusable.yml` | `iceberg_1_8`, `iceberg_1_9`, `iceberg_1_10` |
+| File | Called from `ci.yml` job(s) |
+| --------------------------------- | --------------------------------------------------------------- |
+| `pr_build_linux.yml` | `pr_build_linux` |
+| `pr_build_macos.yml` | `pr_build_macos` |
+| `pr_benchmark_check.yml` | `pr_benchmark_check` |
+| `docs.yaml` | `docs` |
+| `spark_sql_test_reusable.yml` | `spark_3_4`, `spark_3_5`, `spark_4_0`, `spark_4_1`, `spark_4_2` |
+| `iceberg_spark_test_reusable.yml` | `iceberg_1_8`, `iceberg_1_9`, `iceberg_1_10` |
## Modifying path filters
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index be277efa29..6069fb2d43 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -58,6 +58,7 @@ jobs:
github.event.label.name == 'run-spark-3.4-tests' ||
github.event.label.name == 'run-spark-4.0-tests' ||
github.event.label.name == 'run-spark-4.1-tests' ||
+ github.event.label.name == 'run-spark-4.2-tests' ||
github.event.label.name == 'run-iceberg-tests'
steps:
- uses: actions/checkout@v7
@@ -114,6 +115,7 @@ jobs:
spark_3_5: ${{ steps.compute.outputs.spark_3_5 }}
spark_4_0: ${{ steps.compute.outputs.spark_4_0 }}
spark_4_1: ${{ steps.compute.outputs.spark_4_1 }}
+ spark_4_2: ${{ steps.compute.outputs.spark_4_2 }}
iceberg_1_8: ${{ steps.compute.outputs.iceberg_1_8 }}
iceberg_1_9: ${{ steps.compute.outputs.iceberg_1_9 }}
iceberg_1_10: ${{ steps.compute.outputs.iceberg_1_10 }}
@@ -263,6 +265,23 @@ jobs:
spark-full: '4.1.2'
java: 17
+ spark_4_2:
+ name: Spark SQL Tests (Spark 4.2)
+ needs: changes
+ # Main-only by default; PRs need the `run-spark-4.2-tests` label. Spark 4.2
+ # support is still experimental, so keep it off the default PR path.
+ if: |
+ needs.changes.outputs.spark_4_2 == 'true' &&
+ (github.event_name == 'push' ||
+ github.event_name == 'workflow_dispatch' ||
+ (github.event_name == 'pull_request' &&
+ contains(github.event.pull_request.labels.*.name, 'run-spark-4.2-tests')))
+ uses: ./.github/workflows/spark_sql_test_reusable.yml
+ with:
+ spark-short: '4.2'
+ spark-full: '4.2.0'
+ java: 17
+
iceberg_1_8:
name: Iceberg Spark SQL Tests (Iceberg 1.8)
needs: changes
diff --git a/dev/ci/compute-changes.py b/dev/ci/compute-changes.py
index 47af20d450..046cedce0b 100644
--- a/dev/ci/compute-changes.py
+++ b/dev/ci/compute-changes.py
@@ -177,6 +177,28 @@
".github/actions/setup-builder/**",
".github/actions/setup-spark-builder/**",
],
+ "spark_4_2": [
+ "native/**/src/**",
+ "native/**/Cargo.toml",
+ "native/Cargo.lock",
+ "common/src/main/**",
+ "common/pom.xml",
+ "spark/src/main/**",
+ "!spark/src/main/spark-3.4/**",
+ "!spark/src/main/spark-3.5/**",
+ "!spark/src/main/spark-3.x/**",
+ "!spark/src/main/spark-4.0/**",
+ "!spark/src/main/spark-4.1/**",
+ "!spark/src/main/scala/org/apache/comet/GenerateDocs.scala",
+ "spark/pom.xml",
+ "dev/diffs/4.2.0.diff",
+ "pom.xml",
+ "rust-toolchain.toml",
+ ".github/workflows/ci.yml",
+ ".github/workflows/spark_sql_test_reusable.yml",
+ ".github/actions/setup-builder/**",
+ ".github/actions/setup-spark-builder/**",
+ ],
"iceberg_1_8": [
"native/**/src/**",
"native/**/Cargo.toml",
diff --git a/dev/diffs/4.2.0.diff b/dev/diffs/4.2.0.diff
new file mode 100644
index 0000000000..b1f51e1251
--- /dev/null
+++ b/dev/diffs/4.2.0.diff
@@ -0,0 +1,4230 @@
+diff --git a/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala b/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala
+index 6df8bc85b51..dabb75e2b75 100644
+--- a/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala
++++ b/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala
+@@ -268,6 +268,11 @@ class FallbackStorageSuite extends SparkFunSuite with LocalSparkContext {
+ }
+
+ test("Upload from all decommissioned executors") {
++ // Comet replaces Spark's shuffle with its own native shuffle, which is incompatible with
++ // the fallback storage migration path used by BlockManagerDecommissioner.
++ val cometEnv = System.getenv("ENABLE_COMET")
++ assume(cometEnv == null || cometEnv == "0" || cometEnv == "false",
++ "Skipped when Comet is enabled: incompatible with Comet native shuffle storage")
+ sc = new SparkContext(getSparkConf(2, 2))
+ withSpark(sc) { sc =>
+ TestUtils.waitUntilExecutorsUp(sc, 2, 60000)
+@@ -298,6 +303,11 @@ class FallbackStorageSuite extends SparkFunSuite with LocalSparkContext {
+ }
+
+ test("Upload multi stages") {
++ // Comet replaces Spark's shuffle with its own native shuffle, which is incompatible with
++ // the fallback storage migration path used by BlockManagerDecommissioner.
++ val cometEnv = System.getenv("ENABLE_COMET")
++ assume(cometEnv == null || cometEnv == "0" || cometEnv == "false",
++ "Skipped when Comet is enabled: incompatible with Comet native shuffle storage")
+ sc = new SparkContext(getSparkConf())
+ withSpark(sc) { sc =>
+ TestUtils.waitUntilExecutorsUp(sc, 1, 60000)
+@@ -332,6 +342,11 @@ class FallbackStorageSuite extends SparkFunSuite with LocalSparkContext {
+
+ CompressionCodec.shortCompressionCodecNames.keys.foreach { codec =>
+ test(s"$codec - Newly added executors should access old data from remote storage") {
++ // Comet replaces Spark's shuffle with its own native shuffle, which is incompatible with
++ // the fallback storage migration path used by BlockManagerDecommissioner.
++ val cometEnv = System.getenv("ENABLE_COMET")
++ assume(cometEnv == null || cometEnv == "0" || cometEnv == "false",
++ "Skipped when Comet is enabled: incompatible with Comet native shuffle storage")
+ sc = new SparkContext(getSparkConf(2, 0).set(IO_COMPRESSION_CODEC, codec))
+ withSpark(sc) { sc =>
+ TestUtils.waitUntilExecutorsUp(sc, 2, 60000)
+diff --git a/pom.xml b/pom.xml
+index 46558134f41..e58691eef40 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -154,6 +154,8 @@
+ 4.0.3
+ 2.5.3
+ 2.0.8
++ 4.2
++ 1.0.0-SNAPSHOT
+
+
+ org.apache.datasketches
+diff --git a/sql/core/pom.xml b/sql/core/pom.xml
+index 82810f181ac..21a83831188 100644
+--- a/sql/core/pom.xml
++++ b/sql/core/pom.xml
+@@ -97,6 +97,10 @@
+ org.apache.spark
+ spark-tags_${scala.binary.version}
+
++
++ org.apache.datafusion
++ comet-spark-spark${spark.version.short}_${scala.binary.version}
++
+
+