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

gurwls223 pushed a commit to branch branch-3.5
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-3.5 by this push:
     new a1364217df7c [SPARK-52562][INFRA] Automatically create the base of 
release notes and push
a1364217df7c is described below

commit a1364217df7cdc5cfb9e763b33f0229fdf71df67
Author: Hyukjin Kwon <[email protected]>
AuthorDate: Wed Jun 25 08:42:25 2025 +0900

    [SPARK-52562][INFRA] Automatically create the base of release notes and push
    
    ### What changes were proposed in this pull request?
    
    This PR proposes to add the automatic release note process. Here is what it 
does:
    
    1. Add download link to docs
      Inserts the new release version link into `documentation.md`, keeping 
versions sorted by recency.
    
    2. Add download link to spark-website
      Updates `js/downloads.js` with the new version's metadata for the 
downloads page. Replaces existing entry if it's a patch; inserts new entry 
otherwise. Uses different package lists for Spark 3 vs. Spark 4.
    
    3. Generate news & release notes
      Creates a news post and release notes file as below. Note that I skipped 
the short link generation step here.
        - For minor/major releases (x.y.0), describes new features
        - For patch/maintenance releases (x.y.z, z > 0), mentions stability 
fixes and encourages upgrades.
    
    4. Build the Website
      Runs Jekyll to generate updated HTML files for the website.
    
    5. Update latest symlink (only for major/minor)
      Updates the `site/docs/latest` symlink to point to the new version only 
if it's a major or minor release (x.y.0), so maintenance releases don’t affect 
the default documentation version.
    
    If the release manager needs to have better release notes, they can create 
a separate PR to update this.
    
    ### Why are the changes needed?
    
    To make the release process easier.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No, dev-only.
    
    ### How was this patch tested?
    
    I manually tested them in my Mac for now, and checked that they are 
compatible with Ubuntu. It has to be tested in the official release later again.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    No.
    
    Closes #51260 from HyukjinKwon/SPARK-52562.
    
    Authored-by: Hyukjin Kwon <[email protected]>
    Signed-off-by: Hyukjin Kwon <[email protected]>
    (cherry picked from commit 82ab68045759602b1b5a4e8308915375de03be7f)
    Signed-off-by: Hyukjin Kwon <[email protected]>
---
 dev/create-release/release-build.sh | 232 +++++++++++++++++++++++++++++++++++-
 1 file changed, 231 insertions(+), 1 deletion(-)

diff --git a/dev/create-release/release-build.sh 
b/dev/create-release/release-build.sh
index d3f8c509910e..21235e9a8847 100755
--- a/dev/create-release/release-build.sh
+++ b/dev/create-release/release-build.sh
@@ -142,9 +142,239 @@ if [[ "$1" == "finalize" ]]; then
   git commit -m "Add docs for Apache Spark $RELEASE_VERSION"
   git push origin HEAD:asf-site
   cd ..
-  rm -rf spark-website
   echo "docs uploaded"
 
+  echo "Uploading release docs to spark-website"
+  cd spark-website
+
+  # TODO: Test it in the actual release
+  # 1. Add download link to documentation.md
+  python3 <<EOF
+import re
+
+release_version = "${RELEASE_VERSION}"
+newline = f'  <li><a href="{{{{site.baseurl}}}}/docs/{release_version}/">Spark 
{release_version}</a></li>'
+inserted = False
+
+def parse_version(v):
+    return [int(p) for p in v.strip().split(".")]
+
+def vercmp(v1, v2):
+    a = parse_version(v1)
+    b = parse_version(v2)
+    return (a > b) - (a < b)
+
+with open("documentation.md") as f:
+    lines = f.readlines()
+
+with open("documentation.md", "w") as f:
+    for line in lines:
+        match = re.search(r'docs/(\d+\.\d+\.\d+)/', line)
+        if not inserted and match:
+            existing_version = match.group(1)
+            if vercmp(release_version, existing_version) >= 0:
+                f.write(newline + "\n")
+                inserted = True
+        f.write(line)
+    if not inserted:
+        f.write(newline + "\n")
+EOF
+
+  echo "Edited documentation.md"
+
+  # 2. Add download link to js/downloads.js
+  RELEASE_DATE=$(TZ=America/Los_Angeles date +"%m/%d/%Y")
+  IFS='.' read -r rel_maj rel_min rel_patch <<< "$RELEASE_VERSION"
+  NEW_PACKAGES="packagesV14"
+  if [[ "$rel_maj" -ge 4 ]]; then
+    NEW_PACKAGES="packagesV15"
+  fi
+
+  python3 <<EOF
+import re
+
+release_version = "${RELEASE_VERSION}"
+release_date = "${RELEASE_DATE}"
+new_packages = "${NEW_PACKAGES}"
+newline = f'addRelease("{release_version}", new Date("{release_date}"), 
{new_packages}, true);'
+
+new_major, new_minor, new_patch = [int(p) for p in release_version.split(".")]
+
+def parse_version(v):
+    return [int(p) for p in v.strip().split(".")]
+
+def vercmp(v1, v2):
+    a = parse_version(v1)
+    b = parse_version(v2)
+    return (a > b) - (a < b)
+
+inserted = replaced = False
+
+with open("js/downloads.js") as f:
+    lines = f.readlines()
+
+with open("js/downloads.js", "w") as f:
+    for line in lines:
+        m = re.search(r'addRelease\("(\d+\.\d+\.\d+)"', line)
+        if m:
+            existing_version = m.group(1)
+            cmp_result = vercmp(release_version, existing_version)
+            ex_major, ex_minor, ex_patch = parse_version(existing_version)
+
+            if cmp_result == 0:
+                f.write(newline + "\n")
+                replaced = True
+            elif not replaced and ex_major == new_major and ex_minor == 
new_minor:
+                f.write(newline + "\n")
+                replaced = True
+            elif not replaced and not inserted and cmp_result > 0:
+                f.write(newline + "\n")
+                f.write(line)
+                inserted = True
+            else:
+                f.write(line)
+        else:
+            f.write(line)
+    if not replaced and not inserted:
+        f.write(newline + "\n")
+EOF
+
+  echo "Edited js/downloads.js"
+
+  # 3. Add news post
+  RELEASE_DATE=$(TZ=America/Los_Angeles date +"%Y-%m-%d")
+  
FILENAME="news/_posts/${RELEASE_DATE}-spark-${RELEASE_VERSION//./-}-released.md"
+  mkdir -p news/_posts
+  cat > "$FILENAME" <<EOF
+---
+layout: post
+title: Spark ${RELEASE_VERSION} released
+categories:
+- News
+tags: []
+status: publish
+type: post
+published: true
+meta:
+  _edit_last: '4'
+  _wpas_done_all: '1'
+---
+We are happy to announce the availability of <a 
href="{{site.baseurl}}/releases/spark-release-${RELEASE_VERSION}.html" 
title="Spark Release ${RELEASE_VERSION}">Apache Spark ${RELEASE_VERSION}</a>! 
Visit the <a 
href="{{site.baseurl}}/releases/spark-release-${RELEASE_VERSION}.html" 
title="Spark Release ${RELEASE_VERSION}">release notes</a> to read about the 
new features, or <a href="{{site.baseurl}}/downloads.html">download</a> the 
release today.
+EOF
+
+  echo "Created $FILENAME"
+
+  # 4. Add release notes with Python to extract JIRA version ID
+  RELEASE_DATE=$(TZ=America/Los_Angeles date +"%Y-%m-%d")
+  JIRA_PROJECT_ID=12315420
+  JIRA_URL="https://issues.apache.org/jira/rest/api/2/project/SPARK/versions";
+  JSON=$(curl -s "$JIRA_URL")
+
+  VERSION_ID=$(python3 - <<EOF
+import sys, json
+
+release_version = "${RELEASE_VERSION}"
+json_str = """$JSON"""
+
+try:
+    versions = json.loads(json_str)
+except Exception as e:
+    print(f"Error parsing JSON: {e}", file=sys.stderr)
+    sys.exit(1)
+
+version_id = ""
+for v in versions:
+    if v.get("name") == release_version:
+        version_id = v.get("id", "")
+        break
+
+print(version_id)
+EOF
+  )
+
+  if [[ -z "$VERSION_ID" ]]; then
+    echo "Error: Couldn't find JIRA version ID for $RELEASE_VERSION" >&2
+  fi
+
+  
JIRA_LINK="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=${JIRA_PROJECT_ID}&version=${VERSION_ID}";
+
+  IFS='.' read -r rel_maj rel_min rel_patch <<< "$RELEASE_VERSION"
+  if [[ "$rel_patch" -eq 0 ]]; then
+    ACKNOWLEDGE="patches and features to this release."
+    BODY="Apache Spark ${RELEASE_VERSION} is a new feature release. It 
introduces new functionality and improvements. We encourage users to try it and 
provide feedback."
+  else
+    ACKNOWLEDGE="patches to this release."
+    BODY="Apache Spark ${RELEASE_VERSION} is a maintenance release containing 
security and correctness fixes. This release is based on the 
branch-${rel_maj}.${rel_min} maintenance branch of Spark. We strongly recommend 
all ${rel_maj}.${rel_min} users to upgrade to this stable release."
+  fi
+
+  BODY+="
+
+You can find the list of resolved issues and detailed changes in the [JIRA 
release notes](${JIRA_LINK}).
+
+We would like to acknowledge all community members for contributing 
${ACKNOWLEDGE}"
+
+  
FILENAME="releases/_posts/${RELEASE_DATE}-spark-release-${RELEASE_VERSION}.md"
+  mkdir -p releases/_posts
+  cat > "$FILENAME" <<EOF
+---
+layout: post
+title: Spark Release ${RELEASE_VERSION}
+categories: []
+tags: []
+status: publish
+type: post
+published: true
+meta:
+  _edit_last: '4'
+  _wpas_done_all: '1'
+---
+
+${BODY}
+EOF
+
+  echo "Created $FILENAME"
+
+  # 5. Build the website
+  bundle install
+  bundle exec jekyll build
+
+  # 6. Update latest symlink if minor/major release
+  LINK_PATH="site/docs/latest"
+  TARGET_DIR="site/docs/$RELEASE_VERSION"
+  IFS='.' read -r rel_maj rel_min rel_patch <<< "$RELEASE_VERSION"
+  if [[ "$rel_patch" -eq 0 ]]; then
+    if [[ -L "$LINK_PATH" ]]; then
+      CURRENT_TARGET=$(readlink "$LINK_PATH")
+    else
+      CURRENT_TARGET=""
+    fi
+
+    if [[ "$CURRENT_TARGET" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+      IFS='.' read -r cur_maj cur_min cur_patch <<< "$CURRENT_TARGET"
+
+      if [[ "$rel_maj" -gt "$cur_maj" ]]; then
+        ln -sfn "$RELEASE_VERSION" "$LINK_PATH"
+        echo "Updated symlink $LINK_PATH -> $RELEASE_VERSION (major version 
increased)"
+      elif [[ "$rel_maj" -eq "$cur_maj" && "$rel_min" -gt "$cur_min" ]]; then
+        ln -sfn "$RELEASE_VERSION" "$LINK_PATH"
+        echo "Updated symlink $LINK_PATH -> $RELEASE_VERSION (minor version 
increased)"
+      else
+        echo "Symlink $LINK_PATH points to $CURRENT_TARGET with equal or newer 
major.minor, no change"
+      fi
+    else
+      echo "No valid existing version target."
+    fi
+  else
+    echo "Patch release detected ($RELEASE_VERSION), not updating symlink"
+  fi
+
+  git add .
+  git commit -m "Add release docs for Apache Spark $RELEASE_VERSION"
+  git push origin HEAD:asf-site
+  cd ..
+  echo "release docs uploaded"
+  rm -rf spark-website
+
   # Moves the docs from dev directory to release directory.
   echo "Moving Spark docs to the release directory"
   svn mv --username "$ASF_USERNAME" --password "$ASF_PASSWORD" -m"Apache Spark 
$RELEASE_VERSION" \


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to