This is an automated email from the ASF dual-hosted git repository.
vinishjail97 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-xtable.git
The following commit(s) were added to refs/heads/main by this push:
new b0b7f8b0 [855] Add the 0.4.0 release blog post and widen the blog
layout (#915)
b0b7f8b0 is described below
commit b0b7f8b00eedb1765c2ce4857bbb10b042de5f74
Author: Vinish Reddy <[email protected]>
AuthorDate: Wed Aug 26 23:27:44 2026 +0530
[855] Add the 0.4.0 release blog post and widen the blog layout (#915)
* [855] Add the 0.4.0 release blog post and widen the blog layout
Add website/blog/apache-xtable-0.4.0-release.mdx, announcing
0.4.0-incubating.
It covers the three headline items, the Spark runtime jar, the Paimon and
Parquet sources, and Delta Kernel, and links to the release notes page for
the
full change list rather than repeating it.
Also widen the blog layout, which two separate caps were constraining:
- BlogLayout wraps the page in Infima's .container, which caps at
--ifm-container-width. That defaults to 1140px and nothing overrode it, so
the page stopped growing on any monitor wider than that. Raise both
--ifm-container-width and --ifm-container-width-xl to 1600px.
- BlogPostItem/Container set width:50% as an inline style. Being inline, no
stylesheet could override it, it held at every breakpoint, and it applied
to
the single-post page as well as the list, since both views render the same
container. Move it to a .blogPostCard class, apply it only when
isBlogPostPage is false, and drop to one card per row under 996px.
* [855] Tighten the 0.4.0 blog copy and name Paimon and Parquet on the home
page
Blog post:
* Drop the repeated project name from the opening. The title and the author
line already carry it, so the first sentence now starts "We are pleased to
announce".
* Give each feature its own `###` heading, so Spark runtime, Apache Paimon,
Apache Parquet and Delta Kernel all appear in the table of contents. The
"New source formats" heading held two bullets and is gone.
* Name the entry points in the Spark section. "a sync" was ambiguous, so the
text now points at `XTableSyncService` for an existing job and at
`XTableSparkSync` for `spark-submit`.
* Reword the Delta Kernel section against `delta-core`. The Spark dependency
comes from `DeltaLog` and `OptimisticTransaction`, which the older Delta
source and target call directly.
* Use `xtable-write-anywhere.png` as the cover, which is already in the
repo.
Home page:
* The hero named only Hudi, Delta Lake and Iceberg. Paimon and Parquet are
read-only, so they get their own sentence with "Sync from" rather than
joining the "interoperate between" list.
Blog list:
* Cap thumbnails at 365px. Most covers are 2:1 and fill the column at about
that height, so a near-square cover no longer pushes its title far below
the
title of the card beside it.
* Resolve the thumbnail `src` relative to the site root. `withBaseUrl` with
`absolute: true` resolved it against the configured `url`, so every
thumbnail loaded from the production site and a new image could not be
previewed locally.
* [855] Use the description front matter key and scope the blog thumbnail
cap
The post set `excerpt`, which Docusaurus does not read. The page description
fell back to the first line of the body and was cut mid-sentence, so both
the
meta and og:description tags read "... which lands 45 commits from". Rename
the
key to `description`.
`.blog-image` capped every thumbnail at 365px so the list cards line up. The
same image is the hero on the single-post page, where there is no neighbour
to
line up with, and the cap held it to 416px wide. Scope the rule to
`.blogPostCard`, which is set on list cards only.
Also drop the home page hero change. The sentence goes back to naming Apache
Hudi, Delta Lake and Apache Iceberg only.
* [855] Scope the 1600px container width to the blog layout
The two --ifm-container-width variables were set on :root, so every page
that
Infima wraps in .container grew to 1600px, including the docs, the release
notes and the home page. Set them on a blogLayoutContainer class instead and
apply that class to the .container div in BlogLayout, which only the blog
list
and the single-post page render. Infima reads the variable on the element,
so
the override takes effect there and nowhere else.
---
website/blog/apache-xtable-0.4.0-release.mdx | 83 +++++++++++++++++++++++
website/src/css/custom.css | 36 +++++++++-
website/src/theme/BlogLayout/index.js | 2 +-
website/src/theme/BlogPostItem/Container/index.js | 9 ++-
4 files changed, 123 insertions(+), 7 deletions(-)
diff --git a/website/blog/apache-xtable-0.4.0-release.mdx
b/website/blog/apache-xtable-0.4.0-release.mdx
new file mode 100644
index 00000000..4c256cc5
--- /dev/null
+++ b/website/blog/apache-xtable-0.4.0-release.mdx
@@ -0,0 +1,83 @@
+---
+title: "Apache XTable™ (Incubating) 0.4.0 Release"
+description: "Apache XTable™ (Incubating) 0.4.0 adds a Spark runtime jar,
Apache Paimon and Apache Parquet sources, and Delta Kernel."
+author: Apache XTable Community
+category: blog
+image: /images/xtable-write-anywhere.png
+tags:
+- apache xtable
+- release
+- spark
+- paimon
+- parquet
+- delta kernel
+date: 2026-08-25
+---
+
+We are pleased to announce the release of 0.4.0-incubating, which lands 45
commits from
+19 contributors.
+See the [release notes](/releases/release-0.4.0-incubating) for the complete
list of changes.
+
+<!--truncate-->
+
+Apache XTable™ (Incubating) converts metadata between Apache Hudi, Apache
Iceberg and Delta Lake
+without rewriting any data files. With this release it also supports Apache
Paimon and Apache
+Parquet tables as sources.
+
+## Release Highlights
+
+### Spark runtime
+
+A new runtime jar, `xtable-spark-runtime`, runs a sync on a Spark cluster you
already have. Add it
+to an existing job with `--jars` and call `XTableSyncService` right after your
write, or submit
+`XTableSparkSync` on its own with `spark-submit`.
+
+```shell
+$SPARK_HOME/bin/spark-submit \
+ --jars xtable-spark-runtime_2.12-0.4.0-incubating.jar \
+ --class com.example.OrdersJob \
+ orders-job.jar
+```
+
+Every engine dependency is `provided`, so the jar reuses the Hudi, Iceberg and
Delta libraries
+already on your cluster. The jar supports Spark 3.4 and 3.5. See
+[Run an XTable sync on Apache Spark](/docs/how-to-spark-runtime) for the full
guide.
+
+### Apache Paimon
+
+A new conversion source reads Paimon tables, with incremental sync and column
statistics.
+
+### Apache Parquet
+
+A new conversion source reads Parquet tables, with schema conversion, column
statistics, partition
+extraction and incremental sync.
+
+### Delta Kernel
+
+A new conversion source and target read and write Delta tables through the
`delta-kernel-api`
+library, and neither one needs a `SparkSession`. The older Delta source and
target call `DeltaLog`
+and `OptimisticTransaction` from `delta-core`, which ties them to Spark.
+
+## Getting the release
+
+Download the source release, its signature and its checksum from the
+[Downloads](/releases/downloads) page. Always verify the signature before you
use the release.
+
+The binary artifacts are on Maven Central under the `org.apache.xtable` group.
For example, add the
+Spark runtime jar as
`org.apache.xtable:xtable-spark-runtime_2.12:0.4.0-incubating`.
+
+## Getting involved
+
+Apache XTable™ (Incubating) grows through its contributors. We track work in
+[GitHub issues](https://github.com/apache/incubator-xtable/issues) and we
discuss it on the
+[dev mailing list](mailto:[email protected]).
+
+The easiest way to start is to:
+
+1. Try 0.4.0-incubating on your own tables and tell us how it goes.
+2. Join the [community sync](/community/sync) and the dev mailing list.
+3. Pick up a [good first
issue](https://github.com/apache/incubator-xtable/contribute).
+
+For more information, visit the [documentation](/docs/setup) or the
+[GitHub repository](https://github.com/apache/incubator-xtable). If you want
to grow into a
+committer role, read [Becoming a committer](/community/becoming-a-committer).
diff --git a/website/src/css/custom.css b/website/src/css/custom.css
index 5c527f73..bccf0bfa 100644
--- a/website/src/css/custom.css
+++ b/website/src/css/custom.css
@@ -109,4 +109,38 @@ html[data-theme='dark'] {
.blogThumbnail {
padding-left: 0;
padding-right: 48px;
-}
\ No newline at end of file
+}
+
+/* BlogLayout wraps the blog list and the single-post page in Infima's
+ .container, which caps at --ifm-container-width. That defaults to 1140px and
+ leaves a wide monitor mostly empty. Infima reads the variable on the
element,
+ so setting it here widens only the blog pages and leaves the docs, the
+ release notes and the home page at the default line length. See
+ src/theme/BlogLayout/index.js. */
+.blogLayoutContainer {
+ --ifm-container-width: 1600px;
+ --ifm-container-width-xl: 1600px;
+}
+
+/* Blog list cards: two per row on wide screens, one per row on narrow ones.
+ This replaces an inline width:50% on the post container, which no stylesheet
+ could override, held at every breakpoint, and also applied to the
single-post
+ page. See src/theme/BlogPostItem/Container/index.js. */
+.blogPostCard {
+ width: 50%;
+}
+
+@media (max-width: 996px) {
+ .blogPostCard {
+ width: 100%;
+ }
+}
+
+/* Blog list thumbnails differ in aspect ratio. Most are 2:1 and fill the
column
+ at about 365px tall, so cap every thumbnail there: a near-square image then
+ stands as tall as its neighbours instead of pushing its title far below.
+ The same image is the hero on the single-post page, where there is no
+ neighbour to line up with, so scope the cap to the list cards. */
+.blogPostCard .blog-image {
+ max-height: 365px;
+}
diff --git a/website/src/theme/BlogLayout/index.js
b/website/src/theme/BlogLayout/index.js
index 17be6cfc..fe9ca46f 100644
--- a/website/src/theme/BlogLayout/index.js
+++ b/website/src/theme/BlogLayout/index.js
@@ -7,7 +7,7 @@ export default function BlogLayout(props) {
const hasSidebar = false;
return (
<Layout {...layoutProps}>
- <div className="container margin-vert--lg">
+ <div className="container blogLayoutContainer margin-vert--lg">
<div className="row">
<main
className={clsx('col row')}
diff --git a/website/src/theme/BlogPostItem/Container/index.js
b/website/src/theme/BlogPostItem/Container/index.js
index 81170501..294fee8a 100644
--- a/website/src/theme/BlogPostItem/Container/index.js
+++ b/website/src/theme/BlogPostItem/Container/index.js
@@ -1,4 +1,5 @@
import React from 'react';
+import clsx from 'clsx';
import Link from '@docusaurus/Link';
import {useLocation} from 'react-router-dom';
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
@@ -8,6 +9,7 @@ export default function BlogPostItemContainer({children,
className}) {
const {
frontMatter,
assets,
+ isBlogPostPage,
metadata: {description, permalink},
} = useBlogPost();
const location = useLocation();
@@ -17,8 +19,7 @@ export default function BlogPostItemContainer({children,
className}) {
return (
<article
- className={className}
- style={{ width: "50%" }}
+ className={clsx(className, !isBlogPostPage && 'blogPostCard')}
itemProp="blogPost"
itemScope
itemType="https://schema.org/BlogPosting">
@@ -28,9 +29,7 @@ export default function BlogPostItemContainer({children,
className}) {
{location.pathname.startsWith('/blog') ? (
<Link itemProp="url" to={permalink}>
<img
- src={withBaseUrl(image, {
- absolute: true,
- })}
+ src={withBaseUrl(image)}
className="blog-image"
/>
</Link>