Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions .github/scripts/release/test-update-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
#!/bin/bash
# Test script for update-changelog.sh

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
UPDATE_SCRIPT="${SCRIPT_DIR}/update-changelog.sh"
TEST_DIR="/tmp/changelog-test-$$"

# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color

passed=0
failed=0

# Setup test directory
mkdir -p "$TEST_DIR"

# Cleanup on exit
cleanup() {
rm -rf "$TEST_DIR"
}
trap cleanup EXIT

# Helper function to run a test
run_test() {
local test_name="$1"
local test_func="$2"

echo -n "Testing: $test_name ... "

if $test_func; then
echo -e "${GREEN}PASSED${NC}"
passed=$((passed + 1))
else
echo -e "${RED}FAILED${NC}"
failed=$((failed + 1))
fi
}

# Test 1: Basic functionality - Replace Unreleased with version
test_basic_replace() {
local test_file="${TEST_DIR}/test1.md"
cat > "$test_file" << 'EOF'
# Changelog

## [Unreleased]

### Added
- New feature

## [1.0.0] - 2026-01-01

### Added
- Initial release

[1.0.0]: https://github.com/test/repo/releases/tag/1.0.0
EOF

# Run the script
CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.1 > /dev/null 2>&1

# Verify the changes
if grep -q "## \[Unreleased\]" "$test_file" && \
grep -q "## \[1.0.1\] - $(date +%Y-%m-%d)" "$test_file" && \
grep -q "\[Unreleased\]: https://github.com/test/repo/compare/java/v1.0.1...HEAD" "$test_file" && \
grep -q "\[1.0.1\]: https://github.com/test/repo/compare/java/v1.0.0...java/v1.0.1" "$test_file"; then
return 0
Comment thread
edburns marked this conversation as resolved.
else
return 1
fi
}

# Test 2: Handle CHANGELOG without Unreleased link
test_no_unreleased_link() {
local test_file="${TEST_DIR}/test2.md"
cat > "$test_file" << 'EOF'
# Changelog

## [Unreleased]

### Added
- New feature

## [1.0.0] - 2026-01-01

[1.0.0]: https://github.com/test/repo/releases/tag/1.0.0
EOF

CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.1 > /dev/null 2>&1

# Should add both Unreleased and version links
if grep -q "\[Unreleased\]: https://github.com/test/repo/compare/java/v1.0.1...HEAD" "$test_file" && \
grep -q "\[1.0.1\]: https://github.com/test/repo/compare/java/v1.0.0...java/v1.0.1" "$test_file"; then
return 0
else
return 1
fi
}

# Test 3: Preserve content structure
test_preserve_content() {
local test_file="${TEST_DIR}/test3.md"
cat > "$test_file" << 'EOF'
# Changelog

## [Unreleased]

### Added
- Feature A
- Feature B

### Fixed
- Bug fix

## [1.0.0] - 2026-01-01

[1.0.0]: https://github.com/test/repo/releases/tag/1.0.0
EOF

CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.1 > /dev/null 2>&1

# Verify content is preserved under the new version
if grep -A 6 "## \[1.0.1\]" "$test_file" | grep -q "Feature A" && \
grep -A 6 "## \[1.0.1\]" "$test_file" | grep -q "Bug fix"; then
return 0
else
return 1
fi
}

# Test 4: Error handling - no Unreleased section
test_no_unreleased_section() {
local test_file="${TEST_DIR}/test4.md"
cat > "$test_file" << 'EOF'
# Changelog

## [1.0.0] - 2026-01-01

[1.0.0]: https://github.com/test/repo/releases/tag/1.0.0
EOF

# Should fail because there's no Unreleased section
if ! CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.1 > /dev/null 2>&1; then
return 0
else
return 1
fi
}

# Test 5: Multiple version handling
test_multiple_versions() {
local test_file="${TEST_DIR}/test5.md"
cat > "$test_file" << 'EOF'
# Changelog

## [Unreleased]

### Added
- New feature

## [1.0.1] - 2026-02-01

## [1.0.0] - 2026-01-01

[1.0.1]: https://github.com/test/repo/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/test/repo/releases/tag/1.0.0
EOF

CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.2 > /dev/null 2>&1

# Verify the new version is added and links are updated
if grep -q "## \[1.0.2\] - $(date +%Y-%m-%d)" "$test_file" && \
grep -q "\[1.0.2\]: https://github.com/test/repo/compare/java/v1.0.1...java/v1.0.2" "$test_file"; then
return 0
else
return 1
fi
}

# Test 6: Beta-java version format (e.g., 1.0.0-beta-java.N)
test_beta_java_version() {
local test_file="${TEST_DIR}/test6.md"
cat > "$test_file" << 'EOF'
# Changelog

## [Unreleased]

### Added
- New feature

## [1.0.0-beta-java.1] - 2026-05-01

[Unreleased]: https://github.com/test/repo/compare/v1.0.0-beta-java.1...HEAD
[1.0.0-beta-java.1]: https://github.com/test/repo/compare/v0.3.0-java.2...v1.0.0-beta-java.1
[0.3.0-java.2]: https://github.com/test/repo/releases/tag/0.3.0-java.2
EOF

CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.0-beta-java.2 > /dev/null 2>&1

# The [Unreleased] link should now point to java/v1.0.0-beta-java.2
# [1.0.0-beta-java.2] should compare from java/v1.0.0-beta-java.1
if grep -q "\[Unreleased\]: https://github.com/test/repo/compare/java/v1.0.0-beta-java.2...HEAD" "$test_file" && \
grep -q "\[1.0.0-beta-java.2\]: https://github.com/test/repo/compare/java/v1.0.0-beta-java.1...java/v1.0.0-beta-java.2" "$test_file"; then
return 0
else
return 1
fi
}

# Test 7: No duplicate [Unreleased] links when existing [Unreleased] link is present
test_no_duplicate_unreleased_links() {
local test_file="${TEST_DIR}/test7.md"
cat > "$test_file" << 'EOF'
# Changelog

## [Unreleased]

### Added
- New feature

## [1.0.0-beta-java.2] - 2026-05-08

## [1.0.0-beta-java.1] - 2026-05-05

[Unreleased]: https://github.com/test/repo/compare/v1.0.0-beta-java.2...HEAD
[1.0.0-beta-java.2]: https://github.com/test/repo/compare/v1.0.0-beta-java.1...v1.0.0-beta-java.2
[1.0.0-beta-java.1]: https://github.com/test/repo/compare/v0.3.0-java.2...v1.0.0-beta-java.1
[0.3.0-java.2]: https://github.com/test/repo/releases/tag/0.3.0-java.2
EOF

CHANGELOG_FILE="$test_file" bash "$UPDATE_SCRIPT" 1.0.0-beta-java.3 > /dev/null 2>&1

# Count [Unreleased] link definitions - there should be exactly one
local unreleased_count
unreleased_count=$(grep -c "^\[Unreleased\]:" "$test_file")
if [ "$unreleased_count" -eq 1 ] && \
grep -q "\[Unreleased\]: https://github.com/test/repo/compare/java/v1.0.0-beta-java.3...HEAD" "$test_file" && \
grep -q "\[1.0.0-beta-java.3\]: https://github.com/test/repo/compare/java/v1.0.0-beta-java.2...java/v1.0.0-beta-java.3" "$test_file"; then
return 0
else
return 1
fi
}

# Run all tests
echo "Running CHANGELOG update script tests..."
echo ""

run_test "Basic functionality - Replace Unreleased with version" test_basic_replace
run_test "Handle CHANGELOG without Unreleased link" test_no_unreleased_link
run_test "Preserve content structure" test_preserve_content
run_test "Error handling - no Unreleased section" test_no_unreleased_section
run_test "Multiple version handling" test_multiple_versions
run_test "Beta-java version format (e.g., 1.0.0-beta-java.N)" test_beta_java_version
run_test "No duplicate [Unreleased] links when existing link is present" test_no_duplicate_unreleased_links

echo ""
echo "=========================================="
echo -e "Tests passed: ${GREEN}${passed}${NC}"
echo -e "Tests failed: ${RED}${failed}${NC}"
echo "=========================================="

if [ $failed -eq 0 ]; then
exit 0
else
exit 1
fi
125 changes: 125 additions & 0 deletions .github/scripts/release/update-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/bash
set -e

# Script to update CHANGELOG.md during release process
# Usage: ./update-changelog.sh <version> [reference-impl-hash]
# Example: ./update-changelog.sh 1.0.8
# Example: ./update-changelog.sh 1.0.8 05e3c46c8c23130c9c064dc43d00ec78f7a75eab

if [ -z "$1" ]; then
echo "Error: Version argument required"
echo "Usage: $0 <version> [reference-impl-hash]"
exit 1
fi

VERSION="$1"
REFERENCE_IMPL_HASH="${2:-}"
CHANGELOG_FILE="${CHANGELOG_FILE:-CHANGELOG.md}"
RELEASE_DATE=$(date +%Y-%m-%d)

echo "Updating CHANGELOG.md for version ${VERSION} (${RELEASE_DATE})"
if [ -n "$REFERENCE_IMPL_HASH" ]; then
echo " Reference implementation SDK sync: ${REFERENCE_IMPL_HASH:0:7}"
fi

# Check if CHANGELOG.md exists
if [ ! -f "$CHANGELOG_FILE" ]; then
echo "Error: CHANGELOG.md not found"
exit 1
fi

# Check if there's an [Unreleased] section
if ! grep -q "## \[Unreleased\]" "$CHANGELOG_FILE"; then
echo "Error: No [Unreleased] section found in CHANGELOG.md"
exit 1
fi

# Create a temporary file
TEMP_FILE=$(mktemp)

# Process the CHANGELOG
awk -v version="$VERSION" -v date="$RELEASE_DATE" -v REFERENCE_IMPL_HASH="$REFERENCE_IMPL_HASH" '
BEGIN {
unreleased_found = 0
content_found = 0
links_section = 0
first_version_link = ""
repo_url = ""
unreleased_link_handled = 0
}

# Track if we are in the links section at the bottom
/^\[/ {
links_section = 1
}

# Capture the repository URL from the first version link
links_section && repo_url == "" && /^\[[0-9]+\.[0-9]+\.[0-9]+(-(beta-)?java(-preview)?\.[0-9]+)?\]:/ {
match($0, /(https:\/\/github\.com\/[^\/]+\/[^\/]+)\//, arr)
if (arr[1] != "") {
repo_url = arr[1]
}
}

# Replace [Unreleased] with the version and date
/^## \[Unreleased\]/ {
if (!unreleased_found) {
print "## [Unreleased]"
print ""
if (REFERENCE_IMPL_HASH != "") {
short_hash = substr(REFERENCE_IMPL_HASH, 1, 7)
print "> **Reference implementation sync:** [`github/copilot-sdk@" short_hash "`](https://github.com/github/copilot-sdk/commit/" REFERENCE_IMPL_HASH ")"
print ""
}
print "## [" version "] - " date
if (REFERENCE_IMPL_HASH != "") {
print ""
print "> **Reference implementation sync:** [`github/copilot-sdk@" short_hash "`](https://github.com/github/copilot-sdk/commit/" REFERENCE_IMPL_HASH ")"
}
unreleased_found = 1
skip_old_reference_impl = 1
next
}
}

# Skip the old Reference implementation sync line and surrounding blank lines from the previous [Unreleased] section
skip_old_reference_impl && /^[[:space:]]*$/ { next }
skip_old_reference_impl && /^> \*\*Reference implementation sync:\*\*/ { next }
skip_old_reference_impl && !/^[[:space:]]*$/ && !/^> \*\*Reference implementation sync:\*\*/ { skip_old_reference_impl = 0 }

# Update existing [Unreleased] link if present (must be checked before the first-version-link block)
links_section && /^\[Unreleased\]:/ {
# Get the previous version and repo URL from the existing link (handles both v and java/v prefix)
match($0, /(https:\/\/github\.com\/[^\/]+\/[^\/]+)\/compare\/(java\/)?v([0-9]+\.[0-9]+\.[0-9]+(-(beta-)?java(-preview)?\.[0-9]+)?)\.\.\.HEAD/, arr)
if (arr[1] != "" && arr[3] != "") {
print "[Unreleased]: " arr[1] "/compare/java/v" version "...HEAD"
print "[" version "]: " arr[1] "/compare/java/v" arr[3] "...java/v" version
unreleased_link_handled = 1
next
}
}

# Capture the first version link to get the previous version
# Only fires if the [Unreleased] link was not already handled above
links_section && first_version_link == "" && !unreleased_link_handled && /^\[[0-9]+\.[0-9]+\.[0-9]+(-(beta-)?java(-preview)?\.[0-9]+)?\]:/ {
match($0, /\[([0-9]+\.[0-9]+\.[0-9]+(-(beta-)?java(-preview)?\.[0-9]+)?)\]:/, arr)
if (arr[1] != "" && repo_url != "") {
first_version_link = arr[1]
# Insert Unreleased and new version links before first version link
print "[Unreleased]: " repo_url "/compare/java/v" version "...HEAD"
print "[" version "]: " repo_url "/compare/java/v" arr[1] "...java/v" version
}
}

# Print all other lines unchanged
{ print }
' "$CHANGELOG_FILE" > "$TEMP_FILE"

# Replace the original file
mv "$TEMP_FILE" "$CHANGELOG_FILE"

echo "✓ CHANGELOG.md updated successfully"
echo " - Added version ${VERSION} with date ${RELEASE_DATE}"
echo " - Created new [Unreleased] section"
echo " - Updated version comparison links"

Loading