Skip to content

Commit

Permalink
[#187390534] make deploy prompts if not releasing HEAD of origin main…
Browse files Browse the repository at this point in the history
… release branch

Co-authored-by: Simon St-Onge <120414454+simonsto@users.noreply.github.com>
  • Loading branch information
gwpantazes and simonsto committed Apr 12, 2024
1 parent 606ddbf commit be65637
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 8 deletions.
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

source "https://rubygems.org"

group :development do
gem "rubocop"
end
39 changes: 39 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
json (2.7.2)
language_server-protocol (3.17.0.3)
parallel (1.24.0)
parser (3.3.0.5)
ast (~> 2.4.1)
racc
racc (1.7.3)
rainbow (3.1.1)
regexp_parser (2.9.0)
rexml (3.2.6)
rubocop (1.63.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.2)
parser (>= 3.3.0.4)
ruby-progressbar (1.13.0)
unicode-display_width (2.5.0)

PLATFORMS
arm64-darwin-22
ruby

DEPENDENCIES
rubocop

BUNDLED WITH
2.5.6
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# deploy-tools

## Development

Install dependencies.

```shell
bundle install
```

Run rubocop (including on the `.gemspec` file).

```shell
bundle exec rubocop
```

Build the gem. (Example for `v0.2.0`)

```shell
$ gem build deploy-tools.gemspec
WARNING: licenses is empty, but is recommended. Use an license identifier from
https://spdx.org/licenses or 'Nonstandard' for a nonstandard license,
or set it to nil if you don't want to specify a license.
WARNING: See https://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: deploy-tools
Version: 0.2.0
File: deploy-tools-0.2.0.gem
```
Create a [release on the Github repo](https://github.com/simplepractice/deploy-tools/releases). Attach the built gem file as a release asset.
## Usage
To see installation and usage of the `deploy-tools` gem, see examples in `Makefile`s in deployable repos.
Example: [simplepractice/simplepractice Makefile L6L16-L20 (ff81396)](https://github.com/simplepractice/simplepractice/blob/ff8139631c546804aae9a9577ee04bc18b21c987/Makefile#L6-L20)
```shell
DEPLOY_TOOLS_VERSION = 0.1.4
# ...
echo "Downloading deploy-tools gem"
wget -O deploy-tools.gem https://github.com/simplepractice/deploy-tools/releases/download/$(DEPLOY_TOOLS_VERSION)/deploy-tools-$(DEPLOY_TOOLS_VERSION).gem
echo "Installing gem"
gem install deploy-tools.gem
rm deploy-tools.gem
```
7 changes: 7 additions & 0 deletions bin/prompt_for_unusual_local_git_state
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env ruby
# Hacky wrapper file to call the corresponding shell script. By default, installed gems run scripts as if they are Ruby,
# and do not respect the shebang line (e.g. a bash shebang). This file is a workaround to call the shell script directly.
# Hack source: https://stackoverflow.com/a/27988355/2291928

system("#{__FILE__}.sh #{ARGV.join(' ')}")
exit $?.exitstatus
89 changes: 89 additions & 0 deletions bin/prompt_for_unusual_local_git_state.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Checks local git state for unusual conditions and prompts the user to confirm before deploying.
#
# This is a safety measure to prevent accidental deployments of unintended target commits.
# The purpose is to draw attention to unusual conditions to be reviewed carefully.
#
# This script is intended to be used as a pre-deploy hook in a deployment script for manual/local deployments.
# It is not intended for automated deployments. Set CI=true to skip.
#
# Releases typically deploy the HEAD of the release branch. The conditions in this script favor that typical case.
# There are valid situations (rollback, hotfix, temporary config changes) which trigger warnings. That's OK/expected.
# In such situations, the user should review carefully and confirm the deployment at their discretion.
#
# Usage: $0 <GIT_REMOTE> <GIT_RELEASE_BRANCH> <REVISION>
# - git_remote: The remote to fetch the release branch from e.g. "origin".
# - git_release_branch: The release branch to compare the target REVISION against e.g. "main".
# - revision: The specific commit hash being deployed e.g. "41af8fa0fc80b7f590a0f46eccd4956b4a45c932".

if [ "${CI}" = "true" ]; then
echo "CI environment detected. Skipping check for unusual local git state."
exit 0
fi

git_remote="$1"
git_release_branch="$2"
revision="$3"

if [ -z "${git_remote}" ] || [ -z "${git_release_branch}" ] || [ -z "${revision}" ]; then
echo "ERROR: Missing required arguments. Usage: $0 <GIT_REMOTE> <GIT_RELEASE_BRANCH> <REVISION>"
exit 1
fi

set -euo pipefail

git fetch "${git_remote}" "${git_release_branch}" || { echo "ERROR: git fetch failed."; exit 1; }

show_warning_prompt='false'

echo "Checking if there are any uncommitted changes..."
if [ -z "$(git status --porcelain)" ]; then
echo "(check passed) Git state is clean. There are no uncommitted changes."
else
show_warning_prompt='true'
echo "WARNING: Uncommitted changes detected!"
echo "⬇ Review the git status. ⬇"
git status
echo
fi

echo "Checking if the currently checked out branch is the release branch ${git_release_branch}..."
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [ "${current_branch}" = "${git_release_branch}" ]; then
echo "(check passed) On ${current_branch} branch."
else
show_warning_prompt='true'
echo "WARNING: Not on ${git_release_branch} branch! Currently on ${current_branch} branch."
echo "⬇ Review the git log for the currently checked out commit. ⬇"
git --no-pager log -1
echo
fi

echo "Checking if REVISION=${revision} is the HEAD of the up-to-date remote release branch ${git_remote}/${git_release_branch}..."
remote_release_branch_head="$(git rev-parse "${git_remote}/${git_release_branch}")"
if [ "${revision}" = "${remote_release_branch_head}" ]; then
echo "(check passed) REVISION=${revision} is the HEAD of the up-to-date remote release branch ${git_remote}/${git_release_branch}."
else
show_warning_prompt='true'

remote_release_branch_relative_time="$(git --no-pager log -1 --pretty=format:'%cr' "${remote_release_branch_head}")"
revision_relative_time="$(git --no-pager log -1 --pretty=format:'%cr' "${revision}")"

echo "WARNING: REVISION is not the HEAD of the remote release branch ${git_remote}/${git_release_branch}!"
echo "- ${remote_release_branch_head} ${git_remote}/${git_release_branch} (${remote_release_branch_relative_time})"
echo "- ${revision} REVISION (${revision_relative_time})"
echo "⬇ Review the git log for ${git_remote}/${git_release_branch} (committed ${remote_release_branch_relative_time}). ⬇"
git --no-pager log -1 "${git_remote}/${git_release_branch}"
echo "⬇ Review the git log for REVISION (committed ${revision_relative_time}). ⬇"
git --no-pager log -1 "${revision}"
echo
fi

if [ "${show_warning_prompt}" = 'true' ]; then
printf "WARNING: Unusual conditions detected! Are you sure you want to deploy? (y/n) "
read -r prompt_answer
if [ "${prompt_answer}" != "y" ]; then
echo "Aborting."
exit 1
fi
fi
21 changes: 13 additions & 8 deletions deploy-tools.gemspec
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
Gem::Specification.new do |s|
s.name = 'deploy-tools'
s.version = '0.1.4'
s.date = '2022-06-28'
s.name = "deploy-tools"
s.version = "0.2.0"
s.required_ruby_version = ">= 2.7"
s.summary = "Deploy tools"
s.description = "A set of script used for deployment"
s.authors = ["Tony Nyurkin", "Serhii Voronoi"]
s.email = 'tony@simplepractice.com'
s.files = `git ls-files `.split("\n")
s.authors = ["Tony Nyurkin", "Serhii Voronoi", "George Pantazes"]
s.email = "infra@simplepractice.com"
s.homepage = "https://github.com/simplepractice/deploy-tools"
s.files = ["README.md", *Dir.glob("bin/*")]
s.bindir = "bin"
s.executables = ["blue_green_switch", "detect_inactive_color"]
s.add_runtime_dependency 'aws-sdk-elasticloadbalancingv2', '~>1.44'
s.executables = [
"blue_green_switch",
"detect_inactive_color",
"prompt_for_unusual_local_git_state"
]
s.add_runtime_dependency "aws-sdk-elasticloadbalancingv2", "~>1.44"
end

0 comments on commit be65637

Please sign in to comment.