diff --git a/.github/release.tpl b/.github/release.tpl new file mode 100644 index 000000000..2db6df21f --- /dev/null +++ b/.github/release.tpl @@ -0,0 +1,19 @@ +// publish release writes the following to release notes. +{"buildNo":"${buildNo}","preTag":"${preTag}"} +// buildNo is required,buildNo is used to specify the installer package. +// buildNo is found at https://github.com/goharbor/harbor/actions/workflows/build-package.yml +// preTag is not required, preTag is used to specify the previous tag, and generates release notes between previous tag and current tag. If preTag is not specified, previous tag will be automatically calculated. + +// Example 1 +// current tag:v2.5.0-rc1 +{"buildNo":"build.1250","preTag":"v2.4.0"} +// Specify the installer package built by Build Package Workflow #1272 as release asset. +// Specify the previous tag as v2.4.0 + +// Example 2 +// current tag:v2.5.0 +{"buildNo":"rc1"} +// Specify the installer package of v2.5.0-rc1 as the release asset of v2.5.0. +// Unspecified preTag automatically calculates preTag for v2.4.0 + +// If the wrong buildNo is specified and the Workflow fails to run, please modify the buildNo and re run \ No newline at end of file diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml new file mode 100644 index 000000000..e49cc279d --- /dev/null +++ b/.github/workflows/publish_release.yml @@ -0,0 +1,86 @@ +name: Publish Release + +on: + push: + tags: + - 'v*.*.*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup env + run: | + echo "CUR_TAG=${{ github.ref_name }}" >> $GITHUB_ENV + echo "BASE_TAG=$(cat ./VERSION)" >> $GITHUB_ENV + release=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/goharbor/harbor/releases/tags/${{ github.ref_name }}) + echo "BUILD_NO=$(echo $release | jq -r '.body' | jq -r '.buildNo')" >> $GITHUB_ENV + echo "PRE_TAG=$(echo $release | jq -r '.body' | jq -r '.preTag')" >> $GITHUB_ENV + echo "BRANCH=$(echo $release | jq -r '.target_commitish')" >> $GITHUB_ENV + echo "PRERELEASE=$(echo $release | jq -r '.prerelease')" >> $GITHUB_ENV + - uses: 'google-github-actions/auth@v0' + with: + credentials_json: '${{ secrets.GCP_CREDENTIALS }}' + - uses: google-github-actions/setup-gcloud@v0 + with: + version: '285.0.0' + - name: Prepare Assets + run: | + if [ ! ${{ env.BUILD_NO }} -o ${{ env.BUILD_NO }} = "null" ] + then + echo "missing required parameter buildNo." + exit 1 + fi + echo "buildNo:${{ env.BUILD_NO }}" + echo "preTag:${{ env.PRE_TAG }}" + + src_offline_package=harbor-offline-installer-${{ env.BASE_TAG }}-${{ env.BUILD_NO }}.tgz + src_online_package=harbor-online-installer-${{ env.BASE_TAG }}-${{ env.BUILD_NO }}.tgz + dst_offline_package=harbor-offline-installer-${{ env.CUR_TAG }}.tgz + dst_online_package=harbor-online-installer-${{ env.CUR_TAG }}.tgz + gsutil cp gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${src_offline_package} gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${dst_offline_package} + gsutil cp gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${src_offline_package}.asc gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${dst_offline_package}.asc + gsutil cp gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${src_online_package} gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${dst_online_package} + gsutil cp gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${src_online_package}.asc gs://${{ secrets.HARBOR_RELEASE_BUILD }}/${{ env.BRANCH }}/${dst_online_package}.asc + + assets_path=$(pwd)/assets + source tools/release/release_utils.sh && getAssets ${{ secrets.HARBOR_RELEASE_BUILD }} ${{ env.BRANCH }} $dst_offline_package $dst_online_package ${{ env.PRERELEASE }} $assets_path + echo "OFFLINE_PACKAGE_PATH=$assets_path/$dst_offline_package" >> $GITHUB_ENV + echo "ONLINE_PACKAGE_PATH=$assets_path/$dst_online_package" >> $GITHUB_ENV + echo "MD5SUM_PATH=$assets_path/md5sum" >> $GITHUB_ENV + - name: Setup Docker + uses: docker-practice/actions-setup-docker@0.0.1 + with: + docker_version: 18.09 + docker_channel: stable + - name: Publish Images + run: | + tar -zxf ${{ env.OFFLINE_PACKAGE_PATH }} + docker load -i ./harbor/harbor.${{ env.BASE_TAG }}.tar.gz + source tools/release/release_utils.sh && publishImages ${{ env.CUR_TAG }} ${{ env.BASE_TAG }} ${{ secrets.DOCKER_HUB_PUSH_USERNAME }} ${{ secrets.DOCKER_HUB_PUSH_PASSWORD }} + - name: Generate release notes + run: | + release_notes_path=$(pwd)/release-notes.txt + source tools/release/release_utils.sh && generateReleaseNotes ${{ env.CUR_TAG }} ${{ env.PRE_TAG }} ${{ secrets.GITHUB_TOKEN }} $release_notes_path + echo "RELEASE_NOTES_PATH=$release_notes_path" >> $GITHUB_ENV + - name: RC Release + uses: softprops/action-gh-release@v1 + if: ${{ env.PRERELEASE == 'true' }} + with: + body_path: ${{ env.RELEASE_NOTES_PATH }} + files: | + ${{ env.OFFLINE_PACKAGE_PATH }} + ${{ env.OFFLINE_PACKAGE_PATH }}.asc + ${{ env.MD5SUM_PATH }} + - name: GA Release + uses: softprops/action-gh-release@v1 + if: ${{ env.PRERELEASE == 'false' }} + with: + body_path: ${{ env.RELEASE_NOTES_PATH }} + files: | + ${{ env.OFFLINE_PACKAGE_PATH }} + ${{ env.OFFLINE_PACKAGE_PATH }}.asc + ${{ env.ONLINE_PACKAGE_PATH }} + ${{ env.ONLINE_PACKAGE_PATH }}.asc + ${{ env.MD5SUM_PATH }} \ No newline at end of file diff --git a/tools/release/release_utils.sh b/tools/release/release_utils.sh new file mode 100644 index 000000000..50d7b5daf --- /dev/null +++ b/tools/release/release_utils.sh @@ -0,0 +1,87 @@ +#!/bin/bash +set -e + +function getAssets { + local bucket=$1 + local branch=$2 + local offlinePackage=$3 + local onlinePackage=$4 + local prerelease=$5 + local assetsPath=$6 + mkdir $assetsPath && pushd $assetsPath + gsutil cp gs://$bucket/$branch/$offlinePackage . + gsutil cp gs://$bucket/$branch/$offlinePackage.asc . + md5sum $offlinePackage > md5sum + md5sum $offlinePackage.asc >> md5sum + # Pre-release does not handle online installer packages + if [ $prerelease = "false" ] + then + gsutil cp gs://$bucket/$branch/$onlinePackage . + gsutil cp gs://$bucket/$branch/$onlinePackage.asc . + md5sum $onlinePackage >> md5sum + md5sum $onlinePackage.asc >> md5sum + fi + popd +} + +function generateReleaseNotes { + # Use .github/release.yml configuration to generate release notes for preTag to curTag + local curTag=$1 + local preTag=$2 + local token=$3 + local releaseNotesPath=$4 + set +e + # Calculate preTag if preTag is null + # If curTag is v2.5.0-rc1 then preTag is v2.4.0 + # If curTag is v2.5.1 then preTag is v2.5.0 + if [ $preTag = "null" ] + then + IFS='.' read -r -a curTagArray <<< $curTag + IFS='-' read -r -a patch <<< ${curTagArray[2]} + local tagMajor=${curTagArray[0]} + local tagMinor=${curTagArray[1]} + local tagPatch=${patch[0]} + if [ $tagPatch -gt 0 ] + then + preTag="$tagMajor.$tagMinor.$(expr $tagPatch - 1)" + else + preTag="$tagMajor.$(expr $tagMinor - 1).$tagPatch" + fi + fi + set -e + release=$(curl -X POST -H "Authorization: token $token" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/goharbor/harbor/releases/generate-notes -d '{"tag_name":"'$curTag'","previous_tag_name":"'$preTag'"}' | jq '.body' | tr -d '"') + echo -e $release > $releaseNotesPath +} + +function publishImages { + # Create curTag and push it to the goharbor namespace of dockerhub + local curTag=$1 + local baseTag=$2 + local dockerHubUser=$3 + local dockerHubPassword=$4 + docker login -u $dockerHubUser -p $dockerHubPassword + local images="$(docker images --format "{{.Repository}}" --filter=reference='goharbor/*:'$baseTag'')" + for image in $images + do + echo "push image: $image" + docker tag $image:$baseTag $image:$curTag + retry 5 docker push $image:$curTag + done + docker logout +} + +function retry { + local -r -i max="$1"; shift + local -i n=1 + until "$@" + do + if ((n==max)) + then + echo "fail with $n times try..." + return 1 + else + echo "failed, trying again in $n seconds..." + sleep $((n++)) + fi + done +} \ No newline at end of file