Skip to content

Commit d3945d6

Browse files
committed
feat: try local apidiff
1 parent bad507a commit d3945d6

File tree

2 files changed

+132
-4
lines changed

2 files changed

+132
-4
lines changed

.github/workflows/api-diff.yml

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,28 @@ on:
33
pull_request:
44

55
jobs:
6-
analyze:
6+
# analyze:
7+
# permissions:
8+
# pull-requests: write
9+
# contents: read
10+
# runs-on: ubuntu-latest
11+
# steps:
12+
# - name: Checkout the repository
13+
# uses: actions/checkout@v4
14+
# with:
15+
# fetch-depth: 0
16+
17+
# - name: Set up Go
18+
# uses: ./.github/actions/setup-go
19+
# with:
20+
# go-version-file: "go.mod"
21+
# only-modules: "true"
22+
23+
# - uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # v0.8.3
24+
# with:
25+
# version: "v0.8.3"
26+
27+
analyze-apidiff:
728
permissions:
829
pull-requests: write
930
contents: read
@@ -20,6 +41,7 @@ jobs:
2041
go-version-file: "go.mod"
2142
only-modules: "true"
2243

23-
- uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # v0.8.3
24-
with:
25-
version: "v0.8.3"
44+
- name: Run script/apidiff.sh
45+
run: |
46+
go install golang.org/x/exp/cmd/apidiff@latest
47+
./script/apidiff.sh

script/apidiff.sh

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# script/apidiff.sh
5+
# Compare API of only modified Go packages between PR HEAD and default branch using apidiff.
6+
# Usage: ./script/apidiff.sh
7+
8+
# Ensure apidiff is installed
9+
if ! command -v apidiff &> /dev/null; then
10+
echo "apidiff not found, installing..."
11+
go install golang.org/x/exp/apidiff@latest
12+
fi
13+
14+
# Locate repository root
15+
repo_root=$(git rev-parse --show-toplevel)
16+
cd "$repo_root"
17+
18+
echo "Repository root: $repo_root"
19+
20+
# Determine default branch
21+
default_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || echo "main")
22+
echo "Default branch: $default_branch"
23+
24+
# Fetch latest origin
25+
git fetch origin "$default_branch"
26+
27+
# Determine modified Go files relative to base
28+
raw_changes=$(git diff --name-only "origin/$default_branch...HEAD" -- '*.go')
29+
if [[ -z "$raw_changes" ]]; then
30+
echo "No modified Go files detected relative to origin/$default_branch. Exiting."
31+
exit 0
32+
fi
33+
34+
# Derive unique directories
35+
readarray -t changed_dirs < <(
36+
printf '%s
37+
' "$raw_changes" |
38+
xargs -n1 dirname |
39+
sort -u
40+
)
41+
42+
echo "Modified directories: ${changed_dirs[*]}"
43+
44+
# Create temporary workspace
45+
tmp_dir=$(mktemp -d)
46+
trap 'rm -rf "$tmp_dir"' EXIT
47+
48+
# Add worktrees for base and head
49+
git worktree add "$tmp_dir/base" "origin/$default_branch"
50+
git worktree add "$tmp_dir/head" HEAD
51+
52+
# Resolve import paths for changed directories
53+
declare -a pkgs
54+
for dir in "${changed_dirs[@]}"; do
55+
pkg_path=$(cd "$tmp_dir/head" && go list "./$dir")
56+
pkgs+=("$pkg_path")
57+
done
58+
# Deduplicate
59+
readarray -t pkgs < <(printf '%s
60+
' "${pkgs[@]}" | sort -u)
61+
62+
echo "Packages to compare: ${pkgs[*]}"
63+
64+
# Prepare export dirs
65+
exports_dir="$tmp_dir/exports"
66+
base_exports="$exports_dir/base"
67+
head_exports="$exports_dir/head"
68+
mkdir -p "$base_exports" "$head_exports"
69+
70+
# Generate exports
71+
generate_pkg_exports() {
72+
local tree=$1 dest=$2
73+
pushd "$tree" > /dev/null
74+
for pkg in "${pkgs[@]}"; do
75+
local file=${pkg//\//_}.export
76+
echo "Exporting $pkg -> $dest/$file"
77+
apidiff -w "$dest/$file" "$pkg"
78+
done
79+
popd > /dev/null
80+
}
81+
82+
generate_pkg_exports "$tmp_dir/base" "$base_exports"
83+
generate_pkg_exports "$tmp_dir/head" "$head_exports"
84+
85+
# Compare exports for breaking changes
86+
echo -e "\nComparing API for breaking changes..."
87+
broken=false
88+
for pkg in "${pkgs[@]}"; do
89+
file=${pkg//\//_}.export
90+
echo -e "\nChecking $pkg"
91+
if ! apidiff "$base_exports/$file" "$head_exports/$file"; then
92+
broken=true
93+
fi
94+
done
95+
96+
# Clean up worktrees
97+
git worktree remove "$tmp_dir/base" --force
98+
git worktree remove "$tmp_dir/head" --force
99+
100+
# Final status
101+
if [[ "$broken" == true ]]; then
102+
echo -e "\nBreaking API changes detected."
103+
exit 1
104+
else
105+
echo -e "\nNo breaking API changes detected."
106+
fi

0 commit comments

Comments
 (0)