blob: 01772c55ed77028621506490bcbc2f08ff3c38b8 [file] [log] [blame]
Zack Williams12783ac2018-06-12 15:13:12 -07001#!/usr/bin/env bash
2
3# Copyright 2018-present Open Networking Foundation
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
17# tagcollisionreject.sh
18# checks that there isn't an existing tag in the repo that has this tag
19
20set -eu -o pipefail
21
Zack Williams8e69efd2018-06-13 15:05:18 -070022VERSIONFILE="" # file path to file containing version number
23NEW_VERSION="" # version number found in $VERSIONFILE
Zack Williams6e070f52019-10-04 11:08:59 -070024TAG_VERSION="" # version file that might have a leading v to work around go mod funkyness
Zack Williams8e69efd2018-06-13 15:05:18 -070025
Zack Williams66500002018-09-06 15:29:05 -070026SEMVER_STRICT=${SEMVER_STRICT:-0} # require semver versions
27
Zack Williams8e69efd2018-06-13 15:05:18 -070028releaseversion=0
29fail_validation=0
30
31# when not running under Jenkins, use current dir as workspace
32WORKSPACE=${WORKSPACE:-.}
Zack Williams12783ac2018-06-12 15:13:12 -070033
34# find the version string in the repo, read into NEW_VERSION
35# Add additional places NEW_VERSION could be found to this function
36function read_version {
37 if [ -f "VERSION" ]
38 then
39 NEW_VERSION=$(head -n1 "VERSION")
Zack Williams8e69efd2018-06-13 15:05:18 -070040 VERSIONFILE="VERSION"
Zack Williams6e070f52019-10-04 11:08:59 -070041
42 # If this is a golang project, use funky v-prefixed versions
43 if [ -f "Gopkg.toml" ] || [ -f "go.mod" ]
44 then
45 echo "go-based project found, using v-prefixed version for git tags: v${NEW_VERSION}"
46 TAG_VERSION=v${NEW_VERSION}
47 else
48 TAG_VERSION=${NEW_VERSION}
49 fi
50
Zack Williams6a9d2e62018-06-22 15:18:23 -070051 elif [ -f "package.json" ]
52 then
53 NEW_VERSION=$(python -c 'import json,sys;obj=json.load(sys.stdin); print obj["version"]' < package.json)
Zack Williams6e070f52019-10-04 11:08:59 -070054 TAG_VERSION=$NEW_VERSION
Zack Williams6a9d2e62018-06-22 15:18:23 -070055 VERSIONFILE="package.json"
Zack Williams866ef3c2019-09-27 15:41:02 -070056 elif [ -f "pom.xml" ]
57 then
58 NEW_VERSION=$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml)
Zack Williams6e070f52019-10-04 11:08:59 -070059 TAG_VERSION=$NEW_VERSION
Zack Williams866ef3c2019-09-27 15:41:02 -070060 VERSIONFILE="pom.xml"
Zack Williams12783ac2018-06-12 15:13:12 -070061 else
62 echo "ERROR: No versioning file found!"
Matteo Scandolo93b531d2021-03-22 14:36:48 -070063 fail_validation=1
Zack Williams12783ac2018-06-12 15:13:12 -070064 fi
65}
66
Zack Williams8e69efd2018-06-13 15:05:18 -070067# check if the version is a released version
68function check_if_releaseversion {
69 if [[ "$NEW_VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]
70 then
71 echo "Version string '$NEW_VERSION' found in '$VERSIONFILE' is a SemVer released version!"
72 releaseversion=1
73 else
Zack Williams66500002018-09-06 15:29:05 -070074 if [ "$SEMVER_STRICT" -eq "1" ]
75 then
76 echo "Version string '$NEW_VERSION' in '$VERSIONFILE' is not a SemVer released version, SEMVER_STRICT enabled, failing!"
77 fail_validation=1
78 else
79 echo "Version string '$NEW_VERSION' in '$VERSIONFILE' is not a SemVer released version, skipping."
80 fi
Zack Williams8e69efd2018-06-13 15:05:18 -070081 fi
82}
83
Zack Williams6e070f52019-10-04 11:08:59 -070084# check if the version is already a tag in git
85function is_git_tag_duplicated {
Matteo Scandoloe0890432021-04-06 06:37:21 -070086 for existing_tag in $existing_tags
Zack Williams6e070f52019-10-04 11:08:59 -070087 do
88 if [ "$TAG_VERSION" = "$existing_tag" ]
89 then
90 echo "ERROR: Duplicate tag: $existing_tag"
Matteo Scandolo93b531d2021-03-22 14:36:48 -070091 fail_validation=2
Zack Williams6e070f52019-10-04 11:08:59 -070092 fi
Matteo Scandoloe0890432021-04-06 06:37:21 -070093 done
Matteo Scandolo93b531d2021-03-22 14:36:48 -070094}
95
96# from https://github.com/cloudflare/semver_bash/blob/master/semver.sh
97function semverParseInto() {
98 local RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)'
99 #MAJOR
100 eval $2=`echo $1 | sed -e "s#$RE#\1#"`
101 #MINOR
102 eval $3=`echo $1 | sed -e "s#$RE#\2#"`
103 #MINOR
104 eval $4=`echo $1 | sed -e "s#$RE#\3#"`
105 #SPECIAL
106 eval $5=`echo $1 | sed -e "s#$RE#\4#"`
107}
108
109# if it's a -dev version check if a previous tag has been created (to avoid going from 2.7.0-dev to 2.7.1-dev)
110function is_valid_version {
111 local MAJOR=0 MINOR=0 PATCH=0 SPECIAL=""
112 local C_MAJOR=0 C_MINOR=0 C_PATCH=0 C_SPECIAL="" # these are used in the inner loops to compare
113
114 semverParseInto $NEW_VERSION MAJOR MINOR PATCH SPECIAL
115
116 found_parent=false
117
118 # if minor == 0, check that there was a release with MAJOR-1.X.X
119 if [[ "$MINOR" == 0 ]]; then
120 new_major=$(( $MAJOR - 1 ))
121 parent_version="$new_major.x.x"
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700122 for existing_tag in $existing_tags
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700123 do
124 semverParseInto $existing_tag C_MAJOR C_MINOR C_PATCH C_SPECIAL
125 if [[ "$new_major" == "$C_MAJOR" ]]; then
126 found_parent=true
127 fi
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700128 done
Matteo Scandolo9725cdb2021-06-03 09:03:43 -0700129 fi
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700130
131 # if patch == 0, check that there was a release with MAJOR.MINOR-1.X
Matteo Scandolo9725cdb2021-06-03 09:03:43 -0700132 if [[ "$PATCH" == 0 ]]; then
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700133 new_minor=$(( $MINOR - 1 ))
134 parent_version="$MAJOR.$new_minor.x"
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700135 for existing_tag in $existing_tags
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700136 do
137 semverParseInto $existing_tag C_MAJOR C_MINOR C_PATCH C_SPECIAL
138 if [[ "$new_minor" == "$C_MINOR" ]]; then
139 found_parent=true
140 fi
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700141 done
Matteo Scandolo9725cdb2021-06-03 09:03:43 -0700142 fi
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700143
144 # if patch != 0 check that there was a release with MAJOR.MINOR.PATCH-1
Matteo Scandolo9725cdb2021-06-03 09:03:43 -0700145 if [[ "$PATCH" != 0 ]]; then
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700146 new_patch=$(( $PATCH - 1 ))
147 parent_version="$MAJOR.$MINOR.$new_patch"
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700148 for existing_tag in $existing_tags
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700149 do
Matteo Scandoloacccab42021-04-01 12:05:04 -0700150 semverParseInto $existing_tag C_MAJOR C_MINOR C_PATCH C_SPECIAL
151 if [[ "$MAJOR" == "$C_MAJOR" && "$MINOR" == "$C_MINOR" && "$new_patch" == "$C_PATCH" ]]
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700152 then
153 found_parent=true
154 fi
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700155 done
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700156 fi
157
158 # if we are the beginning the is no parent, but that's fine
159 if [[ "$MAJOR" == 0 ]]; then
160 found_parent=true
161 fi
162
163 if [[ $found_parent == false ]]; then
164 echo "Invalid $NEW_VERSION version. Expected parent version $parent_version does not exist."
165 fail_validation=1
166 fi
Zack Williams6e070f52019-10-04 11:08:59 -0700167}
168
Zack Williams8e69efd2018-06-13 15:05:18 -0700169# check if Dockerfiles have a released version as their parent
170function dockerfile_parentcheck {
171 while IFS= read -r -d '' dockerfile
172 do
173 echo "Checking dockerfile: '$dockerfile'"
174
175 # split on newlines
176 IFS=$'\n'
177 df_parents=($(grep "^FROM" "$dockerfile"))
178
179 # check all parents in the Dockerfile
180 for df_parent in "${df_parents[@]}"
181 do
182
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700183 df_pattern="[FfRrOoMm] +(--platform=[^ ]+ +)?([^@: ]+)(:([^: ]+)|@sha[^ ]+)?"
Zack Williams8e69efd2018-06-13 15:05:18 -0700184 if [[ "$df_parent" =~ $df_pattern ]]
185 then
186
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700187 p_image="${BASH_REMATCH[2]}"
188 p_sha=${BASH_REMATCH[3]}
189 p_version="${BASH_REMATCH[4]}"
Zack Williams8e69efd2018-06-13 15:05:18 -0700190
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700191 echo "IMAGE: '${p_image}'"
192 echo "VERSION: '$p_version'"
193 echo "SHA: '$p_sha'"
194
195 if [[ "${p_image}" == "scratch" ]]
196 then
197 echo " OK: Using the versionless 'scratch' parent: '$df_parent'"
198 elif [[ "${p_image}:${p_version}" == "gcr.io/distroless/static:nonroot" ]]
199 then
200 echo " OK: Using static distroless image with nonroot: '${p_image}:${p_version}'"
201 elif [[ "${p_version}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]
Zack Williams8e69efd2018-06-13 15:05:18 -0700202 then
203 echo " OK: Parent '$p_image:$p_version' is a released SemVer version"
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700204 elif [[ "${p_sha}" =~ ^@sha256:[0-9a-f]{64}.*$ ]]
Zack Williamsc800dbe2020-02-14 10:25:12 -0700205 then
206 # allow sha256 hashes to be used as version specifiers
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700207 echo " OK: Parent '$p_image$p_sha' is using a specific sha256 hash as a version"
Zack Williams0dc27542018-10-11 08:09:10 -0700208 elif [[ "${p_version}" =~ ^.*([0-9]+)\.([0-9]+).*$ ]]
Zack Williams8e69efd2018-06-13 15:05:18 -0700209 then
Zack Williams0dc27542018-10-11 08:09:10 -0700210 # handle non-SemVer versions that have a Major.Minor version specifier in the name
211 # 'ubuntu:16.04'
212 # 'postgres:10.3-alpine'
213 # 'openjdk:8-jre-alpine3.8'
Zack Williams8e69efd2018-06-13 15:05:18 -0700214 echo " OK: Parent '$p_image:$p_version' is using a non-SemVer, but sufficient, version"
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700215 elif [[ -z "${p_version}" ]]
216 then
217 echo " ERROR: Parent '$p_image' is NOT using a specific version"
218 fail_validation=1
Zack Williams8e69efd2018-06-13 15:05:18 -0700219 else
Matteo Scandoloc3aaa032021-04-07 10:33:40 -0700220 echo " ERROR: Parent '$p_image:$p_version' is NOT using a specific version"
Zack Williams8e69efd2018-06-13 15:05:18 -0700221 fail_validation=1
222 fi
223
Zack Williams8e69efd2018-06-13 15:05:18 -0700224 else
225 echo " ERROR: Couldn't find a parent image in $df_parent"
226 fi
227
228 done
229
Matteo Scandolob28a02e2019-11-04 09:35:16 -0800230 done < <( find "${WORKSPACE}" -name 'Dockerfile*' ! -path "*/vendor/*" ! -name "*dockerignore" -print0 )
Zack Williams8e69efd2018-06-13 15:05:18 -0700231}
232
Zack Williams12783ac2018-06-12 15:13:12 -0700233echo "Checking git repo with remotes:"
234git remote -v
235
236echo "Branches:"
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700237branches=$(git branch -v)
238echo $branches
Zack Williams12783ac2018-06-12 15:13:12 -0700239
240echo "Existing git tags:"
Matteo Scandolo3e89c072021-04-01 09:36:26 -0700241existing_tags=$(git tag -l)
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700242echo $existing_tags
Zack Williams12783ac2018-06-12 15:13:12 -0700243
244read_version
Matteo Scandolo93b531d2021-03-22 14:36:48 -0700245is_valid_version
Zack Williams8e69efd2018-06-13 15:05:18 -0700246check_if_releaseversion
Zack Williams12783ac2018-06-12 15:13:12 -0700247
Zack Williams8e69efd2018-06-13 15:05:18 -0700248# perform checks if a released version
249if [ "$releaseversion" -eq "1" ]
250then
251 is_git_tag_duplicated
252 dockerfile_parentcheck
253fi
Zack Williams12783ac2018-06-12 15:13:12 -0700254
Zack Williams8e69efd2018-06-13 15:05:18 -0700255exit $fail_validation