...
1#!/usr/bin/env bash
2
3# Copyright 2020 The Kubernetes Authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17set -o errexit
18set -o nounset
19set -o pipefail
20
21function usage {
22 local script="$(basename $0)"
23
24 echo >&2 "Usage: ${script} [-r <branch|tag> | -d <dir>]
25
26This script should be run at the root of a module.
27
28-r <branch|tag>
29 Compare the exported API of the local working copy with the
30 exported API of the local repo at the specified branch or tag.
31
32-d <dir>
33 Compare the exported API of the local working copy with the
34 exported API of the specified directory, which should point
35 to the root of a different version of the same module.
36
37Examples:
38 ${script} -r master
39 ${script} -r v1.10.0
40 ${script} -r release-1.10
41 ${script} -d /path/to/historical/version
42"
43 exit 1
44}
45
46ref=""
47dir=""
48while getopts r:d: o
49do case "$o" in
50 r) ref="$OPTARG";;
51 d) dir="$OPTARG";;
52 [?]) usage;;
53 esac
54done
55
56# If REF and DIR are empty, print usage and error
57if [[ -z "${ref}" && -z "${dir}" ]]; then
58 usage;
59fi
60# If REF and DIR are both set, print usage and error
61if [[ -n "${ref}" && -n "${dir}" ]]; then
62 usage;
63fi
64
65if ! which apidiff > /dev/null; then
66 echo "Installing golang.org/x/exp/cmd/apidiff..."
67 pushd "${TMPDIR:-/tmp}" > /dev/null
68 go install golang.org/x/exp/cmd/apidiff@latest
69 popd > /dev/null
70fi
71
72output=$(mktemp -d -t "apidiff.output.XXXX")
73cleanup_output () { rm -fr "${output}"; }
74trap cleanup_output EXIT
75
76# If ref is set, clone . to temp dir at $ref, and set $dir to the temp dir
77clone=""
78base="${dir}"
79if [[ -n "${ref}" ]]; then
80 base="${ref}"
81 clone=$(mktemp -d -t "apidiff.clone.XXXX")
82 cleanup_clone_and_output () { rm -fr "${clone}"; cleanup_output; }
83 trap cleanup_clone_and_output EXIT
84 git clone . -q --no-tags -b "${ref}" "${clone}"
85 dir="${clone}"
86fi
87
88pushd "${dir}" >/dev/null
89 echo "Inspecting API of ${base}..."
90 go list ./... > packages.txt
91 for pkg in $(cat packages.txt); do
92 mkdir -p "${output}/${pkg}"
93 apidiff -w "${output}/${pkg}/apidiff.output" "${pkg}"
94 done
95popd >/dev/null
96
97retval=0
98
99echo "Comparing with ${base}..."
100for pkg in $(go list ./...); do
101 # New packages are ok
102 if [ ! -f "${output}/${pkg}/apidiff.output" ]; then
103 continue
104 fi
105
106 # Check for incompatible changes to previous packages
107 incompatible=$(apidiff -incompatible "${output}/${pkg}/apidiff.output" "${pkg}")
108 if [[ -n "${incompatible}" ]]; then
109 echo >&2 "FAIL: ${pkg} contains incompatible changes:
110${incompatible}
111"
112 retval=1
113 fi
114done
115
116# Check for removed packages
117removed=$(comm -23 "${dir}/packages.txt" <(go list ./...))
118if [[ -n "${removed}" ]]; then
119 echo >&2 "FAIL: removed packages:
120${removed}
121"
122 retval=1
123fi
124
125exit $retval
View as plain text