diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..7e3a758ae --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,65 @@ +name: Publish release + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: + inputs: + tag: + description: Existing tag to publish a release for + required: true + type: string + +permissions: {} + +jobs: + release: + name: Create GitHub release + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Resolve tag + id: tag + env: + INPUT_TAG: ${{ inputs.tag }} + REF_NAME: ${{ github.ref_name }} + run: | + if [ -n "${INPUT_TAG}" ]; then + echo "tag=${INPUT_TAG}" >> "$GITHUB_OUTPUT" + else + echo "tag=${REF_NAME}" >> "$GITHUB_OUTPUT" + fi + + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + ref: ${{ steps.tag.outputs.tag }} + fetch-depth: 0 + fetch-tags: true + persist-credentials: false + + - name: Build release notes + env: + TAG: ${{ steps.tag.outputs.tag }} + run: bash ci/release-notes.sh "${TAG}" > "${RUNNER_TEMP}/notes.md" + + - name: Create release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.tag.outputs.tag }} + run: | + if gh release view "${TAG}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1 + then + echo "release ${TAG} already exists, leaving it alone" + exit 0 + fi + + gh release create "${TAG}" \ + --repo "${GITHUB_REPOSITORY}" \ + --title "${TAG}" \ + --notes-file "${RUNNER_TEMP}/notes.md" \ + --verify-tag diff --git a/.github/workflows/run-tests-tiered.yml b/.github/workflows/run-tests-tiered.yml index bfc1e0614..9378ba5f9 100644 --- a/.github/workflows/run-tests-tiered.yml +++ b/.github/workflows/run-tests-tiered.yml @@ -55,6 +55,11 @@ jobs: - name: Lint Markdown run: make lint-docs + - name: Check the changelog covers the current version + run: | + version=$(grep '^DEF_VER=' GIT-VERSION-GEN | cut -d= -f2) + bash ci/release-notes.sh "v${version}" > /dev/null + - name: Set Version String From .git run: make version diff --git a/Makefile b/Makefile index 848d0d840..64645a89e 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,9 @@ check-docs: lint-docs: $(DOCKER) run --rm -v "$(CURDIR)":/workdir $(MARKDOWNLINT) +release-notes: + @bash ./ci/release-notes.sh $(TAG) + test: build $(MAKE) -C tests all @@ -81,7 +84,7 @@ debsh-qa: deb-qa $(DOCKER) run --rm -it pgcopydb_debian_qa bash .PHONY: all -.PHONY: bin clean install maintainer-clean update-docs lint-docs +.PHONY: bin clean install maintainer-clean update-docs lint-docs release-notes .PHONY: test tests tests/ci tests/* .PHONY: deb debsh deb-qa debsh-qa .PHONY: GIT-VERSION-FILE diff --git a/ci/release-notes.sh b/ci/release-notes.sh new file mode 100755 index 000000000..3d0d8bb86 --- /dev/null +++ b/ci/release-notes.sh @@ -0,0 +1,73 @@ +#! /bin/bash + +set -e +set -u +set -o pipefail + +if [ $# -ne 1 ]; then + echo "usage: $0 " >&2 + echo "example: $0 v0.20.0" >&2 + exit 64 +fi + +TAG="$1" +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +CHANGELOG="${SCRIPT_DIR}/../CHANGELOG.md" +REPO_URL="https://github.com/planetscale/pgcopydb" + +if [ ! -f "${CHANGELOG}" ]; then + echo "error: ${CHANGELOG} not found" >&2 + exit 1 +fi + +VERSION="${TAG#v}" +SHORT="$(echo "${VERSION}" | cut -d. -f1,2)" + +section() { + local want="$1" + + awk -v want="${want}" ' + /^### pgcopydb v/ { + if (found) { exit } + split($0, f, " ") + if (f[3] == want) { found = 1; next } + } + found { print } + ' "${CHANGELOG}" +} + +BODY="$(section "v${VERSION}")" + +if [ -z "${BODY}" ]; then + BODY="$(section "v${SHORT}")" +fi + +if [ -z "${BODY}" ]; then + echo "error: CHANGELOG.md has no section for v${VERSION} or v${SHORT}" >&2 + echo "add one before tagging, the release notes come from it" >&2 + exit 1 +fi + +PREVIOUS="" + +if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then + PREVIOUS="$(git tag --sort=-v:refname --list 'v[0-9]*' | + grep -A1 -x -- "${TAG}" | tail -n +2 | head -1 || true)" +fi + +{ + printf '%s\n' "${BODY}" | + awk ' + /^### / { sub(/^### /, "## "); sub(/[ \t]*#+[ \t]*$/, "") } + /^\* / { sub(/^\* /, "- ") } + { print } + ' | + awk 'BEGIN { blank = 1 } + NF == 0 { if (!blank) { print }; blank = 1; next } + { print; blank = 0 }' + + if [ -n "${PREVIOUS}" ]; then + printf '\n**Full changelog:** %s/compare/%s...%s\n' \ + "${REPO_URL}" "${PREVIOUS}" "${TAG}" + fi +}