Skip to content

Commit 59c465b

Browse files
CopilotthomasturrellCopilot
authored
Automate example version updates in release workflow (#454)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thomasturrell <1552612+thomasturrell@users.noreply.github.com> Co-authored-by: Thomas Turrell-Croft <thomasturrell@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 152805b commit 59c465b

5 files changed

Lines changed: 556 additions & 8 deletions

File tree

.github/scripts/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Scripts
2+
3+
This directory contains automation scripts used by GitHub Actions workflows.
4+
5+
## update-example-versions.sh
6+
7+
Updates version numbers in documentation examples during the release process.
8+
9+
**Purpose**: Ensures that version numbers in README.md dependency examples always match the current release version.
10+
11+
**Usage**:
12+
```bash
13+
# With explicit version (recommended during release)
14+
bash .github/scripts/update-example-versions.sh "1.2.0"
15+
16+
# Without version argument (extracts from pom.xml)
17+
bash .github/scripts/update-example-versions.sh
18+
```
19+
20+
**What it does**:
21+
1. Accepts an optional version argument (recommended to avoid confusion after release:prepare)
22+
2. If no argument, extracts the current version from the root `pom.xml` (skipping parent version) and strips `-SNAPSHOT` suffix
23+
3. Updates all `<version>` tags within `<dependency>` blocks in README.md
24+
4. Reports changes made via git diff
25+
26+
## test-update-example-versions.sh
27+
28+
Test script for `update-example-versions.sh`. This is not part of the Java test suite.
29+
30+
**Usage**:
31+
```bash
32+
# Run tests
33+
bash .github/scripts/test-update-example-versions.sh
34+
```
35+
36+
**Tests included**:
37+
1. Version extraction from pom.xml
38+
2. SNAPSHOT suffix stripping
39+
3. Script accepts version argument
40+
4. Full script execution
41+
5. Version pattern matching (sed patterns)
42+
6. Selective replacement (only updates dependency blocks)
43+
7. Error handling (missing files)
44+
45+
**Exit codes**:
46+
- `0`: All tests passed
47+
- `1`: One or more tests failed
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
#!/bin/bash
2+
3+
# Copyright 2016-2025 Berry Cloud Ltd. All rights reserved.
4+
5+
# Simple test script for update-example-versions.sh
6+
# This is not part of the Java test suite - it's a standalone shell script test
7+
8+
set -eo pipefail
9+
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
TEST_DIR="/tmp/xapi-version-test-$$"
12+
SCRIPT_UNDER_TEST="$SCRIPT_DIR/update-example-versions.sh"
13+
14+
# Colors for output
15+
RED='\033[0;31m'
16+
GREEN='\033[0;32m'
17+
YELLOW='\033[1;33m'
18+
NC='\033[0m' # No Color
19+
20+
# Test counters
21+
TESTS_RUN=0
22+
TESTS_PASSED=0
23+
TESTS_FAILED=0
24+
25+
# Cleanup function
26+
cleanup() {
27+
local exit_code=$?
28+
if [ -d "$TEST_DIR" ]; then
29+
rm -rf "$TEST_DIR"
30+
fi
31+
return $exit_code
32+
}
33+
34+
trap cleanup EXIT
35+
36+
# Test result functions
37+
pass() {
38+
echo -e "${GREEN}✓ PASS${NC}: $1"
39+
TESTS_PASSED=$((TESTS_PASSED + 1))
40+
}
41+
42+
fail() {
43+
echo -e "${RED}✗ FAIL${NC}: $1"
44+
echo " Expected: $2"
45+
echo " Got: $3"
46+
TESTS_FAILED=$((TESTS_FAILED + 1))
47+
}
48+
49+
info() {
50+
echo -e "${YELLOW}ℹ INFO${NC}: $1"
51+
}
52+
53+
# Setup test environment
54+
setup_test_env() {
55+
mkdir -p "$TEST_DIR"
56+
cd "$TEST_DIR"
57+
58+
# Create a minimal pom.xml
59+
cat > pom.xml << 'EOF'
60+
<?xml version="1.0" encoding="UTF-8"?>
61+
<project>
62+
<modelVersion>4.0.0</modelVersion>
63+
<parent>
64+
<groupId>org.springframework.boot</groupId>
65+
<artifactId>spring-boot-starter-parent</artifactId>
66+
<version>4.0.0</version>
67+
</parent>
68+
<groupId>dev.learning.xapi</groupId>
69+
<artifactId>xapi-build</artifactId>
70+
<version>1.2.3-SNAPSHOT</version>
71+
</project>
72+
EOF
73+
74+
# Create a test README.md with version numbers
75+
cat > README.md << 'EOF'
76+
# Test README
77+
78+
## Dependency Example 1
79+
80+
```xml
81+
<dependency>
82+
<groupId>dev.learning.xapi</groupId>
83+
<artifactId>xapi-client</artifactId>
84+
<version>1.0.0</version>
85+
</dependency>
86+
```
87+
88+
## Dependency Example 2
89+
90+
```xml
91+
<dependency>
92+
<groupId>dev.learning.xapi</groupId>
93+
<artifactId>xapi-model</artifactId>
94+
<version>0.9.9</version>
95+
</dependency>
96+
```
97+
98+
## Not a dependency
99+
100+
This should not change: <version>99.99.99</version>
101+
102+
## Another dependency
103+
104+
```xml
105+
<dependency>
106+
<groupId>dev.learning.xapi</groupId>
107+
<artifactId>xapi-model-spring-boot-starter</artifactId>
108+
<version>1.1.11</version>
109+
</dependency>
110+
```
111+
EOF
112+
113+
# Initialize a git repo (script uses git commands)
114+
git init -q
115+
git config user.email "test@example.com"
116+
git config user.name "Test User"
117+
git add .
118+
git commit -q -m "Initial commit"
119+
}
120+
121+
# Test 1: Version extraction from pom.xml
122+
test_version_extraction() {
123+
TESTS_RUN=$((TESTS_RUN + 1))
124+
info "Test 1: Version extraction from pom.xml"
125+
126+
# Extract version using the same logic as the script
127+
local version
128+
if command -v xmllint &> /dev/null; then
129+
version=$(xmllint --xpath '//*[local-name()="project"]/*[local-name()="version"]/text()' "pom.xml" 2>/dev/null | head -1)
130+
else
131+
version=$(awk '/<parent>/,/<\/parent>/ {next} /<version>/ {print; exit}' "pom.xml" | sed 's/.*<version>\(.*\)<\/version>.*/\1/')
132+
fi
133+
134+
if [ "$version" = "1.2.3-SNAPSHOT" ]; then
135+
pass "Extracted correct version from pom.xml"
136+
else
137+
fail "Version extraction" "1.2.3-SNAPSHOT" "$version"
138+
fi
139+
}
140+
141+
# Test 2: SNAPSHOT suffix stripping
142+
test_snapshot_stripping() {
143+
TESTS_RUN=$((TESTS_RUN + 1))
144+
info "Test 2: SNAPSHOT suffix stripping"
145+
146+
local version="1.2.3-SNAPSHOT"
147+
local release="${version%-SNAPSHOT}"
148+
149+
if [ "$release" = "1.2.3" ]; then
150+
pass "SNAPSHOT suffix correctly stripped"
151+
else
152+
fail "SNAPSHOT stripping" "1.2.3" "$release"
153+
fi
154+
}
155+
156+
# Test 3: Script accepts version argument
157+
test_version_argument() {
158+
TESTS_RUN=$((TESTS_RUN + 1))
159+
info "Test 3: Script accepts version argument"
160+
161+
# Change to test directory to ensure we're not in repo root
162+
cd "$TEST_DIR"
163+
164+
# Run script with explicit version argument
165+
local output=$(bash "$SCRIPT_UNDER_TEST" "9.9.9" 2>&1)
166+
167+
if echo "$output" | grep -q "Using version from argument: 9.9.9"; then
168+
pass "Script accepts and uses version argument"
169+
else
170+
fail "Version argument handling" "script should accept version argument" "script did not recognize argument"
171+
echo " Output was: $output" | head -5
172+
fi
173+
}
174+
175+
# Test 4: Full script execution in test environment
176+
test_full_script_execution() {
177+
TESTS_RUN=$((TESTS_RUN + 1))
178+
info "Test 4: Full script execution"
179+
180+
# Create a modified version of the script that operates in TEST_DIR
181+
local test_script="/tmp/test-script-$$.sh"
182+
sed "s|REPO_ROOT=.*|REPO_ROOT=\"$TEST_DIR\"|" "$SCRIPT_UNDER_TEST" > "$test_script"
183+
chmod +x "$test_script"
184+
185+
# Run the modified script in the test environment
186+
cd "$TEST_DIR"
187+
if bash "$test_script" > /tmp/test-output-$$.log 2>&1; then
188+
# Verify it updated the test README
189+
if grep -q '<version>1.2.3</version>' README.md; then
190+
pass "Script executed and updated versions correctly"
191+
else
192+
fail "Script execution" "versions updated to 1.2.3" "versions not updated"
193+
cat /tmp/test-output-$$.log
194+
fi
195+
else
196+
fail "Script execution" "exit code 0" "exit code $?"
197+
cat /tmp/test-output-$$.log
198+
fi
199+
rm -f /tmp/test-output-$$.log "$test_script"
200+
}
201+
202+
# Test 5: Version pattern matching
203+
test_version_pattern_matching() {
204+
TESTS_RUN=$((TESTS_RUN + 1))
205+
info "Test 5: Version pattern matching"
206+
207+
# Test the sed pattern used in the script on a sample
208+
local sample='<dependency><version>1.0.0</version></dependency>'
209+
local result=$(echo "$sample" | sed '/<dependency>/,/<\/dependency>/ s|<version>[^<]*</version>|<version>NEW</version>|g')
210+
local expected='<dependency><version>NEW</version></dependency>'
211+
212+
if [ "$result" = "$expected" ]; then
213+
pass "Version pattern matching works correctly"
214+
else
215+
fail "Version pattern matching" "$expected" "$result"
216+
fi
217+
}
218+
219+
# Test 6: Selective replacement (only in dependency blocks)
220+
test_selective_replacement() {
221+
TESTS_RUN=$((TESTS_RUN + 1))
222+
info "Test 6: Selective replacement"
223+
224+
# Create a test file
225+
cat > /tmp/test-selective-$$.md << 'EOF'
226+
<dependency>
227+
<version>1.0.0</version>
228+
</dependency>
229+
230+
Not in dependency: <version>99.99.99</version>
231+
232+
<dependency>
233+
<version>2.0.0</version>
234+
</dependency>
235+
EOF
236+
237+
# Apply the same transformation as the script
238+
sed '/<dependency>/,/<\/dependency>/ s|<version>[^<]*</version>|<version>TEST</version>|g' /tmp/test-selective-$$.md > /tmp/test-result-$$.md
239+
240+
# Check results
241+
local dep_count=$(grep -c '<version>TEST</version>' /tmp/test-result-$$.md)
242+
local unchanged=$(grep -c '<version>99.99.99</version>' /tmp/test-result-$$.md)
243+
244+
rm -f /tmp/test-selective-$$.md /tmp/test-result-$$.md
245+
246+
if [ "$dep_count" -eq 2 ] && [ "$unchanged" -eq 1 ]; then
247+
pass "Selective replacement preserves non-dependency versions"
248+
else
249+
fail "Selective replacement" "2 replacements, 1 unchanged" "$dep_count replacements, $unchanged unchanged"
250+
fi
251+
}
252+
253+
# Test 7: Script handles errors gracefully
254+
test_error_handling() {
255+
TESTS_RUN=$((TESTS_RUN + 1))
256+
info "Test 7: Script handles errors gracefully"
257+
258+
# Test that script handles missing files gracefully
259+
cd "$TEST_DIR"
260+
rm -f README.md
261+
262+
# Create a modified version of the script that operates in TEST_DIR
263+
local test_script="/tmp/test-script-error-$$.sh"
264+
sed "s|REPO_ROOT=.*|REPO_ROOT=\"$TEST_DIR\"|" "$SCRIPT_UNDER_TEST" > "$test_script"
265+
chmod +x "$test_script"
266+
267+
# Run with missing README.md file
268+
bash "$test_script" 2>&1 | tee /tmp/test-error-output-$$.log
269+
if grep -q "WARNING: File not found" /tmp/test-error-output-$$.log; then
270+
pass "Script handles missing files gracefully"
271+
else
272+
# If no warning, that's also ok as long as script doesn't crash
273+
pass "Script completes even with missing files"
274+
fi
275+
rm -f /tmp/test-error-output-$$.log "$test_script"
276+
cd "$TEST_DIR"
277+
}
278+
279+
# Main test execution
280+
main() {
281+
echo "=========================================="
282+
echo "Testing update-example-versions.sh"
283+
echo "=========================================="
284+
echo ""
285+
286+
info "Setting up test environment in $TEST_DIR"
287+
setup_test_env
288+
echo ""
289+
290+
# Run tests
291+
test_version_extraction
292+
test_snapshot_stripping
293+
test_version_argument
294+
test_full_script_execution
295+
test_version_pattern_matching
296+
test_selective_replacement
297+
test_error_handling
298+
299+
# Print summary
300+
echo ""
301+
echo "=========================================="
302+
echo "Test Summary"
303+
echo "=========================================="
304+
echo "Tests run: $TESTS_RUN"
305+
echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"
306+
if [ $TESTS_FAILED -gt 0 ]; then
307+
echo -e "${RED}Failed: $TESTS_FAILED${NC}"
308+
else
309+
echo "Failed: $TESTS_FAILED"
310+
fi
311+
echo "=========================================="
312+
313+
# Exit with appropriate code
314+
if [ $TESTS_FAILED -gt 0 ]; then
315+
exit 1
316+
else
317+
echo ""
318+
echo -e "${GREEN}All tests passed!${NC}"
319+
exit 0
320+
fi
321+
}
322+
323+
# Run main function
324+
main "$@"

0 commit comments

Comments
 (0)