Skip to content

Feature/mono repo safety #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ This is accomplished by counting the merges of branches matching the [naming sch

## Recent Changes

- 1.0.0: (non-breaking) Addition of support for mono-repos. IE: Discretely version specific directories.
- NOTE: Github, Jira, etc., were designed to host one product per repo/project. DO NOT create new mono-repo projects unless you're specifically tooling out to support them well.
- 0.3.1: Update the checkout action version to v4.
- 0.3.0: Bring back the unshallowing, which ensures the full git log is available.
- TODO: Adjust scripts to use `git log --remotes` to avoid unshallowing large repos.
Expand Down Expand Up @@ -56,6 +58,28 @@ git push --set-upstream origin fix/not-a-feature
# THEN: Click the link to create a PR & merge it</pre></dd>
</dl>

### Inputs

Note: Only required for setting up mono-repo versioning.

<dl>
<dt>mono-repo-product-name: [string]</dt>
<dd>Enables mono-repo mode. The product name to match against.<br>
Eg: 'bob', would match the tags like 'bob_1.2.3'.<br>
<i>Required:</i> if mono-repo-mode: true<br>
<i>Default:</i> ''</dd>
<dt>mono-repo-product-path: [string]</dt>
<dd>The path to the product.<br>
Eg: path/to/bob<br>
<i>Required:</i> if mono-repo-mode: true<br>
<i>Default:</i> ''</dd>
<dt>force-patch-increment: [bool]</dt>
<dd>Forces a PATCH increment if no other increment detected.<br>
(Intended for development purposes only.)<br>
<i>Required:</i> false<br>
<i>Default:</i> false</dd>
</dl>

### Outputs

<dl>
Expand Down Expand Up @@ -84,14 +108,22 @@ Below is a valid workflow utilizing this action. If you wanted to extend it to d
- uses: actions/checkout@v3
- name: Run GitOps Automatic Versioning Action
id: gitops-autover
uses: AlexAtkinson/github-action-gitops-autover@0.3.0
uses: AlexAtkinson/github-action-gitops-autover@0.3.1
- name: Verify Outputs
run: |
NEW_VERSION=${{ steps.gitops-autover.outputs.new-version }}
echo "new-version: $NEW_VERSION"
PREVIOUS_VERSION=${{ steps.gitops-autover.outputs.previous-version }}
echo "previous-version: $PREVIOUS_VERSION"

To make use of the mono-repo support, simply add a block for the director you wish to version.

- name: Run GitOps Automatic Versioning Action
id: gitops-autover
uses: AlexAtkinson/github-action-gitops-autover@0.3.1
with:
mono-repo-product-name: bob

This results in outputs like:

_major:_
Expand Down Expand Up @@ -151,7 +183,7 @@ Additionally, this repo uses its own action for versioning, so feel free to inve
echo "PRODUCT_NAME_LOWER=$PRODUCT_NAME_LOWER" >> $GITHUB_OUTPUT
- name: GitOps Automatic Versioning
id: gitops-autover
uses: AlexAtkinson/github-action-gitops-autover@0.3.0
uses: AlexAtkinson/github-action-gitops-autover@0.3.1
build:
name: "Build"
runs-on: ubuntu-latest
Expand Down Expand Up @@ -265,5 +297,5 @@ For those interested, here's some pseudo code:
PRs are welcome.

- input(s): iteration-branches (map) - inform MINOR and PATCH incrementing branch name patterns.
- input(s): mono-mode (bool) - version subdirs discretely
- ~~CAN'T DO~~: DONE: unshallow from last version tag to latest commit to... Seems a limitation of (git at first glance). See the [Checkout From Tag](https://github.com/marketplace/actions/checkout-from-tag) action.
- DONE: input(s): mono-mode (bool) - version subdirs discretely
- UNDONE-CAN'T DO: ~~CAN'T DO~~: ~~DONE:~~ unshallow from last version tag to latest commit to... Seems a limitation of (git at first glance). See the [Checkout From Tag](https://github.com/marketplace/actions/checkout-from-tag) action.
17 changes: 15 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ inputs:
description: "Forces a PATCH increment if no other increment detected. NOTE: This is intended for development purposes only."
required: false
default: 'false'
mono-repo-product-name:
description: "Enables mono-repo mode. The product name to match against. EG: 'bob', match the tags like 'bob_1.2.3'."
required: false
default: ''
mono-repo-product-path:
description: "The path to the product. IE: 'path/to/bob'. Required if 'mono-repo-mode' is enabled."
required: false
default: ''
outputs:
new-version:
description: "New Version"
Expand Down Expand Up @@ -41,8 +49,13 @@ runs:
run: |
cd $GITHUB_WORKSPACE
opt=''
[[ "${{ inputs.force-re-evaluate }}" == 'true' ]] && opt='-f'
[[ "${{ inputs.force-patch-increment }}" == 'true' ]] && opt='-p'
[[ "${{ inputs.force-re-evaluate }}" == 'true' ]] && opt='$opt -f'
[[ "${{ inputs.force-patch-increment }}" == 'true' ]] && opt='$opt -p'
if [[ -z ${{ inputs.mono-repo-product-name }} ]]; then
echo -e "ERROR: 571 - mono-repo-product-name must be set and NOT null!"
exit 1 || true
fi
[[ -n "${{ inputs.mono-repo-product-name }}" ]] && opt='$opt -n ${{ inputs.mono-repo-product-name }}'
new_version="$(${{ github.action_path }}/scripts/detectNewVersion.sh $opt)" || true
echo "new-version=$new_version" | tee $GITHUB_OUTPUT
if [[ "$new_version" =~ "520" ]]; then
Expand Down
44 changes: 31 additions & 13 deletions scripts/detectNewVersion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ NAME
${0##*/}

SYNOPSIS
${0##*/} [-hv]
${0##*/} [-hefpnd]

DESCRIPTION
Detects the new version for the repository by analyzing the gitflow branch history since the
Expand All @@ -47,6 +47,12 @@ DESCRIPTION
-p Increments PATCH version on _every_ run.
WARN: This is intended development use only.

-n Enables mono-repo mode allowing the product name to match against tags.
EG: 'bob' would match tags like 'bob_1.2.3'.
TIP: dir names and product names should match. This arg exists in case they do not.

-d The directory of the product to version. EG: 'path/to/bob'.

EXAMPLES
The following detects the new version for the repo.

Expand Down Expand Up @@ -75,7 +81,7 @@ fi
# --------------------------------------------------------------------------------------------------

OPTIND=1
while getopts "he:vfp" opt; do
while getopts "he:vfpn:d:" opt; do
case $opt in
h)
printHelp
Expand All @@ -95,6 +101,17 @@ while getopts "he:vfp" opt; do
p)
arg_p='set'
;;
n)
arg_n='set'
arg_n_val="$OPTARG"
arg_opts="$arg_opts -n $OPTARG"
;;
d)
arg_d='set'
arg_d_val="$OPTARG"
arg_d_opt="--full-history"
arg_opts="$arg_opts -d $OPTARG"
;;
*)
echo -e "\e[01;31mERROR\e[00m: 570 - Invalid argument!"
printHelp
Expand All @@ -118,13 +135,13 @@ tsCmd='date --utc +%FT%T.%3NZ'
relative_path="$(dirname "${BASH_SOURCE[0]}")"
dir="$(realpath "${relative_path}")"

lastVersion=$(/usr/bin/env bash -c "${dir}/detectPreviousVersion.sh")
lastVersionMajor=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -p major $lastVersion")
lastVersionMinor=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -p minor $lastVersion")
lastVersionPatch=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -p patch $lastVersion")
lastVersionCommitHash=$(/usr/bin/env bash -c "${dir}/detectPreviousVersion.sh -c")
lastVersion=$(/usr/bin/env bash -c "${dir}/detectPreviousVersion.sh -9 $arg_opts")
lastVersionMajor=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -p major $lastVersion $arg_opts")
lastVersionMinor=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -p minor $lastVersion $arg_opts")
lastVersionPatch=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -p patch $lastVersion $arg_opts")
lastVersionCommitHash=$(/usr/bin/env bash -c "${dir}/detectPreviousVersion.sh -9 -c $arg_opts")
lastCommitHash=$(git rev-parse HEAD)
firstCommitHash=$(git rev-list --max-parents=0 HEAD)
firstCommitHash=$(git rev-list --max-parents=0 HEAD | tail -n 1)

ci_name=$("${dir}/detect-ci.sh")
origin=$(git config --get remote.origin.url)
Expand Down Expand Up @@ -169,20 +186,20 @@ if [[ -n $arg_e ]]; then
fi
fi

git log --pretty=oneline "$lastVersionCommitHash".."$lastCommitHash" | grep '+semver' | grep -q 'major\|breaking' && incrementMajor='true'
git log $arg_d_opt --pretty=oneline "$lastVersionCommitHash".."$lastCommitHash" $arg_d_val | grep '+semver' | grep -q 'major\|breaking' && incrementMajor='true'

if [[ $incrementMajor != 'true' ]]; then
IFS=$'\r\n'
if [[ -n $arg_f ]]; then
for i in $(git log --pretty=oneline "${firstCommitHash}".."${lastCommitHash}" | awk -v s="$merge_string" -v c="$column" '$0 ~ s {print $c}' | awk -v f="$field" -F'/' '{print $f}' | tr -d "'" | grep -i '^enhancement$\|^feature$\|^fix$\|^hotfix$\|^bugfix$\|^ops$' | awk -F '\r' '{print $1}' | sort | uniq -c | sort -nr) ; do
for i in $(git log $arg_d_opt --pretty=oneline "${firstCommitHash}".."${lastCommitHash}" $arg_d_val | awk -v s="$merge_string" -v c="$column" '$0 ~ s {print $c}' | awk -v f="$field" -F'/' '{print $f}' | tr -d "'" | grep -i '^enhancement$\|^feature$\|^fix$\|^hotfix$\|^bugfix$\|^ops$' | awk -F '\r' '{print $1}' | sort | uniq -c | sort -nr) ; do
varname=$(echo "$i" | awk '{print $2}')
varname=${varname,,}
value=$(echo "$i" | awk '{print $1}')
value=${value,,}
declare count_"$varname"="$value"
done
else
for i in $(git log --pretty=oneline "${lastVersionCommitHash}".."${lastCommitHash}" | awk -v s="$merge_string" -v c="$column" '$0 ~ s {print $c}' | awk -v f="$field" -F'/' '{print $f}' | tr -d "'" | grep -i '^enhancement$\|^feature$\|^fix$\|^hotfix$\|^bugfix$\|^ops$' | awk -F '\r' '{print $1}' | sort | uniq -c | sort -nr) ; do
for i in $(git log $arg_d_opt --pretty=oneline "${lastVersionCommitHash}".."${lastCommitHash}" $arg_d_val | awk -v s="$merge_string" -v c="$column" '$0 ~ s {print $c}' | awk -v f="$field" -F'/' '{print $f}' | tr -d "'" | grep -i '^enhancement$\|^feature$\|^fix$\|^hotfix$\|^bugfix$\|^ops$' | awk -F '\r' '{print $1}' | sort | uniq -c | sort -nr) ; do
varname=$(echo "$i" | awk '{print $2}')
varname=${varname,,}
value=$(echo "$i" | awk '{print $1}')
Expand Down Expand Up @@ -236,12 +253,13 @@ elif [[ -n $arg_p ]]; then
newVersionPatch=$((lastVersionPatch + 1))
fi

newVersion=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -9p full $newVersionMajor.$newVersionMinor.$newVersionPatch")
newVersion=$(/usr/bin/env bash -c "${dir}/validateSemver.sh -9p full $newVersionMajor.$newVersionMinor.$newVersionPatch $arg_opts")
[[ -n $arg_n ]] && newVersion="${arg_n_val}_${newVersion}"

if [[ -n $arg_e ]]; then
export_var="$arg_e_val"
eval "${export_var}=${newVersion}"
export export_var
else
echo "$newVersion"
fi
fi
44 changes: 38 additions & 6 deletions scripts/detectPreviousVersion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ NAME
detectPreviousVersion.sh

SYNOPSIS
${0##*/} [-hvc]
${0##*/} [-hvcnd]

DESCRIPTION
Detects most recent version tag of the repository.
Expand All @@ -30,6 +30,12 @@ DESCRIPTION

-c Prints the commit hash instead of the detected version to stdout.

-n Enables mono-repo mode allowing the product name to match against tags.
EG: 'bob' would match tags like 'bob_1.2.3'.
TIP: dir names and product names should match. This arg exists in case they do not.

-d The directory of the product to version. EG: 'path/to/bob'.

EXAMPLES
Detects previous version, printing additional information if available.

Expand Down Expand Up @@ -59,7 +65,7 @@ fi
# --------------------------------------------------------------------------------------------------

OPTIND=1
while getopts "hvc" opt; do
while getopts "hv9cn:d:" opt; do
case $opt in
h)
printHelp
Expand All @@ -71,6 +77,20 @@ while getopts "hvc" opt; do
c)
arg_c='set'
;;
9)
arg_9='set'
;;
n)
arg_n='set'
arg_n_val="$OPTARG"
arg_opts="$arg_opts -n $OPTARG"
;;
d)
arg_d='set'
arg_d_val="$OPTARG"
arg_d_opt="--full-history"
arg_opts="$arg_opts -d $OPTARG"
;;
*)
echo -e "\e[01;31mERROR\e[00m: Invalid argument!"
printHelp
Expand All @@ -85,31 +105,43 @@ shift $((OPTIND-1))
# --------------------------------------------------------------------------------------------------

tsCmd='date --utc +%FT%T.%3NZ'
semverRegex="^[v]?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-([0-9A-Za-z]+))?(\\+((([1-9])|([1-9][0-9]+))))?$"

if [[ -n $arg_9 ]]; then
semverRegex="^[v]?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"
[[ -n $arg_d ]] && semverRegex="([0-9A-Za-z]+)?[_-]?[v]?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"
else
semverRegex="^[v]?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-([0-9A-Za-z]+))?(\\+((([1-9])|([1-9][0-9]+))))?$"
[[ -n $arg_d ]] && semverRegex="^([0-9A-Za-z]+)?[_-]?[v]?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-([0-9A-Za-z]+))?(\\+((([1-9])|([1-9][0-9]+))))?$"
fi

relative_path="$(dirname "${BASH_SOURCE[0]}")"
dir="$(realpath "${relative_path}")"

lastVersion=$(git for-each-ref --sort=creatordate --format '%(refname:lstrip=2)' refs/tags | grep -E "$semverRegex" | tail -n 1)
# Support mono-repos where a product name is specified.
[[ -n $arg_n ]] && lastVersion=$(git for-each-ref --sort=creatordate --format '%(refname:lstrip=2)' refs/tags | grep "$arg_n_val" | grep -E "$semverRegex" | tail -n 1)

# --------------------------------------------------------------------------------------------------
# Sanity (2/2)
# --------------------------------------------------------------------------------------------------

if [[ "$lastVersion" == '' ]]; then
[[ -n $arg_v ]] && echo -e "[$(${tsCmd})] INFO: No previous version detected. Initializing at '0.0.0'.\n"
[[ -n $arg_v && -z $arg_n ]] && echo -e "[$(${tsCmd})] INFO: No previous version detected. Initializing at '0.0.0'.\n"
[[ -n $arg_v && -n $arg_n ]] && echo -e "[$(${tsCmd})] INFO: No previous version detected. Initializing at '${arg_n_val}_0.0.0'.\n"
lastVersion='0.0.0'
lastVersionCommitHash=$(git rev-list --max-parents=0 HEAD)
else
if ! bash -c "${dir}/validateSemver.sh -v9 $lastVersion"; then
if ! bash -c "${dir}/validateSemver.sh -v9 $arg_opts $lastVersion"; then
exit 1
else
lastVersionCommitHash=$(git rev-list -n 1 "$lastVersion")
# Ensure lastVersion does not include a leading [vV]
lastVersion=$(bash -c "${dir}/validateSemver.sh -v9p full $lastVersion")
lastVersion=$(bash -c "${dir}/validateSemver.sh -v9p full $arg_opts $lastVersion")
fi
fi

[[ -n $arg_n ]] && lastVersion="${arg_n_val}_${lastVersion}"

# --------------------------------------------------------------------------------------------------
# Main Operations
# --------------------------------------------------------------------------------------------------
Expand Down
Loading
Loading