From 78cc142ad70f6c05a7f48739983edb51f8067b58 Mon Sep 17 00:00:00 2001 From: LiteSun Date: Tue, 10 Jun 2025 18:25:50 +0800 Subject: [PATCH 1/6] feat: add script to check PRs against CHANGELOG.md for completeness --- ci/check_changelog_prs.sh | 82 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100755 ci/check_changelog_prs.sh diff --git a/ci/check_changelog_prs.sh b/ci/check_changelog_prs.sh new file mode 100755 index 000000000000..c8f1ac8b7daa --- /dev/null +++ b/ci/check_changelog_prs.sh @@ -0,0 +1,82 @@ +#!/bin/bash +set -euo pipefail + +old_tag=$1 +new_tag=$2 + +# Configure PR types to ignore +IGNORE_TYPES=( + "docs" + "chore" + "test" + "ci" +) + +# Configure PR numbers to ignore +IGNORE_PRS=( + # 3.9.0 + 10655 10857 10858 10887 10959 11029 11041 11053 11055 11061 10976 10984 11025 + # 3.10.0 + 11105 11128 11169 11171 11280 11333 11081 11202 11469 + # 3.11.0 + 11463 11570 + # 3.12.0 + 11769 11816 11881 11905 11924 11926 11973 11991 11992 11829 +) + +# Build ignore pattern to match the following formats: +# - Direct keyword prefix (e.g., "docs:") +ignore_pattern=$(IFS="|"; echo "(${IGNORE_TYPES[*]}):|(${IGNORE_TYPES[*]})\([^)]*\):") + +# Extract PRs between two versions from CHANGELOG.md +echo "Extracting PRs between $old_tag and $new_tag from CHANGELOG.md..." +changelog_prs=$(awk -v start="$new_tag" -v end="$old_tag" ' + BEGIN { flag = 0 } + $0 ~ "^## " { + if ($0 ~ start) { flag = 1; next } + if (flag && $0 ~ end) { flag = 0 } + } + flag { print } +' CHANGELOG.md | grep -oE '#[0-9]+' | sort -n) + +# Extract actual PRs from git log, filtering out configured types and specified PR numbers +echo -e "\nExtracting actual PRs from git log (excluding: ${IGNORE_TYPES[*]} and PRs: ${IGNORE_PRS[*]})..." +git_prs=$(git log "$old_tag".."$new_tag" --oneline | grep -vE "$ignore_pattern" | grep -oE '#[0-9]+' | sort -n) + +# Filter out specified PR numbers +for pr in "${IGNORE_PRS[@]}"; do + git_prs=$(echo "$git_prs" | grep -v "#$pr") +done + +# Compare the two lists +echo -e "\nComparing PRs..." +missing_prs=$(comm -23 <(echo "$git_prs") <(echo "$changelog_prs")) + +# Print comparison results +echo -e "\n=== PR Comparison Results ===" +echo -e "\nPRs in git log (sorted, excluding configured types):" +echo "$git_prs" | sed 's/^/ /' + +echo -e "\nPRs in CHANGELOG.md (sorted):" +echo "$changelog_prs" | sed 's/^/ /' + +if [ -z "$missing_prs" ]; then + echo -e "\n✅ All PRs are included in CHANGELOG.md" +else + echo -e "\n❌ Missing PRs in CHANGELOG.md (sorted):" + echo "$missing_prs" | sed 's/^/ /' + + # Get detailed information for each missing PR + echo -e "\nDetailed information about missing PRs:" + for pr in $missing_prs; do + pr_num=${pr#\#} # Remove # symbol + echo -e "\nPR $pr:" + # Get PR commit information + git log "$old_tag".."$new_tag" --oneline | grep "$pr" | while read -r line; do + echo " - $line" + done + # Try to get PR title (if possible) + echo " - PR URL: https://github.com/apache/apisix/pull/$pr_num" + done + exit 1 +fi From 94a5daa13a41fb09c86934fa6c18bf6539932699 Mon Sep 17 00:00:00 2001 From: LiteSun Date: Wed, 11 Jun 2025 08:54:36 +0800 Subject: [PATCH 2/6] f --- .github/workflows/check-changelog.yml | 30 +++++++++++++++++++++++++++ ci/check_changelog_prs.sh | 28 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/workflows/check-changelog.yml diff --git a/.github/workflows/check-changelog.yml b/.github/workflows/check-changelog.yml new file mode 100644 index 000000000000..aedb6fe36a5b --- /dev/null +++ b/.github/workflows/check-changelog.yml @@ -0,0 +1,30 @@ +name: Check Changelog + +on: + push: + paths: + - 'CHANGELOG.md' + pull_request: + paths: + - 'CHANGELOG.md' + +jobs: + check-changelog: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run check_changelog_prs script + run: | + # Extract the latest two versions from CHANGELOG.md + versions=($(grep -E '^## [0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | head -n 2 | sed 's/^## //')) + if [ ${#versions[@]} -ge 2 ]; then + new_tag=${versions[0]} + old_tag=${versions[1]} + bash ci/check_changelog_prs.sh "$old_tag" "$new_tag" + else + echo "Not enough versions found in CHANGELOG.md" + exit 1 + fi diff --git a/ci/check_changelog_prs.sh b/ci/check_changelog_prs.sh index c8f1ac8b7daa..fc9011ac86b2 100755 --- a/ci/check_changelog_prs.sh +++ b/ci/check_changelog_prs.sh @@ -1,9 +1,37 @@ #!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + set -euo pipefail old_tag=$1 new_tag=$2 +# Function to compare versions +version_gt() { + test "$(printf '%s\n' "$@" | sort -V | head -n1)" != "$1" +} + +# Check if versions are above 3.8.0 +if ! version_gt "${old_tag#v}" "3.8.0"; then + echo "Skipping check for versions below or equal to 3.8.0" + exit 0 +fi + # Configure PR types to ignore IGNORE_TYPES=( "docs" From 13e62bc75d202a55d60722f712a08619ebbb9e66 Mon Sep 17 00:00:00 2001 From: LiteSun Date: Wed, 11 Jun 2025 10:22:45 +0800 Subject: [PATCH 3/6] t --- .github/workflows/check-changelog.yml | 11 +-- CHANGELOG.md | 1 - ci/check_changelog_prs.sh | 127 +++++++++++++++----------- 3 files changed, 73 insertions(+), 66 deletions(-) diff --git a/.github/workflows/check-changelog.yml b/.github/workflows/check-changelog.yml index aedb6fe36a5b..ce82fb7afed7 100644 --- a/.github/workflows/check-changelog.yml +++ b/.github/workflows/check-changelog.yml @@ -18,13 +18,4 @@ jobs: - name: Run check_changelog_prs script run: | - # Extract the latest two versions from CHANGELOG.md - versions=($(grep -E '^## [0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | head -n 2 | sed 's/^## //')) - if [ ${#versions[@]} -ge 2 ]; then - new_tag=${versions[0]} - old_tag=${versions[1]} - bash ci/check_changelog_prs.sh "$old_tag" "$new_tag" - else - echo "Not enough versions found in CHANGELOG.md" - exit 1 - fi + bash ci/check_changelog_prs.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a5bade1350b..e881dccd3aee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,7 +83,6 @@ title: Changelog ### Change -- replace plugin attribute with plugin metadata in `opentelemetry` plugin [#11940](https://github.com/apache/apisix/pull/11940) - refactor: ai-content-moderation to ai-aws-content-moderation [#11596](https://github.com/apache/apisix/pull/11596]) - add expiration time for all Prometheus metrics [#11838](https://github.com/apache/apisix/pull/11838) - allow workflow config without case [#11787](https://github.com/apache/apisix/pull/11787) diff --git a/ci/check_changelog_prs.sh b/ci/check_changelog_prs.sh index fc9011ac86b2..cb64226c56c0 100755 --- a/ci/check_changelog_prs.sh +++ b/ci/check_changelog_prs.sh @@ -18,20 +18,17 @@ set -euo pipefail -old_tag=$1 -new_tag=$2 - # Function to compare versions version_gt() { - test "$(printf '%s\n' "$@" | sort -V | head -n1)" != "$1" + local v1=$1 + local v2=$2 + # Remove 'v' prefix if present + v1=${v1#v} + v2=${v2#v} + # Compare versions using sort -V + [ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n1)" != "$v1" ] } -# Check if versions are above 3.8.0 -if ! version_gt "${old_tag#v}" "3.8.0"; then - echo "Skipping check for versions below or equal to 3.8.0" - exit 0 -fi - # Configure PR types to ignore IGNORE_TYPES=( "docs" @@ -56,55 +53,75 @@ IGNORE_PRS=( # - Direct keyword prefix (e.g., "docs:") ignore_pattern=$(IFS="|"; echo "(${IGNORE_TYPES[*]}):|(${IGNORE_TYPES[*]})\([^)]*\):") -# Extract PRs between two versions from CHANGELOG.md -echo "Extracting PRs between $old_tag and $new_tag from CHANGELOG.md..." -changelog_prs=$(awk -v start="$new_tag" -v end="$old_tag" ' - BEGIN { flag = 0 } - $0 ~ "^## " { - if ($0 ~ start) { flag = 1; next } - if (flag && $0 ~ end) { flag = 0 } - } - flag { print } -' CHANGELOG.md | grep -oE '#[0-9]+' | sort -n) - -# Extract actual PRs from git log, filtering out configured types and specified PR numbers -echo -e "\nExtracting actual PRs from git log (excluding: ${IGNORE_TYPES[*]} and PRs: ${IGNORE_PRS[*]})..." -git_prs=$(git log "$old_tag".."$new_tag" --oneline | grep -vE "$ignore_pattern" | grep -oE '#[0-9]+' | sort -n) - -# Filter out specified PR numbers -for pr in "${IGNORE_PRS[@]}"; do - git_prs=$(echo "$git_prs" | grep -v "#$pr") -done +# Get all versions from CHANGELOG.md +versions=($(grep -E '^## [0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | sed 's/^## //')) -# Compare the two lists -echo -e "\nComparing PRs..." -missing_prs=$(comm -23 <(echo "$git_prs") <(echo "$changelog_prs")) +# Initialize error flag +has_errors=0 -# Print comparison results -echo -e "\n=== PR Comparison Results ===" -echo -e "\nPRs in git log (sorted, excluding configured types):" -echo "$git_prs" | sed 's/^/ /' +# Process each pair of consecutive versions +for ((i=0; i<${#versions[@]}-1; i++)); do + new_tag=${versions[i]} + old_tag=${versions[i+1]} + + # Skip if new_tag is less than or equal to 3.8.0 + if ! version_gt "$new_tag" "3.8.0"; then + continue + fi -echo -e "\nPRs in CHANGELOG.md (sorted):" -echo "$changelog_prs" | sed 's/^/ /' + echo -e "\n=== Checking changes between $new_tag and $old_tag ===" -if [ -z "$missing_prs" ]; then - echo -e "\n✅ All PRs are included in CHANGELOG.md" -else - echo -e "\n❌ Missing PRs in CHANGELOG.md (sorted):" - echo "$missing_prs" | sed 's/^/ /' - - # Get detailed information for each missing PR - echo -e "\nDetailed information about missing PRs:" - for pr in $missing_prs; do - pr_num=${pr#\#} # Remove # symbol - echo -e "\nPR $pr:" - # Get PR commit information - git log "$old_tag".."$new_tag" --oneline | grep "$pr" | while read -r line; do - echo " - $line" - done - # Try to get PR title (if possible) - echo " - PR URL: https://github.com/apache/apisix/pull/$pr_num" + # Extract PRs between two versions from CHANGELOG.md + echo "Extracting PRs from CHANGELOG.md..." + changelog_prs=$(awk -v start="$new_tag" -v end="$old_tag" ' + BEGIN { flag = 0 } + $0 ~ "^## " { + if ($0 ~ start) { flag = 1; next } + if (flag && $0 ~ end) { flag = 0 } + } + flag { print } + ' CHANGELOG.md | grep -oE '#[0-9]+' | sort -n) + + # Extract actual PRs from git log, filtering out configured types and specified PR numbers + echo "Extracting actual PRs from git log (excluding: ${IGNORE_TYPES[*]} and PRs: ${IGNORE_PRS[*]})..." + git_prs=$(git log "$old_tag".."$new_tag" --oneline | grep -vE "$ignore_pattern" | grep -oE '#[0-9]+' | sort -n) + + # Filter out specified PR numbers + for pr in "${IGNORE_PRS[@]}"; do + git_prs=$(echo "$git_prs" | grep -v "#$pr") done + + # Compare the two lists + echo "Comparing PRs..." + missing_prs=$(comm -23 <(echo "$git_prs") <(echo "$changelog_prs")) + + # Print comparison results + echo -e "\n=== PR Comparison Results for $new_tag ===" + + if [ -z "$missing_prs" ]; then + echo -e "\n✅ All PRs are included in CHANGELOG.md for version $new_tag" + else + echo -e "\n❌ [ERROR] Missing PRs in CHANGELOG.md for version $new_tag (sorted):" + echo "$missing_prs" | sed 's/^/ /' + + # Get detailed information for each missing PR + echo -e "\nDetailed information about missing PRs for version $new_tag:" + for pr in $missing_prs; do + pr_num=${pr#\#} # Remove # symbol + echo -e "\nPR $pr :" + # Get PR commit information + git log "$old_tag".."$new_tag" --oneline | grep "$pr" | while read -r line; do + echo " - $line" + done + # Try to get PR title (if possible) + echo " - PR URL: https://github.com/apache/apisix/pull/$pr_num" + done + echo "Note: If you confirm that a PR should not appear in the changelog, please add its number to the IGNORE_PRS array in this script." + has_errors=1 + fi +done + +# Exit with error if any version had missing PRs +if [ $has_errors -eq 1 ]; then exit 1 fi From d310baf8cab387d900a329b8e74997b733e1042f Mon Sep 17 00:00:00 2001 From: LiteSun Date: Wed, 11 Jun 2025 10:33:08 +0800 Subject: [PATCH 4/6] f --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e881dccd3aee..7a5bade1350b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ title: Changelog ### Change +- replace plugin attribute with plugin metadata in `opentelemetry` plugin [#11940](https://github.com/apache/apisix/pull/11940) - refactor: ai-content-moderation to ai-aws-content-moderation [#11596](https://github.com/apache/apisix/pull/11596]) - add expiration time for all Prometheus metrics [#11838](https://github.com/apache/apisix/pull/11838) - allow workflow config without case [#11787](https://github.com/apache/apisix/pull/11787) From 42c803a7b040e0c8a7700af6ff9c2f4a4b37aa1a Mon Sep 17 00:00:00 2001 From: LiteSun Date: Wed, 11 Jun 2025 10:46:52 +0800 Subject: [PATCH 5/6] f --- ci/check_changelog_prs.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ci/check_changelog_prs.sh b/ci/check_changelog_prs.sh index cb64226c56c0..9a8caf584453 100755 --- a/ci/check_changelog_prs.sh +++ b/ci/check_changelog_prs.sh @@ -54,7 +54,7 @@ IGNORE_PRS=( ignore_pattern=$(IFS="|"; echo "(${IGNORE_TYPES[*]}):|(${IGNORE_TYPES[*]})\([^)]*\):") # Get all versions from CHANGELOG.md -versions=($(grep -E '^## [0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | sed 's/^## //')) +mapfile -t versions < <(grep -E '^## [0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | sed 's/^## //') # Initialize error flag has_errors=0 @@ -63,7 +63,7 @@ has_errors=0 for ((i=0; i<${#versions[@]}-1; i++)); do new_tag=${versions[i]} old_tag=${versions[i+1]} - + # Skip if new_tag is less than or equal to 3.8.0 if ! version_gt "$new_tag" "3.8.0"; then continue @@ -102,8 +102,9 @@ for ((i=0; i<${#versions[@]}-1; i++)); do echo -e "\n✅ All PRs are included in CHANGELOG.md for version $new_tag" else echo -e "\n❌ [ERROR] Missing PRs in CHANGELOG.md for version $new_tag (sorted):" - echo "$missing_prs" | sed 's/^/ /' - + + printf ' %s\n' "$missing_prs" + # Get detailed information for each missing PR echo -e "\nDetailed information about missing PRs for version $new_tag:" for pr in $missing_prs; do From 4945019d7baa229822a15532cedfbc8bedc74627 Mon Sep 17 00:00:00 2001 From: LiteSun Date: Wed, 11 Jun 2025 11:16:36 +0800 Subject: [PATCH 6/6] f --- ci/check_changelog_prs.sh | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ci/check_changelog_prs.sh b/ci/check_changelog_prs.sh index 9a8caf584453..d5dad0d51c2c 100755 --- a/ci/check_changelog_prs.sh +++ b/ci/check_changelog_prs.sh @@ -29,6 +29,16 @@ version_gt() { [ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n1)" != "$v1" ] } +# Function to get git reference (tag or HEAD) +get_git_ref() { + local version=$1 + if git rev-parse "$version" >/dev/null 2>&1; then + echo "$version" + else + echo "HEAD" + fi +} + # Configure PR types to ignore IGNORE_TYPES=( "docs" @@ -69,7 +79,11 @@ for ((i=0; i<${#versions[@]}-1; i++)); do continue fi - echo -e "\n=== Checking changes between $new_tag and $old_tag ===" + # Get git references + new_ref=$(get_git_ref "$new_tag") + old_ref=$(get_git_ref "$old_tag") + + echo -e "\n=== Checking changes between $new_tag ($new_ref) and $old_tag ($old_ref) ===" # Extract PRs between two versions from CHANGELOG.md echo "Extracting PRs from CHANGELOG.md..." @@ -84,7 +98,7 @@ for ((i=0; i<${#versions[@]}-1; i++)); do # Extract actual PRs from git log, filtering out configured types and specified PR numbers echo "Extracting actual PRs from git log (excluding: ${IGNORE_TYPES[*]} and PRs: ${IGNORE_PRS[*]})..." - git_prs=$(git log "$old_tag".."$new_tag" --oneline | grep -vE "$ignore_pattern" | grep -oE '#[0-9]+' | sort -n) + git_prs=$(git log "$old_ref..$new_ref" --oneline | grep -vE "$ignore_pattern" | grep -oE '#[0-9]+' | sort -n) # Filter out specified PR numbers for pr in "${IGNORE_PRS[@]}"; do @@ -102,7 +116,6 @@ for ((i=0; i<${#versions[@]}-1; i++)); do echo -e "\n✅ All PRs are included in CHANGELOG.md for version $new_tag" else echo -e "\n❌ [ERROR] Missing PRs in CHANGELOG.md for version $new_tag (sorted):" - printf ' %s\n' "$missing_prs" # Get detailed information for each missing PR @@ -111,7 +124,7 @@ for ((i=0; i<${#versions[@]}-1; i++)); do pr_num=${pr#\#} # Remove # symbol echo -e "\nPR $pr :" # Get PR commit information - git log "$old_tag".."$new_tag" --oneline | grep "$pr" | while read -r line; do + git log "$old_ref..$new_ref" --oneline | grep "$pr" | while read -r line; do echo " - $line" done # Try to get PR title (if possible)