blob: dcfa75608baef0751ac9377a78ad1908f924e2af [file] [log] [blame]
Zack Williamsbe542312022-06-23 21:51:32 -07001#!/usr/bin/env bash
2
3# Copyright 2018-2022 Networking Foundation
4#
5# SPDX-License-Identifier: Apache-2.0
6
7# version-tag.sh
8# Tags a git commit with the SemVer version discovered within the commit,
9# if the tag doesn't already exist. Ignore non-SemVer commits.
10
11set -eu -o pipefail
12
13VERSIONFILE="" # file path to file containing version number
14NEW_VERSION="" # version number found in $VERSIONFILE
15TAG_VERSION="" # version file that might have a leading v to work around go mod funkyness
16
17SEMVER_STRICT=${SEMVER_STRICT:-0} # require semver versions
18DOCKERPARENT_STRICT=${DOCKERPARENT_STRICT:-1} # require semver versions on parent images in dockerfiles
19
20releaseversion=0
21fail_validation=0
22
23# when not running under Jenkins, use current dir as workspace
24WORKSPACE=${WORKSPACE:-.}
25
26# find the version string in the repo, read into NEW_VERSION
27# Add additional places NEW_VERSION could be found to this function
28function read_version {
29 if [ -f "VERSION" ]
30 then
31 NEW_VERSION=$(head -n1 "VERSION")
32 VERSIONFILE="VERSION"
33
34 # If this is a golang project, use funky v-prefixed versions
35 if [ -f "Gopkg.toml" ] || [ -f "go.mod" ]
36 then
37 echo "go-based project found, using v-prefixed version for git tags: v${NEW_VERSION}"
38 TAG_VERSION=v${NEW_VERSION}
39 else
40 TAG_VERSION=${NEW_VERSION}
41 fi
42
43 elif [ -f "package.json" ]
44 then
45 NEW_VERSION=$(python -c 'import json,sys;obj=json.load(sys.stdin); print obj["version"]' < package.json)
46 TAG_VERSION=$NEW_VERSION
47 VERSIONFILE="package.json"
48 elif [ -f "pom.xml" ]
49 then
50 NEW_VERSION=$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml)
51 TAG_VERSION=$NEW_VERSION
52 VERSIONFILE="pom.xml"
53 else
54 echo "ERROR: No versioning file found!"
55 exit 1
56 fi
57}
58
59# check if the version is a released version
60function check_if_releaseversion {
61 if [[ "$NEW_VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]
62 then
63 echo "Version string '$NEW_VERSION' in '$VERSIONFILE' is a SemVer released version!"
64 releaseversion=1
65 else
66 if [ "$SEMVER_STRICT" -eq "1" ]
67 then
68 echo "Version string '$NEW_VERSION' in '$VERSIONFILE' is not a SemVer released version, SEMVER_STRICT enabled, failing!"
69 fail_validation=1
70 else
71 echo "Version string '$NEW_VERSION' in '$VERSIONFILE' is not a SemVer released version, skipping."
72 fi
73 fi
74}
75
76# check if the version is already a tag in git
77function is_git_tag_duplicated {
78 for existing_tag in $(git tag)
79 do
80 if [ "$TAG_VERSION" = "$existing_tag" ]
81 then
82 echo "ERROR: Duplicate tag: $existing_tag"
83 exit 2
84 fi
85 done
86}
87
88# check if Dockerfiles have a released version as their parent
89function dockerfile_parentcheck {
90 if [ "$DOCKERPARENT_STRICT" -eq "0" ];
91 then
92 echo "DOCKERPARENT_STRICT is disabled - skipping parent checks"
93 else
94 while IFS= read -r -d '' dockerfile
95 do
96 echo "Checking dockerfile: '$dockerfile'"
97
98 # split on newlines
99 IFS=$'\n'
100 df_parents=($(grep "^FROM" "$dockerfile"))
101
102 # check all parents in the Dockerfile
103 for df_parent in "${df_parents[@]}"
104 do
105
106 df_pattern="[FfRrOoMm] +(--platform=[^ ]+ +)?([^@: ]+)(:([^: ]+)|@sha[^ ]+)?"
107 if [[ "$df_parent" =~ $df_pattern ]]
108 then
109
110 p_image="${BASH_REMATCH[2]}"
111 p_sha=${BASH_REMATCH[3]}
112 p_version="${BASH_REMATCH[4]}"
113
114 echo "IMAGE: '${p_image}'"
115 echo "VERSION: '$p_version'"
116 echo "SHA: '$p_sha'"
117
118 if [[ "${p_image}" == "scratch" ]]
119 then
120 echo " OK: Using the versionless 'scratch' parent: '$df_parent'"
121 elif [[ "${p_image}:${p_version}" == "gcr.io/distroless/static:nonroot" ]]
122 then
123 echo " OK: Using static distroless image with nonroot: '${p_image}:${p_version}'"
124 elif [[ "${p_version}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]
125 then
126 echo " OK: Parent '$p_image:$p_version' is a released SemVer version"
127 elif [[ "${p_sha}" =~ ^@sha256:[0-9a-f]{64}.*$ ]]
128 then
129 # allow sha256 hashes to be used as version specifiers
130 echo " OK: Parent '$p_image$p_sha' is using a specific sha256 hash as a version"
131 elif [[ "${p_version}" =~ ^.*([0-9]+)\.([0-9]+).*$ ]]
132 then
133 # handle non-SemVer versions that have a Major.Minor version specifier in the name
134 # 'ubuntu:16.04'
135 # 'postgres:10.3-alpine'
136 # 'openjdk:8-jre-alpine3.8'
137 echo " OK: Parent '$p_image:$p_version' is using a non-SemVer, but sufficient, version"
138 elif [[ -z "${p_version}" ]]
139 then
140 echo " ERROR: Parent '$p_image' is NOT using a specific version"
141 fail_validation=1
142 else
143 echo " ERROR: Parent '$p_image:$p_version' is NOT using a specific version"
144 fail_validation=1
145 fi
146
147 else
148 echo " ERROR: Couldn't find a parent image in $df_parent"
149 fi
150
151 done
152
153 done < <( find "${WORKSPACE}" -name 'Dockerfile*' ! -path "*/vendor/*" ! -name "*dockerignore" -print0 )
154 fi
155}
156
157# create a git tag
158function create_git_tag {
159 echo "Creating git tag: $TAG_VERSION"
160 git checkout "$GERRIT_PATCHSET_REVISION"
161
162 git config --global user.email "do-not-reply@opennetworking.org"
163 git config --global user.name "Jenkins"
164
165 git tag -a "$TAG_VERSION" -m "Tagged by CORD Jenkins version-tag job: $BUILD_NUMBER, for Gerrit patchset: $GERRIT_CHANGE_NUMBER"
166
167 echo "Tags including new tag:"
168 git tag -n
169
170 git push origin "$TAG_VERSION"
171}
172
173echo "Checking git repo with remotes:"
174git remote -v
175
176echo "Branches:"
177git branch -v
178
179echo "Existing git tags:"
180git tag -n
181
182read_version
183check_if_releaseversion
184
185# perform checks if a released version
186if [ "$releaseversion" -eq "1" ]
187then
188 is_git_tag_duplicated
189 dockerfile_parentcheck
190
191 if [ "$fail_validation" -eq "0" ]
192 then
193 create_git_tag
194 else
195 echo "ERROR: commit merged but failed validation, not tagging!"
196 fi
197fi
198
199exit $fail_validation