Skip to content

Commit be65637

Browse files
gwpantazessimonsto
andcommitted
[#187390534] make deploy prompts if not releasing HEAD of origin main release branch
Co-authored-by: Simon St-Onge <[email protected]>
1 parent 606ddbf commit be65637

6 files changed

+202
-8
lines changed

Gemfile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
source "https://rubygems.org"
4+
5+
group :development do
6+
gem "rubocop"
7+
end

Gemfile.lock

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
GEM
2+
remote: https://rubygems.org/
3+
specs:
4+
ast (2.4.2)
5+
json (2.7.2)
6+
language_server-protocol (3.17.0.3)
7+
parallel (1.24.0)
8+
parser (3.3.0.5)
9+
ast (~> 2.4.1)
10+
racc
11+
racc (1.7.3)
12+
rainbow (3.1.1)
13+
regexp_parser (2.9.0)
14+
rexml (3.2.6)
15+
rubocop (1.63.1)
16+
json (~> 2.3)
17+
language_server-protocol (>= 3.17.0)
18+
parallel (~> 1.10)
19+
parser (>= 3.3.0.2)
20+
rainbow (>= 2.2.2, < 4.0)
21+
regexp_parser (>= 1.8, < 3.0)
22+
rexml (>= 3.2.5, < 4.0)
23+
rubocop-ast (>= 1.31.1, < 2.0)
24+
ruby-progressbar (~> 1.7)
25+
unicode-display_width (>= 2.4.0, < 3.0)
26+
rubocop-ast (1.31.2)
27+
parser (>= 3.3.0.4)
28+
ruby-progressbar (1.13.0)
29+
unicode-display_width (2.5.0)
30+
31+
PLATFORMS
32+
arm64-darwin-22
33+
ruby
34+
35+
DEPENDENCIES
36+
rubocop
37+
38+
BUNDLED WITH
39+
2.5.6

README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# deploy-tools
2+
3+
## Development
4+
5+
Install dependencies.
6+
7+
```shell
8+
bundle install
9+
```
10+
11+
Run rubocop (including on the `.gemspec` file).
12+
13+
```shell
14+
bundle exec rubocop
15+
```
16+
17+
Build the gem. (Example for `v0.2.0`)
18+
19+
```shell
20+
$ gem build deploy-tools.gemspec
21+
WARNING: licenses is empty, but is recommended. Use an license identifier from
22+
https://spdx.org/licenses or 'Nonstandard' for a nonstandard license,
23+
or set it to nil if you don't want to specify a license.
24+
WARNING: See https://guides.rubygems.org/specification-reference/ for help
25+
Successfully built RubyGem
26+
Name: deploy-tools
27+
Version: 0.2.0
28+
File: deploy-tools-0.2.0.gem
29+
```
30+
31+
Create a [release on the Github repo](https://github.com/simplepractice/deploy-tools/releases). Attach the built gem file as a release asset.
32+
33+
## Usage
34+
35+
To see installation and usage of the `deploy-tools` gem, see examples in `Makefile`s in deployable repos.
36+
37+
Example: [simplepractice/simplepractice Makefile L6L16-L20 (ff81396)](https://github.com/simplepractice/simplepractice/blob/ff8139631c546804aae9a9577ee04bc18b21c987/Makefile#L6-L20)
38+
39+
```shell
40+
DEPLOY_TOOLS_VERSION = 0.1.4
41+
# ...
42+
echo "Downloading deploy-tools gem"
43+
wget -O deploy-tools.gem https://github.com/simplepractice/deploy-tools/releases/download/$(DEPLOY_TOOLS_VERSION)/deploy-tools-$(DEPLOY_TOOLS_VERSION).gem
44+
echo "Installing gem"
45+
gem install deploy-tools.gem
46+
rm deploy-tools.gem
47+
```
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env ruby
2+
# Hacky wrapper file to call the corresponding shell script. By default, installed gems run scripts as if they are Ruby,
3+
# and do not respect the shebang line (e.g. a bash shebang). This file is a workaround to call the shell script directly.
4+
# Hack source: https://stackoverflow.com/a/27988355/2291928
5+
6+
system("#{__FILE__}.sh #{ARGV.join(' ')}")
7+
exit $?.exitstatus
+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env bash
2+
# Checks local git state for unusual conditions and prompts the user to confirm before deploying.
3+
#
4+
# This is a safety measure to prevent accidental deployments of unintended target commits.
5+
# The purpose is to draw attention to unusual conditions to be reviewed carefully.
6+
#
7+
# This script is intended to be used as a pre-deploy hook in a deployment script for manual/local deployments.
8+
# It is not intended for automated deployments. Set CI=true to skip.
9+
#
10+
# Releases typically deploy the HEAD of the release branch. The conditions in this script favor that typical case.
11+
# There are valid situations (rollback, hotfix, temporary config changes) which trigger warnings. That's OK/expected.
12+
# In such situations, the user should review carefully and confirm the deployment at their discretion.
13+
#
14+
# Usage: $0 <GIT_REMOTE> <GIT_RELEASE_BRANCH> <REVISION>
15+
# - git_remote: The remote to fetch the release branch from e.g. "origin".
16+
# - git_release_branch: The release branch to compare the target REVISION against e.g. "main".
17+
# - revision: The specific commit hash being deployed e.g. "41af8fa0fc80b7f590a0f46eccd4956b4a45c932".
18+
19+
if [ "${CI}" = "true" ]; then
20+
echo "CI environment detected. Skipping check for unusual local git state."
21+
exit 0
22+
fi
23+
24+
git_remote="$1"
25+
git_release_branch="$2"
26+
revision="$3"
27+
28+
if [ -z "${git_remote}" ] || [ -z "${git_release_branch}" ] || [ -z "${revision}" ]; then
29+
echo "ERROR: Missing required arguments. Usage: $0 <GIT_REMOTE> <GIT_RELEASE_BRANCH> <REVISION>"
30+
exit 1
31+
fi
32+
33+
set -euo pipefail
34+
35+
git fetch "${git_remote}" "${git_release_branch}" || { echo "ERROR: git fetch failed."; exit 1; }
36+
37+
show_warning_prompt='false'
38+
39+
echo "Checking if there are any uncommitted changes..."
40+
if [ -z "$(git status --porcelain)" ]; then
41+
echo "(check passed) Git state is clean. There are no uncommitted changes."
42+
else
43+
show_warning_prompt='true'
44+
echo "WARNING: Uncommitted changes detected!"
45+
echo "⬇ Review the git status. ⬇"
46+
git status
47+
echo
48+
fi
49+
50+
echo "Checking if the currently checked out branch is the release branch ${git_release_branch}..."
51+
current_branch=$(git rev-parse --abbrev-ref HEAD)
52+
if [ "${current_branch}" = "${git_release_branch}" ]; then
53+
echo "(check passed) On ${current_branch} branch."
54+
else
55+
show_warning_prompt='true'
56+
echo "WARNING: Not on ${git_release_branch} branch! Currently on ${current_branch} branch."
57+
echo "⬇ Review the git log for the currently checked out commit. ⬇"
58+
git --no-pager log -1
59+
echo
60+
fi
61+
62+
echo "Checking if REVISION=${revision} is the HEAD of the up-to-date remote release branch ${git_remote}/${git_release_branch}..."
63+
remote_release_branch_head="$(git rev-parse "${git_remote}/${git_release_branch}")"
64+
if [ "${revision}" = "${remote_release_branch_head}" ]; then
65+
echo "(check passed) REVISION=${revision} is the HEAD of the up-to-date remote release branch ${git_remote}/${git_release_branch}."
66+
else
67+
show_warning_prompt='true'
68+
69+
remote_release_branch_relative_time="$(git --no-pager log -1 --pretty=format:'%cr' "${remote_release_branch_head}")"
70+
revision_relative_time="$(git --no-pager log -1 --pretty=format:'%cr' "${revision}")"
71+
72+
echo "WARNING: REVISION is not the HEAD of the remote release branch ${git_remote}/${git_release_branch}!"
73+
echo "- ${remote_release_branch_head} ${git_remote}/${git_release_branch} (${remote_release_branch_relative_time})"
74+
echo "- ${revision} REVISION (${revision_relative_time})"
75+
echo "⬇ Review the git log for ${git_remote}/${git_release_branch} (committed ${remote_release_branch_relative_time}). ⬇"
76+
git --no-pager log -1 "${git_remote}/${git_release_branch}"
77+
echo "⬇ Review the git log for REVISION (committed ${revision_relative_time}). ⬇"
78+
git --no-pager log -1 "${revision}"
79+
echo
80+
fi
81+
82+
if [ "${show_warning_prompt}" = 'true' ]; then
83+
printf "WARNING: Unusual conditions detected! Are you sure you want to deploy? (y/n) "
84+
read -r prompt_answer
85+
if [ "${prompt_answer}" != "y" ]; then
86+
echo "Aborting."
87+
exit 1
88+
fi
89+
fi

deploy-tools.gemspec

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
Gem::Specification.new do |s|
2-
s.name = 'deploy-tools'
3-
s.version = '0.1.4'
4-
s.date = '2022-06-28'
2+
s.name = "deploy-tools"
3+
s.version = "0.2.0"
4+
s.required_ruby_version = ">= 2.7"
55
s.summary = "Deploy tools"
66
s.description = "A set of script used for deployment"
7-
s.authors = ["Tony Nyurkin", "Serhii Voronoi"]
8-
s.email = '[email protected]'
9-
s.files = `git ls-files `.split("\n")
7+
s.authors = ["Tony Nyurkin", "Serhii Voronoi", "George Pantazes"]
8+
s.email = "[email protected]"
9+
s.homepage = "https://github.com/simplepractice/deploy-tools"
10+
s.files = ["README.md", *Dir.glob("bin/*")]
1011
s.bindir = "bin"
11-
s.executables = ["blue_green_switch", "detect_inactive_color"]
12-
s.add_runtime_dependency 'aws-sdk-elasticloadbalancingv2', '~>1.44'
12+
s.executables = [
13+
"blue_green_switch",
14+
"detect_inactive_color",
15+
"prompt_for_unusual_local_git_state"
16+
]
17+
s.add_runtime_dependency "aws-sdk-elasticloadbalancingv2", "~>1.44"
1318
end

0 commit comments

Comments
 (0)