summaryrefslogtreecommitdiff
path: root/hack/make-and-check-size
blob: a6a77e8ca867874e31aa67dd8feb19a6eb09b841 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/bin/bash
#
# make-and-check-size - wrapper around 'make' that also checks binary growth
#
# This script is intended to be run via 'git rebase -x', in a Makefile rule
# such as:
#
#    build-all-new-commits:
#       CONTEXT_DIR=$(shell mktemp -d --tmpdir make-size-check.XXXXXXX); \
#       git rebase $(GIT_BASE_BRANCH)^ -x "hack/make-and-check-size $$CONTEXT_DIR"; \
#       $(RM) -rf $$CONTEXT_DIR
#
# ...which has long been a part of our usual CI, one that makes sure that
# each commit (in a multi-commit PR) can be compiled individually. By
# adding the '^' to GIT_BASE_BRANCH we establish a baseline and store
# the binary sizes of each file (podman, podman-remote) prior to our PR.
#
# CONTEXT_DIR is a temporary directory used to store the original sizes
# of each binary file under bin/
#
# *IMPORTANT NOTE*: this script will leave the git checkout in a funky state!
# (because we rebase onto a nonterminal commit). I believe this is OK, since
# this makefile target is used only in CI and only in a scratch VM. Running
# this in a development environment would yield unpredictable results anyway,
# by rebasing onto origin/main by default and by leaving an aborted rebase
# on failure.
#
ME=$(basename $0)

###############################################################################
# BEGIN end-user-customizable settings

# Maximum allowable size, in bytes
MAX_BIN_GROWTH=$((50 * 1024))

# Github label which allows overriding this check
OVERRIDE_LABEL=bloat_approved

# END   end-user-customizable settings
###############################################################################

#
# Helper function: queries github for labels on this PR
#
function bloat_approved() {
    # Argument is the actual size increase in this build.
    # FIXME: 2022-03-21: this is not actually used atm, but Ed hopes some day
    #        to implement a more robust size-override mechanism, such as by
    #        requiring a MAX_BIN_GROWTH=nnn statement in github comments.
    local actual_growth="$1"

    if [[ -z "$CIRRUS_PR" ]]; then
        echo "$ME: cannot query github: \$CIRRUS_PR is undefined" >&2
        return 1
    fi
    if [[ -z "$CIRRUS_REPO_CLONE_TOKEN" ]]; then
        echo "$ME: cannot query github: \$CIRRUS_REPO_CLONE_TOKEN is undefined" >&2
        return 1
    fi

    query="{
  \"query\": \"query {
  repository(owner: \\\"containers\\\", name: \\\"podman\\\") {
    pullRequest(number: $CIRRUS_PR) {
      labels(first: 100) {
        nodes {
          name
        }
      }
    }
  }
}\"
}"

    result=$(curl -s -H "Authorization: bearer $CIRRUS_REPO_CLONE_TOKEN" -H "Accept: application/vnd.github.antiope-preview+json" -H "Content-Type: application/json" -X POST --data @- https://api.github.com/graphql <<<"$query")

    labels=$(jq -r '.data.repository.pullRequest.labels.nodes[].name' <<<"$result")

    grep -q -w "$OVERRIDE_LABEL" <<<"$labels"
}

# ACTUAL CODE BEGINS HERE
set -e

# Must be invoked with one argument, an existing context directory
context_dir=${1?Missing CONTEXT-DIR argument}
if [[ ! -d $context_dir ]]; then
    echo "$ME: directory '$context_dir' does not exist"
    exit 1
fi

# This is the original (and primary) purpose of this check: if 'make' fails,
# there is no point in continuing
echo
echo "Building: $(git rev-parse HEAD)"
make

# Determine size of each built file.
# - If this is our first time through, preserve that size in a tmpfile
# - On all subsequent runs, compare built size to initial size
for bin in bin/*;do
    size=$(stat -c %s $bin)

    saved_size_file=$context_dir/$(basename $bin)
    if [[ -e $saved_size_file ]]; then
        # Not the first time through: compare to original size
        size_orig=$(< $saved_size_file)
        delta_size=$(( size - size_orig ))

        if [[ $delta_size -gt $MAX_BIN_GROWTH ]]; then
            separator=$(printf "%.0s*" {1..75})   # row of stars, for highlight
            echo "$separator"
            echo "* $bin grew by $delta_size bytes; max allowed is $MAX_BIN_GROWTH."
            echo "*"
            if bloat_approved $delta_size; then
                echo "* Continuing due to '$OVERRIDE_LABEL' label"
                echo "*"
                echo "$separator"
            else
                echo "* Please investigate, and fix if possible."
                echo "*"
                echo "* A repo admin can override by setting the $OVERRIDE_LABEL label"
                echo "$separator"
                exit 1
            fi
        fi
    else
        # First time through: preserve original file size
        echo $size >$saved_size_file
    fi
done