diff --git a/.github/is-latest-release.sh b/.github/is-latest-release.sh new file mode 100644 index 000000000..cf8f0071c --- /dev/null +++ b/.github/is-latest-release.sh @@ -0,0 +1,132 @@ +#!/bin/sh + +# Checks if the current tag should be the latest (in terms of semver and not of release date). +# Ex: previous tag -> v0.10.1 +# new tag -> v0.8.12 +# The new tag should not be the latest +# So it returns "false", the CI should not run for the release v0.8.2 + +# Used in GHA in publish-docker-latest.yml +# Returns "true" or "false" (as a string) to be used in the `if` in GHA + +# GLOBAL +GREP_SEMVER_REGEXP='v\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)$' # i.e. v[number].[number].[number] + +# FUNCTIONS + +# semverParseInto and semverLT from https://github.com/cloudflare/semver_bash/blob/master/semver.sh + +# usage: semverParseInto version major minor patch special +# version: the string version +# major, minor, patch, special: will be assigned by the function +semverParseInto() { + local RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)' + #MAJOR + eval $2=`echo $1 | sed -e "s#$RE#\1#"` + #MINOR + eval $3=`echo $1 | sed -e "s#$RE#\2#"` + #MINOR + eval $4=`echo $1 | sed -e "s#$RE#\3#"` + #SPECIAL + eval $5=`echo $1 | sed -e "s#$RE#\4#"` +} + +# usage: semverLT version1 version2 +semverLT() { + local MAJOR_A=0 + local MINOR_A=0 + local PATCH_A=0 + local SPECIAL_A=0 + + local MAJOR_B=0 + local MINOR_B=0 + local PATCH_B=0 + local SPECIAL_B=0 + + semverParseInto $1 MAJOR_A MINOR_A PATCH_A SPECIAL_A + semverParseInto $2 MAJOR_B MINOR_B PATCH_B SPECIAL_B + + if [ $MAJOR_A -lt $MAJOR_B ]; then + return 0 + fi + if [ $MAJOR_A -le $MAJOR_B ] && [ $MINOR_A -lt $MINOR_B ]; then + return 0 + fi + if [ $MAJOR_A -le $MAJOR_B ] && [ $MINOR_A -le $MINOR_B ] && [ $PATCH_A -lt $PATCH_B ]; then + return 0 + fi + if [ "_$SPECIAL_A" == "_" ] && [ "_$SPECIAL_B" == "_" ] ; then + return 1 + fi + if [ "_$SPECIAL_A" == "_" ] && [ "_$SPECIAL_B" != "_" ] ; then + return 1 + fi + if [ "_$SPECIAL_A" != "_" ] && [ "_$SPECIAL_B" == "_" ] ; then + return 0 + fi + if [ "_$SPECIAL_A" < "_$SPECIAL_B" ]; then + return 0 + fi + + return 1 +} + +# Returns the tag of the latest stable release (in terms of semver and not of release date) +get_latest() { + temp_file='temp_file' # temp_file needed because the grep would start before the download is over + curl -s 'https://api.github.com/repos/meilisearch/MeiliSearch/releases' > "$temp_file" + releases=$(cat "$temp_file" | \ + grep -E "tag_name|draft|prerelease" \ + | tr -d ',"' | cut -d ':' -f2 | tr -d ' ') + # Returns a list of [tag_name draft_boolean prerelease_boolean ...] + # Ex: v0.10.1 false false v0.9.1-rc.1 false true v0.9.0 false false... + + i=0 + latest="" + current_tag="" + for release_info in $releases; do + if [ $i -eq 0 ]; then # Cheking tag_name + if echo "$release_info" | grep -q "$GREP_SEMVER_REGEXP"; then # If it's not an alpha or beta release + current_tag=$release_info + else + current_tag="" + fi + i=1 + elif [ $i -eq 1 ]; then # Checking draft boolean + if [ "$release_info" == "true" ]; then + current_tag="" + fi + i=2 + elif [ $i -eq 2 ]; then # Checking prerelease boolean + if [ "$release_info" == "true" ]; then + current_tag="" + fi + i=0 + if [ "$current_tag" != "" ]; then # If the current_tag is valid + if [ "$latest" = "" ]; then # If there is no latest yet + latest="$current_tag" + else + semverLT $current_tag $latest # Comparing latest and the current tag + if [ $? -eq 1 ]; then + latest="$current_tag" + fi + fi + fi + fi + done + + rm -f "$temp_file" + echo $latest +} + +# MAIN +current_tag="$(echo $GITHUB_REF | tr -d 'refs/tags/')" +latest="$(get_latest)" + +if [ "$current_tag" != "$latest" ]; then + # The current release tag is not the latest + echo "false" +else + # The current release tag is the latest + echo "true" +then diff --git a/.github/workflows/README.md b/.github/workflows/README.md index b7d60cc47..32c32c7d6 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,4 +1,4 @@ -# GitHub actions workflow for MeiliDB +# GitHub Actions Workflow for MeiliSearch > **Note:** @@ -6,12 +6,14 @@ ## Workflow -- On each pull request, we are triggering `cargo test`. -- On each tag, we are building: - - the tagged docker image +- On each pull request, we trigger `cargo test`. +- On each tag, we build: + - the tagged Docker image and publish it to Docker Hub - the binaries for MacOS, Ubuntu, and Windows - - the debian package -- On each stable release, we are build the latest docker image. + - the Debian package +- On each stable release (`v*.*.*` tag): + - we build the `latest` Docker image and publish it to Docker Hub + - we publish the binary to Hombrew and Gemfury ## Problems diff --git a/.github/workflows/publish-deb-brew-pkg.yml b/.github/workflows/publish-deb-brew-pkg.yml index 1f2def546..3a2844f3c 100644 --- a/.github/workflows/publish-deb-brew-pkg.yml +++ b/.github/workflows/publish-deb-brew-pkg.yml @@ -1,9 +1,8 @@ -name: Publish deb pkg to GitHub release & apt repository & Homebrew +name: Publish deb pkg to GitHub release & APT repository & Homebrew on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+' + release: + types: [published] jobs: debian: @@ -32,7 +31,8 @@ jobs: name: Bump Homebrew formula runs-on: ubuntu-latest steps: - - uses: mislav/bump-homebrew-formula-action@v1 + - name: Create PR to Homebrew + uses: mislav/bump-homebrew-formula-action@v1 with: formula-name: meilisearch env: diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml index 5c7d6899e..052fd3792 100644 --- a/.github/workflows/publish-docker-latest.yml +++ b/.github/workflows/publish-docker-latest.yml @@ -1,8 +1,7 @@ --- on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+' + release: + types: [published] name: Publish latest image to Docker Hub @@ -10,8 +9,12 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 + - name: Check if current release is latest + run: echo "##[set-output name=is_latest;]$(sh .github/is-latest-release.sh)" + id: release - name: Publish to Registry + if: steps.release.outputs.is_latest == 'true' uses: elgohr/Publish-Docker-Github-Action@master with: name: getmeili/meilisearch diff --git a/download-latest.sh b/download-latest.sh index a8fe4a1f5..d3640f472 100644 --- a/download-latest.sh +++ b/download-latest.sh @@ -6,8 +6,10 @@ GREEN='\033[32m' DEFAULT='\033[0m' # GLOBALS -GREP_SEMVER_REGEXP='\"v\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\"' # i.e. "v[number].[number].[number]" BINARY_NAME='meilisearch' +GREP_SEMVER_REGEXP='v\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)$' # i.e. v[number].[number].[number] + +# FUNCTIONS # semverParseInto and semverLT from https://github.com/cloudflare/semver_bash/blob/master/semver.sh @@ -66,6 +68,74 @@ semverLT() { return 1 } +# Returns the tag of the latest stable release (in terms of semver and not of release date) +get_latest() { + temp_file='temp_file' # temp_file needed because the grep would start before the download is over + curl -s 'https://api.github.com/repos/meilisearch/MeiliSearch/releases' > "$temp_file" + releases=$(cat "$temp_file" | \ + grep -E "tag_name|draft|prerelease" \ + | tr -d ',"' | cut -d ':' -f2 | tr -d ' ') + # Returns a list of [tag_name draft_boolean prerelease_boolean ...] + # Ex: v0.10.1 false false v0.9.1-rc.1 false true v0.9.0 false false... + + i=0 + latest="" + current_tag="" + for release_info in $releases; do + if [ $i -eq 0 ]; then # Cheking tag_name + if echo "$release_info" | grep -q "$GREP_SEMVER_REGEXP"; then # If it's not an alpha or beta release + current_tag=$release_info + else + current_tag="" + fi + i=1 + elif [ $i -eq 1 ]; then # Checking draft boolean + if [ "$release_info" == "true" ]; then + current_tag="" + fi + i=2 + elif [ $i -eq 2 ]; then # Checking prerelease boolean + if [ "$release_info" == "true" ]; then + current_tag="" + fi + i=0 + if [ "$current_tag" != "" ]; then # If the current_tag is valid + if [ "$latest" = "" ]; then # If there is no latest yet + latest="$current_tag" + else + semverLT $current_tag $latest # Comparing latest and the current tag + if [ $? -eq 1 ]; then + latest="$current_tag" + fi + fi + fi + fi + done + + rm -f "$temp_file" + echo $latest +} + +get_os() { + os_name=$(uname -s) + if [ "$os_name" != "Darwin" ]; then + os_name=$(cat /etc/os-release | grep '^ID=' | tr -d '"' | cut -d '=' -f 2) + fi + case "$os_name" in + 'Darwin') + os='macos' + ;; + 'ubuntu' | 'debian') + os='linux' + ;; + *) + failure_usage + exit 1 + esac + + echo "$os" +} + success_usage() { printf "$GREEN%s\n$DEFAULT" "MeiliSearch binary successfully downloaded as '$BINARY_NAME' file." echo '' @@ -82,45 +152,11 @@ failure_usage() { echo 'Follow the steps on the docs: https://docs.meilisearch.com/advanced_guides/binary.html#how-to-compile-meilisearch' } -# OS DETECTION -echo 'Detecting OS distribution...' -os_name=$(uname -s) -if [ "$os_name" != "Darwin" ]; then - os_name=$(cat /etc/os-release | grep '^ID=' | tr -d '"' | cut -d '=' -f 2) -fi -echo "OS distribution detected: $os_name" -case "$os_name" in -'Darwin') - os='macos' - ;; -'ubuntu' | 'debian') - os='linux' - ;; -*) - failure_usage - exit 1 -esac +# MAIN +os="$(get_os)" +latest="$(get_latest)" +echo "Downloading MeiliSearch binary $latest for $os..." -# GET LATEST VERSION -tags=$(curl -s 'https://api.github.com/repos/meilisearch/MeiliSearch/tags' \ - | grep "$GREP_SEMVER_REGEXP" \ - | grep 'name' \ - | tr -d '"' | tr -d ',' | cut -d 'v' -f 2) - -latest="" -for tag in $tags; do - if [ "$latest" = "" ]; then - latest="$tag" - else - semverLT $tag $latest - if [ $? -eq 1 ]; then - latest="$tag" - fi - fi -done - -# DOWNLOAD THE LATEST -echo "Downloading MeiliSearch binary v$latest for $os..." release_file="meilisearch-$os-amd64" link="https://github.com/meilisearch/MeiliSearch/releases/download/v$latest/$release_file" curl -OL "$link"