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