From 3f817864d6227e2b0c2c16271cb15114eb35bdf4 Mon Sep 17 00:00:00 2001 From: "Sean T. Allen" Date: Sun, 1 Sep 2019 17:04:20 -0400 Subject: [PATCH] Add automated release process --- .ci-scripts/documentation.bash | 89 +++++++++++++++++ .ci-scripts/env.bash | 8 ++ .ci-scripts/install-dependencies.bash | 3 +- .ci-scripts/release.bash | 135 ++++++++++++++++++++++++++ .circleci/config.yml | 66 ++++++++++--- CONTRIBUTING.md | 25 ++--- Makefile | 18 +++- RELEASE_PROCESS.md | 54 +++-------- STYLE_GUIDE.md | 2 +- release.bash | 97 ------------------ 10 files changed, 320 insertions(+), 177 deletions(-) create mode 100644 .ci-scripts/documentation.bash create mode 100644 .ci-scripts/env.bash create mode 100644 .ci-scripts/release.bash mode change 100755 => 100644 RELEASE_PROCESS.md mode change 100755 => 100644 STYLE_GUIDE.md delete mode 100755 release.bash diff --git a/.ci-scripts/documentation.bash b/.ci-scripts/documentation.bash new file mode 100644 index 0000000..c2d9503 --- /dev/null +++ b/.ci-scripts/documentation.bash @@ -0,0 +1,89 @@ +#!/bin/bash + +set -o errexit +set -o nounset + +base=$(dirname "$0") +source "${base}/env.bash" + +# Gather expected arguments. +if [ $# -lt 2 ] +then + echo "Tag and GH personal access token are required" + exit 1 +fi + +# Directory we are going to do additional work in +GEN_MD="$(mktemp -d)" + +# From command line +TAG=$1 +GITHUB_TOKEN=$2 + +# Shouldn't need to touch these +BUILD_DIR="build/glob-docs" +DOCS_DIR="${GEN_MD}/glob/${TAG}" + +# Generated markdown repo +echo "Cloning main.actor-package-markdown repo into ${GEN_MD}" +git clone \ + "https://${GITHUB_TOKEN}@github.com/${REPO_OWNER}/main.actor-package-markdown.git" \ + "${GEN_MD}" + +# Make the docs +# We make assumptions about the location for the docs +make docs + +# $BUILD_DIR contains the raw generated markdown for our documentation +pushd "${BUILD_DIR}" || exit 1 +mkdir -p "${DOCS_DIR}" +cp -r docs/* "${DOCS_DIR}"/ +cp -r mkdocs.yml "${DOCS_DIR}" + +# Upload any new documentation +echo "Preparing to upload generated markdown content from ${GEN_MD}" +echo "Git fiddling commences..." +pushd "${GEN_MD}" || exit 1 +echo "Creating a branch for generated documentation..." +branch_name="glob-${TAG}" +git checkout -b "${branch_name}" +echo "Adding content..." +git add . +git commit -m "Add docs for package: glob version: ${TAG}" +echo "Uploading new generated markdown content..." +git push --set-upstream origin "${branch_name}" +echo "Generated markdown content has been uploaded!" +popd || exit 1 + +# Create a PR +echo "Preparing to create a pull request..." +jsontemplate=" +{ + \"title\":\$title, + \"head\":\$incoming_repo_and_branch, + \"base\":\"master\" +} +" + +json=$(jq -n \ +--arg title "glob ${TAG}" \ +--arg incoming_repo_and_branch "${REPO_OWNER}:${branch_name}" \ +"${jsontemplate}") + + +echo "Curling..." +result=$(curl -X POST \ + https://api.github.com/repos/ponylang/main.actor-package-markdown/pulls \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -u "${GITHUB_USER}:${GITHUB_TOKEN}" \ + --data "${json}") + +rslt_scan=$(echo "${result}" | jq -r '.id') +if [ "$rslt_scan" != null ] +then + echo "PR successfully created!" +else + echo "Unable to create PR, here's the curl output..." + echo "${result}" + exit 1 +fi diff --git a/.ci-scripts/env.bash b/.ci-scripts/env.bash new file mode 100644 index 0000000..5467526 --- /dev/null +++ b/.ci-scripts/env.bash @@ -0,0 +1,8 @@ +REPO_OWNER="ponylang" +REPO_NAME="glob" +GITHUB_USER="ponylang-main" + +# Who we are for git +git config --global user.email "ponylang.main@gmail.com" +git config --global user.name "Main" +git config --global push.default simple diff --git a/.ci-scripts/install-dependencies.bash b/.ci-scripts/install-dependencies.bash index 25fe0db..9591efa 100755 --- a/.ci-scripts/install-dependencies.bash +++ b/.ci-scripts/install-dependencies.bash @@ -1,6 +1,7 @@ #!/bin/bash -add-apt-repository ppa:ponylang/ponylang apt-get update apt-get install -y libpcre2-dev apt-get install -y pony-stable + +stable fetch diff --git a/.ci-scripts/release.bash b/.ci-scripts/release.bash new file mode 100644 index 0000000..4a7e6b2 --- /dev/null +++ b/.ci-scripts/release.bash @@ -0,0 +1,135 @@ +#!/bin/bash + +set -o errexit +set -o nounset + +base=$(dirname "$0") +source "${base}/env.bash" + +# Gather expected arguments. +if [ $# -lt 3 ] +then + echo "Tag, GH personal access token, and Ponylang zulip access token are required" + exit 1 +fi + +TAG=$1 +GITHUB_TOKEN=$2 +ZULIP_TOKEN=$3 +# changes tag from "release-1.0.0" to "1.0.0" +VERSION="${TAG/release-/}" + +### this doesn't account for master changing commit, assumes we are HEAD +# or can otherwise push without issue. that shouldl error out without issue. +# leaving us to restart from a different HEAD commit +# update CHANGELOG +changelog-tool release "${VERSION}" -e + +# commit CHANGELOG updates +git add CHANGELOG.md +git commit -m "Release ${VERSION}" + +# tag release +git tag "${VERSION}" + +# push to release to remote +git push origin HEAD:master "${VERSION}" + +# update CHANGELOG for new entries +changelog-tool unreleased -e + +# commit changelog and push to master +git add CHANGELOG.md +git commit -m "Add unreleased section to CHANGELOG post ${VERSION} release + +[skip ci]" +git push origin HEAD:master + +# release body +echo "Preparing to update GitHub release notes..." + +body=$(changelog-tool get "${VERSION}") + +jsontemplate=" +{ + \"tag_name\":\$version, + \"name\":\$version, + \"body\":\$body +} +" + +json=$(jq -n \ +--arg version "$VERSION" \ +--arg body "$body" \ +"${jsontemplate}") + +echo "Uploading release notes..." + +result=$(curl -X POST "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -u "${GITHUB_USER}:${GITHUB_TOKEN}" \ + --data "${json}") + +rslt_scan=$(echo "${result}" | jq -r '.id') +if [ "$rslt_scan" != null ] +then + echo "Release notes uploaded" +else + echo "Unable to upload release notes, here's the curl output..." + echo "${result}" + exit 1 +fi + +# Update Last Week in Pony +echo "Adding release to Last Week in Pony..." + +result=$(curl https://api.github.com/repos/ponylang/ponylang-website/issues?labels=last-week-in-pony) + +lwip_url=$(echo "${result}" | jq -r '.[].url') +if [ "$lwip_url" != "" ] +then + body=" +Version ${VERSION} of glob has been released. + +See the [release notes](https://github.com/ponylang/glob/releases/tag/${VERSION}) for more details. +" + + jsontemplate=" + { + \"body\":\$body + } + " + + json=$(jq -n \ + --arg body "$body" \ + "${jsontemplate}") + + result=$(curl -X POST "$lwip_url/comments" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -u "${GITHUB_USER}:${GITHUB_TOKEN}" \ + --data "${json}") + + rslt_scan=$(echo "${result}" | jq -r '.id') + if [ "$rslt_scan" != null ] + then + echo "Release notice posted to LWIP" + else + echo "Unable to post to LWIP, here's the curl output..." + echo "${result}" + fi +else + echo "Unable to post to Last Week in Pony. Can't find the issue." +fi + +message=" +Version ${VERSION} of glob has been released. + +See the [release notes](https://github.com/ponylang/glob/releases/tag/${VERSION}) for more details. +" + +curl -X POST https://ponylang.zulipchat.com/api/v1/messages \ + -u ${ZULIP_TOKEN} \ + -d "type=stream" \ + -d "to=announce" \ + -d "topic=glob" \ + -d "content=${message}" diff --git a/.circleci/config.yml b/.circleci/config.yml index 287e69a..a936e48 100755 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,25 +4,22 @@ orbs: zulip: ponylang/zulip@1 jobs: - release-vs-ponyc-release: + verify-changelog: docker: - - image: ponylang/ponyc:release + - image: ponylang/changelog-tool:release steps: - checkout - - run: bash .ci-scripts/install-dependencies.bash - - run: stable fetch - - run: make test config=release + - run: changelog-tool verify - zulip/status: fail_only: true - debug-vs-ponyc-release: + release-vs-ponyc-release: docker: - image: ponylang/ponyc:release steps: - checkout - run: bash .ci-scripts/install-dependencies.bash - - run: stable fetch - - run: make test config=debug + - run: make test config=release - zulip/status: fail_only: true @@ -32,34 +29,53 @@ jobs: steps: - checkout - run: bash .ci-scripts/install-dependencies.bash - - run: stable fetch - run: make test config=release - zulip/status: fail_only: true + debug-vs-ponyc-release: + docker: + - image: ponylang/ponyc:release + steps: + - checkout + - run: bash .ci-scripts/install-dependencies.bash + - run: make test config=debug + - zulip/status: + fail_only: true + debug-vs-ponyc-master: docker: - image: ponylang/ponyc:latest steps: - checkout - run: bash .ci-scripts/install-dependencies.bash - - run: stable fetch - run: make test config=debug - zulip/status: fail_only: true - verify-changelog: + cut-release: docker: - - image: ponylang/changelog-tool:release + - image: ponylang/shared-docker-ci-release-a-library:release steps: - checkout - - run: changelog-tool verify + - run: bash .ci-scripts/release.bash "$CIRCLE_TAG" "$GITHUB_TOKEN" "$ZULIP_RELEASE_ANNOUNCEMENT_TOKEN" + - zulip/status: + fail_only: true + + generate-documentation-pr-for-main-dot-actor: + docker: + - image: ponylang/shared-docker-ci-release-a-library:release + steps: + - checkout + - run: bash .ci-scripts/install-dependencies.bash + - run: bash .ci-scripts/documentation.bash "$CIRCLE_TAG" "$GITHUB_TOKEN" - zulip/status: fail_only: true workflows: version: 2.1 - commit: + + on-every-commit: jobs: - verify-changelog: context: org-global @@ -68,7 +84,27 @@ workflows: - debug-vs-ponyc-release: context: org-global - nightly: + create-release: + jobs: + - cut-release: + context: org-global + filters: + tags: + only: /^release-\d+\.\d+\.\d+$/ + branches: + ignore: /.*/ + + on-release-being-tagged: + jobs: + - generate-documentation-pr-for-main-dot-actor: + context: org-global + filters: + tags: + only: /^\d+\.\d+\.\d+$/ + branches: + ignore: /.*/ + + daily-check-for-breakage: triggers: - schedule: cron: "0 0 * * *" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 761b277..d6c3795 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,12 +12,7 @@ Additional notes regarding formatting: * [Documentation formatting](#documentation-formatting) * [Code formatting](#code-formatting) -* [File Naming](#standard-library-file-naming) - -## Feature request -For any feature requests or enhancements to the Pony distribution, it is quite likely that you have to go through our [RFC process](https://github.com/ponylang/rfcs). Before opening or submitting any feature requests, please make sure you are familiar with the RFC process and follow the process as required. - -If you submit a pull request to implement a new feature without going through the RFC process, it may be closed with a polite request to submit an RFC first. +* [File naming](#file-naming) ## Bug report @@ -33,17 +28,17 @@ Provide the following details: If possible, try to isolate the problem and provide just enough code to demonstrate it. Add any related information which might help to fix the issue. -## How to Contribute +## How to contribute This project uses a fairly standard GitHub pull request workflow. If you have already contributed to a project via GitHub pull request, you can skip this section and proceed to the [specific details of what we ask for in a pull request](#pull-request). If this is your first time contributing to a project via GitHub, read on. Here is the basic GitHub workflow: -1. Fork this repo. you can do this via the GitHub website. This will result in you having your own copy of the repo under your GitHub account. +1. Fork this repo. you can do this via the GitHub website. This will result in you having your own copy of the repo under your GitHub account. 2. Clone your forked repo to your local machine 3. Make a branch for your change 4. Make your change on that branch -5. Push your change to your repo +5. Push your change to your repo 6. Use the github ui to open a PR Some things to note that aren't immediately obvious to folks just starting out: @@ -52,9 +47,7 @@ Some things to note that aren't immediately obvious to folks just starting out: 2. Any changes you make on your branch that you used for one PR will automatically appear in another PR so if you have more than 1 PR, be sure to always create different branches for them. 3. Weird things happen with commit history if you don't create your PR branches off of `master` so always make sure you have the `master` branch checked out before creating a branch for a PR -If you feel overwhelmed at any point, don't worry, it can be a lot to learn when you get started. You can usually find me on the [Pony Slack](https://www.ponylang.io/get-slack-invite) if you need help. - -You can get help using GitHub via [the official documentation](https://help.github.com/). Some hightlights include: +You can get help using GitHub via [the official documentation](https://help.github.com/). Some highlights include: - [Fork A Repo](https://help.github.com/articles/fork-a-repo/) - [Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) @@ -83,19 +76,19 @@ Documentation is not "source code." As such, it should not be wrapped at 80 colu All code examples in documentation should be formatted in a fashion appropriate to the language in question. -All command line examples in documentation should be presented in a copy and paste friendly fashion. Assume the user is using the `bash` shell. GitHub formatting on long command lines can be unfriendly to copy-and-paste. Long command lines should be broken up using `\` so that each line is no more than 80 columns. Wrapping at 80 columns should result in a good display experience in GitHub. Additionally, continuation lines should be indented two spaces. +All command line examples in documentation should be presented in a copy and paste friendly fashion. Assume the user is using the `bash` shell. GitHub formatting on long command lines can be unfriendly to copy-and-paste. Long command lines should be broken up using `\` so that each line is no more than 80 columns. Wrapping at 80 columns should result in a good display experience in GitHub. Additionally, continuation lines should be indented two spaces. OK: ```bash -my_command --some-option foo --path-to-file ../../wallaroo/long/line/foo \ +my_command --some-option foo --path-to-file ../../project/long/line/foo \ --some-other-option bar ``` Not OK: ```bash -my_command --some-option foo --path-to-file ../../wallaroo/long/line/foo --some-other-option bar +my_command --some-option foo --path-to-file ../../project/long/line/foo --some-other-option bar ``` Wherever possible when writing documentation, favor full command options rather than short versions. Full flags are usually much easier to modify because the meaning is clearer. @@ -136,6 +129,6 @@ The details: All Pony sources should follow the [Pony standard library style guide](https://github.com/ponylang/ponyc/blob/master/STYLE_GUIDE.md). -## File naming +## File naming Pony code follows the [Pony standard library file naming guidelines](https://github.com/ponylang/ponyc/blob/master/STYLE_GUIDE.md#naming). diff --git a/Makefile b/Makefile index 698a23a..dd87076 100755 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ config ?= release +PACKAGE := glob +COMPILE_WITH := stable env ponyc + BUILD_DIR ?= build/$(config) -SRC_DIR ?= glob -tests_binary := $(BUILD_DIR)/glob +SRC_DIR ?= $(PACKAGE) +tests_binary := $(BUILD_DIR)/$(PACKAGE) +docs_dir := build/$(PACKAGE)-docs ifdef config ifeq (,$(filter $(config),debug release)) @@ -11,9 +15,9 @@ ifdef config endif ifeq ($(config),release) - PONYC = stable env ponyc + PONYC = ${COMPILE_WITH} else - PONYC = stable env ponyc --debug + PONYC = ${COMPILE_WITH} --debug endif SOURCE_FILES := $(shell find $(SRC_DIR) -name \*.pony) @@ -35,6 +39,12 @@ clean: realclean: rm -rf build +$(docs_dir): $(GEN_FILES) $(SOURCE_FILES) + rm -rf $(docs_dir) + ${PONYC} --docs-public --pass=docs --output build $(SRC_DIR) + +docs: $(docs_dir) + TAGS: ctags --recurse=yes $(SRC_DIR) diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md old mode 100755 new mode 100644 index 9a45cff..20a818d --- a/RELEASE_PROCESS.md +++ b/RELEASE_PROCESS.md @@ -1,59 +1,27 @@ -# How to cut a {REPO} release +# How to cut a glob release This document is aimed at members of the Pony team who might be cutting a release of Pony. It serves as a checklist that can take you through doing a release step-by-step. -## Prerequisites for doing any release +## Prerequisites -In order to do a release, you absolutely must have: - -* Commit access to the `{REPO}` repo -* Version 0.3.x of the [changelog tool](https://github.com/ponylang/changelog-tool/releases) installed -* [git](https://git-scm.com/), [cURL](https://curl.haxx.se/), and [jq](https://stedolan.github.io/jq/) installed -* An account on the [Pony Zulip](https://ponylang.zulipchat.com) - -## Prerequisites for specific releases - -Before getting started, you will need a number for the version that you will be releasing as well as an agreed upon "golden commit" that will form the basis of the release. +You must have commit access to the glob repository ## Releasing -Please note that the release script was written with the assumption that you are using a clone of the `{REPO}` repo. You have to be using a clone rather than a fork. Further, due to how git works, you need to make sure that both your `master` branch is up-to-date. It is advised to your do this but making a fresh clone of the `{REPO}` repo from which you will release. For example: +Please note that this document was written with the assumption that you are using a clone of the `glob` repo. You have to be using a clone rather than a fork. It is advised to your do this by making a fresh clone of the `glob` repo from which you will release. ```bash -git clone git@github.com:{USERNAME}/{REPO}.git {REPO}-release-clean -cd {REPO}-release-clean +git clone git@github.com:ponylang/glob.git glob-release-clean +cd glob-release-clean ``` -Any commit is eligible to be a "golden commit" so long as it has passed all CI checks. However, the normal case for the release tool that you will use assumes you will use a "golden commit" that is the most recent change to the `master` branch of {REPO}. If you deviate from that expectation, then some manual intervention might be required for you to continue the release process. Once manual intervention is involved, there is no way to restart the automated process and you'll have to do each of the steps in the release script by hand. - -For the duration of this document, we will pretend the "golden commit" version is `8a8ee28` and the version is `0.3.1`. Any place you see those values, please substitute your own version. +Before getting started, you will need a number for the version that you will be releasing as well as an agreed upon "golden commit" that will form the basis of the release. -You also need your GitHub user name and a GitHub personal access token. In the example below, the GitHub username is `seantallen` and the personal access token is `9999998gk48888ddd78a9fd12345a12870987uk`. +The "golden commit" must be `HEAD` on the `master` branch of this repository. At this time, releasing from any other location is not supported. -With that in mind, run the release script: +For the duration of this document, that we are releasing version is `0.3.1`. Any place you see those values, please substitute your own version. ```bash -bash release.bash seantallen 9999998gk48888ddd78a9fd12345a12870987uk \ - 0.3.1 8a8ee28 -``` - -### Get release notes URL - -Navigate to the GitHub page for the release you just created. It will be something like: - -``` -https://github.com/{USERNAME}/{REPO}/releases/tag/0.3.1 +git tag release-0.3.1 +git push origin release-0.3.1 ``` - -Copy the url to the page. You'll need it for the next two steps. - -### Inform the Pony Zulip - -Once you have the URL for the release notes, drop a note in the [#announce stream](https://ponylang.zulipchat.com/#narrow/stream/189932-announce) with a topic like "{REPO} 0.3.1 has been released" of the Pony Zulip letting everyone know that the release is out and include a link the release notes. - -If this is an "emergency release" that is designed to get a high priority bug fix out, be sure to note that everyone is advised to update ASAP. - -### Add to "Last Week in Pony" - -Last Week in Pony is the Pony community's weekly newsletter. Add information about the release, including a link to the release notes, to the [current Last Week in Pony](https://github.com/ponylang/ponylang.github.io/issues?q=is%3Aissue+is%3Aopen+label%3Alast-week-in-pony). - diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md old mode 100755 new mode 100644 index e75b5f0..ee877d2 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -1,3 +1,3 @@ # Style Guide -{REPO} follows the [Pony standard library Style Guide](https://github.com/ponylang/ponyc/blob/master/STYLE_GUIDE.md). +glob follows the [Pony standard library Style Guide](https://github.com/ponylang/ponyc/blob/master/STYLE_GUIDE.md). diff --git a/release.bash b/release.bash deleted file mode 100755 index 966683b..0000000 --- a/release.bash +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset - -USERNAME=ponylang -REPONAME=glob - -verify_args() { - echo "Cutting a release for version $version with commit $commit" - while true; do - read -rp "Is this correct (y/n)?" yn - case $yn in - [Yy]*) break;; - [Nn]*) exit;; - *) echo "Please answer y or n.";; - esac - done -} - -if [ $# -le 3 ]; then - echo "GH username, GH personal access token, version, commit arguments required" -fi - -set -eu -ghuser=$1 -ghtoken=$2 -version=$3 -commit=$4 - -verify_args - -# create version release branch -git checkout master -git pull -if ! git diff --exit-code master origin/master -then - echo "ERROR! There are local-only changes on branch 'master'!" - exit 1 -fi -git checkout -b "release-$version" "$commit" - -# update CHANGELOG -changelog-tool release "$version" -e - -# commit CHANGELOG updates -git add CHANGELOG.md -git commit -m "Prep for $version release - -[skip ci]" - -# merge into master -git checkout master -if ! git diff --exit-code master origin/master -then - echo "ERROR! There are local-only changes on branch 'master'!" - exit 1 -fi -git merge "release-$version" -m "Release $version" - -# tag release -git tag "$version" - -# push to release to remote -git push origin master -git push origin "$version" - -# update CHANGELOG for new entries -changelog-tool unreleased -e - -# commit changelog and push to master -git add CHANGELOG.md -git commit -m "Add unreleased section to CHANGELOG post $version release prep - -[skip ci]" -git push origin master - -# release body -body=$(changelog-tool get "${version}") - -jsontemplate=" -{ - \"tag_name\":\$version, - \"name\":\$version, - \"body\":\$body -} -" - -json=$(jq -n \ ---arg version "$version" \ ---arg body "$body" \ -"${jsontemplate}") - -curl -X POST "https://api.github.com/repos/${USERNAME}/${REPO}/releases" \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -u "${ghuser}:${ghtoken}" \ - --data "${json}"