Skip to content

Commit

Permalink
chore: Automate releases. (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
Luke Sneeringer authored Oct 6, 2020
1 parent 26f9c06 commit 651c79f
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 4 deletions.
90 changes: 90 additions & 0 deletions .github/release_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import collections
import subprocess
import sys
import typing


class Changelog:
def __init__(self, git_log: str):
self._commits = {}
for commit in git_log.split('\n'):
# Spilt the type from the message.
type_ = 'other'
message = commit
if ':' in message:
type_, message = commit.split(':', 1)

# If the change is breaking, note it separately.
if type_.endswith('!'):
type_ = 'breaking'

# Add the commit to the appropriate bucket.
self._commits.setdefault(type_, [])
self._commits[type_].append(message.strip())

@property
def markdown(self):
"""Return the changelog Markdown for the GitHub release."""
answer = ''
headers = collections.OrderedDict((
('breaking', 'Breaking Changes'),
('feat', 'Features'),
('fix', 'Bugfixes'),
('refactor', 'Refactors'),
('docs', 'Documentation'),
))
for key, header in headers.items():
if key in self._commits:
answer += f'## {header}\n\n'
for cmt in self._commits[key]:
answer += f'- {cmt}\n'
answer += '\n'
return answer.strip()


def exec(cmd: typing.List[str]) -> str:
"""Execute the given command and return the output.
If the command returns a non-zero exit status, fail loudly and exit.
"""
proc = subprocess.run(cmd, capture_output=True, text=True)
if proc.returncode != 0:
print(f'Error running {cmd[0]}: {proc.stderr}', file=sys.stderr)
sys.exit(proc.returncode)
return proc.stdout.strip()


if __name__ == '__main__':
# Get the previous tag and the current tag.
revs = exec(['git', 'rev-list', '--simplify-by-decoration',
'--tags', '--max-count=2']).split('\n')
new_tag, prev_tag = (exec(['git', 'describe', '--tags', r]) for r in revs)
commit_range = f'{prev_tag}..{new_tag}'
if len(sys.argv) > 1:
commit_range = sys.argv[1]

# Get the changelog between those two tags.
cl = Changelog(exec(['git', 'log', commit_range,
'--oneline', '--pretty=format:%s']))

# Print the Markdown using GitHub's special syntax.
#
# Note: %0A must be used for newline.
# https://github.community/t/set-output-truncates-multiline-strings/16852
print('::set-output name=release_notes::{rel_notes}'.format(
rel_notes=cl.markdown.replace('\n', '%0A')
))
60 changes: 60 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
name: release
on:
push:
tags: v[0-9]+.[0-9]+.[0-9]+
jobs:
inspect:
runs-on: ubuntu-latest
container: python:3.8
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Get the version from the tag.
id: get_version
run: echo ::set-output name=version::${GITHUB_REF:11}
shell: bash
- name: Get the release notes from the previous release to this one.
id: release_tool
run: python ./.github/release_notes.py
outputs:
version: ${{ steps.get_version.outputs.version }}
release_notes: ${{ steps.release_tool.outputs.release_notes }}
github_release:
runs-on: ubuntu-latest
needs: inspect
steps:
- name: Create the GitHub release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tag_name: v${{ needs.inspect.outputs.version }}
release_name: aip-site-generator ${{ needs.inspect.outputs.version }}
body: ${{ needs.inspect.outputs.release_notes }}
draft: false
prerelease: false
pypi_release:
runs-on: ubuntu-latest
container: python:3.8
needs:
- inspect
- github_release
steps:
- uses: actions/checkout@v2
- name: Install twine.
run: pip install twine
- name: Set the version number.
run: |
cat > VERSION <<EOF
${{ needs.inspect.outputs.version }}
EOF
- name: Create a source distribution.
run: python setup.py sdist
- name: Upload to PyPI.
run: twine upload dist/*
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
TWINE_NON_INTERACTIVE: 1
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
include README.md CONTRIBUTING.md LICENSE
include README.md CONTRIBUTING.md LICENSE VERSION
recursive-include aip_site/support *
global-exclude *.py[co]
global-exclude __pycache__
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# aip.dev static site generator

Welcome to our NIH static site generator.
This is the site generator for [aip.dev](https://aip.dev) and its forks. It
takes AIP files in a git repository and outputs a static website.

## Why?

We are not fans of rolling our own tools when off-the-shelf alternatives exist.
However, the AIP project has grown sufficiently mature to warrant it.

GitHub Pages normally automatically builds documentation with [Jekyll][], but
as the AIP system has grown, we are beginning to reach the limits of what
Expand All @@ -26,8 +28,10 @@ There are some additional advantages that we unlock with a custom generator:
rather than modifying existing files.
- We can provide useful abstractions for common deviations between companies
(e.g. case systems) that minimize the need to fork AIPs.
- We can customize the Markdown parsing where necessary (tabs, hotlinking,
etc.).

## Grumble. Fine. How does it work?
## How does it work?

This is essentially split into three parts:

Expand Down
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dev
11 changes: 10 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import io
import os

from setuptools import find_packages, setup # type: ignore


PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__))

with io.open(os.path.join(PACKAGE_ROOT, 'VERSION'), 'r') as version_file:
VERSION = version_file.read().strip()

with io.open(os.path.join(PACKAGE_ROOT, 'README.md'), 'r') as readme_file:
long_description = readme_file.read().strip()

setup(
name='aip-site-generator',
version='0.3.0',
version=VERSION,
license='Apache 2.0',
author='Luke Sneeringer',
author_email='[email protected]',
url='https://github.com/aip-dev/site-generator.git',
packages=find_packages(exclude=['tests']),
description='Static site generator for aip.dev and forks.',
long_description=long_description,
long_description_content_type='text/markdown',
entry_points="""[console_scripts]
aip-site-gen=aip_site.cli:publish
aip-site-serve=aip_site.cli:serve
Expand Down

0 comments on commit 651c79f

Please sign in to comment.