rel-eng/gem_release.ipynb
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Release of apipie-rails gem\n",
"\n",
"### Requirements\n",
"- push access to https://github.com/Apipie/apipie-rails\n",
"- push access to rubygems.org for apipie-rails\n",
"- sudo yum install python-slugify asciidoc\n",
"- ensure neither the `git push` or `gem push` don't require interactive auth. If you can't use api key or ssh key to auth skip these steps and run them form the shell manually\n",
"- ensure all checks have passed on the branch you're about to release\n",
"\n",
"### Release process\n",
"- Follow the steps with `<Shift>+<Enter>` or `<Ctrl>+<Enter>,<Down>`\n",
"- If anything fails, fix it and re-run the step if applicable\n",
"\n",
"### Release settings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%autosave 0"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%cd .."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Update the following notebook settings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"NEW_VERSION = '0.5.20'\n",
"LAST_VERSION = '0.5.19'\n",
"GIT_REMOTE_UPSTREAM = 'origin'\n",
"STABLE_RELEASE = False\n",
"WORK_BRANCH = 'stable' if STABLE_RELEASE else 'master'\n",
"# Array of strings, e.g. [\"21cbsc214g3\", \"21casc214g3\"]\n",
"CHERRY_PICKS = []\n",
"GEMFILE='Gemfile.rails61'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ensure the repo is up to date"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! git checkout {WORK_BRANCH}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! git fetch {GIT_REMOTE_UPSTREAM}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! git rebase {GIT_REMOTE_UPSTREAM}/{WORK_BRANCH}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cherry picks for stable release"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"if STABLE_RELEASE:\n",
" for cp in CHERRY_PICKS:\n",
" ! git cherry-pick -x {cp}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Run tests locally if your setup allows, otherwise ensure the HEAD is green"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! BUNDLE_GEMFILE=gemfiles/{GEMFILE} bundle update"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"! BUNDLE_GEMFILE=gemfiles/{GEMFILE} bundle exec rspec"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Update release related stuff"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! sed -i 's/VERSION = .*/VERSION = \"{NEW_VERSION}\"/' lib/apipie/version.rb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Parse git changelog\n",
"from IPython.display import Markdown as md\n",
"from subprocess import check_output\n",
"from shlex import split\n",
"import re\n",
"\n",
"def format_log_entry(entry):\n",
" author = re.search(r'author:(.*)', entry).group(1)\n",
" entry = re.sub(r'author:(.*)', '', entry)\n",
" entry = re.sub(r'([fF]ixes|[rR]efs)[^-]*-\\s*(.*)', r'\\2', entry)\n",
" entry = '* ' + entry.capitalize()\n",
" entry = re.sub(r'\\(#([0-9]+)\\)', r'[#\\1](https://github.com/Apipie/apipie-rails/pull/\\1)', entry)\n",
" entry = entry + f'({author})'\n",
" return entry\n",
"\n",
"def skip(entry):\n",
" if re.match(r'Merge pull', entry) or \\\n",
" re.match(r'^i18n', entry) or \\\n",
" re.match(r'^Bump to version', entry):\n",
" return True\n",
" else:\n",
" return False \n",
"git_log_cmd = 'git log --pretty=format:\"%%s author:%%an\" v%s..HEAD' % LAST_VERSION\n",
"log = check_output(split(git_log_cmd)).decode('utf8').split('\\n')\n",
"change_log = [format_log_entry(e) for e in log if not skip(e)]\n",
"md('\\n'.join(change_log))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Write release notes\n",
"from datetime import datetime\n",
"import fileinput\n",
"import sys\n",
"\n",
"fh = fileinput.input('CHANGELOG.md', inplace=True) \n",
"for line in fh: \n",
" print(line.rstrip())\n",
" if re.match(r'========', line):\n",
" print('## [v%s](https://github.com/Apipie/apipie-rails/tree/v%s) (%s)' % (NEW_VERSION, NEW_VERSION, datetime.today().strftime('%Y-%m-%d')))\n",
" print('[Full Changelog](https://github.com/Apipie/apipie-rails/compare/v%s...v%s)' % (LAST_VERSION, NEW_VERSION))\n",
" for entry in change_log:\n",
" print(entry)\n",
" print('')\n",
"fh.close() "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Manual step: Update deps in the gemspec if necessary"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Check what is going to be committed"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"! git add -u\n",
"! git status"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"! git diff --cached"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Commit changes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"! git commit -m \"Bump to {NEW_VERSION}\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tag new version"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! git tag {NEW_VERSION}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Build the gem"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! BUNDLE_GEMFILE=gemfiles/{GEMFILE} bundle exec rake build"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! gem push pkg/apipie-rails-{NEW_VERSION}.gem"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### PUSH the changes upstream If everything is correct"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! git push {GIT_REMOTE_UPSTREAM} {WORK_BRANCH}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! git push --tags {GIT_REMOTE_UPSTREAM} {WORK_BRANCH}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Now the new release is in upstream repo"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Some manual steps follow to improve the UX\n",
"\n",
"#### New release on GitHub\n",
"\n",
"Copy the following changelog lines to the description in form on link below\n",
"The release title is the new version."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('\\n')\n",
"print('\\n'.join(change_log))\n",
"print('\\n\\nhttps://github.com/Apipie/apipie-rails/releases/new?tag=%s' % NEW_VERSION)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Congratulations\n",
"\n",
"Release is public now."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}