Skip to content
Open
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
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ Tracks the commits in a [git](http://git-scm.com/) repository.
* `ignore_branches`: *Optional.* Used in conjunction with and applied after
the `branches` pattern. See example for common use case.

* `sort`: *Optional.* When set to `semver`, branches matched by the
`branches` pattern will be sorted by semantic version (highest first)
before processing. This ensures the branch with the highest version
number is always checked first. Only meaningful in multi-branch mode.

* `sort_prefix`: *Optional.* Used in conjunction with `sort: semver`. A
regex pattern that is stripped from the branch name before extracting
the version for comparison. For example, `(release|hotfix)/` would
strip the prefix from `release/2.0.0` and `hotfix/1.0.1` to compare
`2.0.0` vs `1.0.1`.

* `redis`: *Optional.* Contains the information required to use a specified
Redis server to store multibranch historic references so that they don't
clutter up the ref lines. It consists of the following subkeys:
Expand Down Expand Up @@ -102,6 +113,19 @@ resources:
ignore_branches: '(master|deploy)'
```

Detecting the highest version release or hotfix branch first

``` yaml
resources:
- name: my-releases
type: git-multibranch
source:
uri: git@github.com:my-org/my-repo.git
branches: '(release|hotfix)/\d+\.\d+\.\d+'
sort: semver
sort_prefix: '(release|hotfix)/'
```

## Behavior

### `check`: Check for new commits.
Expand Down
28 changes: 27 additions & 1 deletion assets/check
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ ignore_branches=$(jq -r '.source.ignore_branches // ""' < $payload)
paths="$(jq -r '(.source.paths // ["."])[]' < $payload)" # those "'s are important
ignore_paths="$(jq -r '":!" + (.source.ignore_paths // [])[]' < $payload)" # these ones too
last_refs=$(jq -r '.version.ref // ""' < $payload)
sort_mode=$(jq -r '.source.sort // ""' < $payload)
sort_prefix=$(jq -r '.source.sort_prefix // ""' < $payload)

## Redis stuff to support cleaner multibranch behaviour
redis_host=$(jq -r '.source.redis.host // ""' < $payload)
Expand Down Expand Up @@ -75,6 +77,29 @@ filter_branches() {
echo "$branch_refs"
}

sort_branches_semver() {
# When sort mode is semver, strip the prefix from branch names,
# sort by major.minor.patch descending, then restore original format.
# This ensures the highest version is processed first.
if [ "$sort_mode" = "semver" ] ; then
local input="$(cat)"
if [ -n "$sort_prefix" ] ; then
echo "$input" | \
awk -F: -v prefix="$sort_prefix" '{
branch = $2;
ver = branch;
gsub(prefix, "", ver);
print ver "\t" $0
}' | sort -t. -k1,1rn -k2,2rn -k3,3rn | \
cut -f2
else
echo "$input"
fi
else
cat
fi
}

get_refs() {
local ref="$1"
git log --grep '\[ci skip\]' --invert-grep --format='%H' $(log_range $ref) $(paths_search "$paths" "$ignore_paths")
Expand Down Expand Up @@ -128,7 +153,8 @@ get_branch_refs() {
grep -e '^[0-9a-f]\{40\}:' | \
sort -t: -k1 | grep ":origin/" | \
sed -e 's/:origin\//:/' | \
filter_branches)"
filter_branches | \
sort_branches_semver)"

# Find the first branch that has a different ref
for branch_and_ref in $current_branches ; do
Expand Down
46 changes: 46 additions & 0 deletions test/check_multi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,50 @@ it_can_find_successive_branches_with_multiple_commits_with_redis() {
fi
}

it_sorts_branches_by_semver_highest_first() {
local repo=$(init_repo)

# Create release branches with different versions
local ref1=$(make_commit_to_branch $repo "release/1.0.0")
local ref2=$(make_commit_to_branch $repo "release/2.0.0")
local ref3=$(make_commit_to_branch $repo "release/1.5.0")

# With semver sort, the highest version (release/2.0.0) should always be returned first
# regardless of commit hash ordering
local result=$(test_check uri $repo branches 'release/.*' sort semver sort_prefix 'release/')

local returned_branch=$(echo "$result" | jq -r '.[0].ref' | sed 's/^[0-9a-f]*://' | awk '{print $1}')

if [ "$returned_branch" != "release/2.0.0" ] ; then
echo "Expected release/2.0.0 to be returned first, got: $returned_branch"
return 1
fi

echo "Correctly returned release/2.0.0 (highest semver) first"
}

it_sorts_mixed_release_hotfix_branches_by_semver() {
local repo=$(init_repo)

# Create mixed release and hotfix branches
local ref1=$(make_commit_to_branch $repo "release/1.0.0")
local ref2=$(make_commit_to_branch $repo "hotfix/1.0.1")
local ref3=$(make_commit_to_branch $repo "release/2.0.0")
local ref4=$(make_commit_to_branch $repo "hotfix/2.0.1")

# With semver sort and prefix stripping, hotfix/2.0.1 (version 2.0.1) should be first
local result=$(test_check uri $repo branches '(release|hotfix)/.*' sort semver sort_prefix '(release|hotfix)/')

local returned_branch=$(echo "$result" | jq -r '.[0].ref' | sed 's/^[0-9a-f]*://' | awk '{print $1}')

if [ "$returned_branch" != "hotfix/2.0.1" ] ; then
echo "Expected hotfix/2.0.1 to be returned first (highest semver 2.0.1), got: $returned_branch"
return 1
fi

echo "Correctly returned hotfix/2.0.1 (highest semver 2.0.1) first"
}

# --- RUN TESTS ---

run it_can_perform_initial_check
Expand All @@ -308,3 +352,5 @@ run it_can_find_successive_branches_with_multiple_commits
run it_ignores_branches_with_only_skip_commits
run it_can_find_branches_that_has_multiple_commits_with_latest_being_skipped
run it_can_find_successive_branches_with_multiple_commits_with_redis
run it_sorts_branches_by_semver_highest_first
run it_sorts_mixed_release_hotfix_branches_by_semver
16 changes: 16 additions & 0 deletions test/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,22 @@ test_check() {
}")"
shift;;

"sort" )
addition="$(jq -n "{
source: {
sort: $(echo "$1" | jq -R '.')
}
}")"
shift;;

"sort_prefix" )
addition="$(jq -n "{
source: {
sort_prefix: $(echo "$1" | jq -R '.')
}
}")"
shift;;

"redis" )
addition="$(jq -n "{
source: {
Expand Down