Skip to content

Commit

Permalink
Updated release and development flow to be automated
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Jul 31, 2013
1 parent a937ada commit 7f5806d
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 21 deletions.
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ python:
- "pypy"
- "3.3"

script: python setup.py test
install:
- pip install --editable .

script: make test

notifications:
email: false
Expand Down
31 changes: 19 additions & 12 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,53 +1,60 @@
Changelog
---------
=========

Here you can see the full list of changes between each Flask-SQLAlchemy
release.

Version 1.1
-----------

(Release date to be decided, codename to be selected)

Version 1.0
```````````
-----------

(Released on July 20th 2013, no codename)

- Added Python 3.3 support.
- Dropped 2.5 compatibility.
- Various bugfixes
- Changed versioning format to do major releases for each update now.

Version 0.16
````````````
------------

- New distribution format (flask_sqlalchemy)
- Added support for Flask 0.9 specifics.

Version 0.15
````````````
------------

- Added session support for multiple databases

Version 0.14
````````````
------------

- Make relative sqlite paths relative to the application root.

Version 0.13
````````````
------------

- Fixed an issue with Flask-SQLAlchemy not selecting the correct binds.

Version 0.12
````````````
------------
- Added support for multiple databases.
- Expose Flask-SQLAlchemy's BaseQuery as `db.Query`.
- Set default query_class for `db.relation`, `db.relationship`, and
`db.dynamic_loader` to Flask-SQLAlchemy's BaseQuery.
- Improved compatibility with Flask 0.7.

Version 0.11
````````````
------------

- Fixed a bug introduced in 0.10 with alternative table constructors.

Version 0.10
````````````
------------

- Added support for signals.
- Table names are now automatically set from the class name unless
Expand All @@ -61,18 +68,18 @@ Version 0.10
This makes it possible to omit the metadata.

Version 0.9
```````````
-----------

- applied changes to pass the Flask extension approval process.

Version 0.8
```````````
-----------

- added a few configuration keys for creating connections.
- automatically activate connection recycling for MySQL connections.
- added support for the Flask testing mode.

Version 0.7
```````````
-----------

- Initial public release
23 changes: 22 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,25 @@
all: test

test:
python setup.py test
@python test_sqlalchemy.py

clean: clean-pyc

clean-pyc:
@find . -name '*.pyc' -exec rm {} \;
@find . -name '__pycache__' -type d | xargs rm -rf

develop:
@pip install --editable .

release:
@python scripts/make-release.py

tox-test:
@tox

upload-docs:
$(MAKE) -C docs html
python setup.py upload-docs

.PHONY: test release all clean clean-pyc develop tox-test upload-docs
3 changes: 3 additions & 0 deletions flask_sqlalchemy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
_app_ctx_stack = None


__version__ = '1.1-dev'


# Which stack should we use? _app_ctx_stack is new in 0.9
connection_stack = _app_ctx_stack or _request_ctx_stack

Expand Down
154 changes: 154 additions & 0 deletions scripts/make-release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
make-release
~~~~~~~~~~~~
Helper script that performs a release. Does pretty much everything
automatically for us.
:copyright: (c) 2013 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import sys
import os
import re
from datetime import datetime, date
from subprocess import Popen, PIPE

_date_clean_re = re.compile(r'(\d+)(st|nd|rd|th)')


def parse_changelog():
with open('CHANGES') as f:
lineiter = iter(f)
for line in lineiter:
match = re.search('^Version\s+(.*)', line.strip())
if match is None:
continue
length = len(match.group(1))
version = match.group(1).strip()
if lineiter.next().count('-') != len(match.group(0)):
continue
while 1:
change_info = lineiter.next().strip()
if change_info:
break

match = re.search(r'released on (\w+\s+\d+\w+\s+\d+)'
r'(?:, codename (.*))?(?i)', change_info)
if match is None:
continue

datestr, codename = match.groups()
return version, parse_date(datestr), codename


def bump_version(version):
try:
parts = map(int, version.split('.'))
except ValueError:
fail('Current version is not numeric')
if parts[-1] != 0:
parts[-1] += 1
else:
parts[0] += 1
return '.'.join(map(str, parts))


def parse_date(string):
string = _date_clean_re.sub(r'\1', string)
return datetime.strptime(string, '%B %d %Y')


def set_filename_version(filename, version_number, pattern):
changed = []
def inject_version(match):
before, old, after = match.groups()
changed.append(True)
return before + version_number + after
with open(filename) as f:
contents = re.sub(r"^(\s*%s\s*=\s*')(.+?)(')(?sm)" % pattern,
inject_version, f.read())

if not changed:
fail('Could not find %s in %s', pattern, filename)

with open(filename, 'w') as f:
f.write(contents)


def set_init_version(version):
info('Setting __init__.py version to %s', version)
set_filename_version('flask_sqlalchemy/__init__.py', version, '__version__')


def set_setup_version(version):
info('Setting setup.py version to %s', version)
set_filename_version('setup.py', version, 'version')


def build_and_upload():
Popen([sys.executable, 'setup.py', 'release', 'sdist', 'upload']).wait()


def fail(message, *args):
print >> sys.stderr, 'Error:', message % args
sys.exit(1)


def info(message, *args):
print >> sys.stderr, message % args


def get_git_tags():
return set(Popen(['git', 'tag'], stdout=PIPE).communicate()[0].splitlines())


def git_is_clean():
return Popen(['git', 'diff', '--quiet']).wait() == 0


def make_git_commit(message, *args):
message = message % args
Popen(['git', 'commit', '-am', message]).wait()


def make_git_tag(tag):
info('Tagging "%s"', tag)
Popen(['git', 'tag', tag]).wait()


def main():
os.chdir(os.path.join(os.path.dirname(__file__), '..'))

rv = parse_changelog()
if rv is None:
fail('Could not parse changelog')

version, release_date, codename = rv
dev_version = bump_version(version) + '-dev'

info('Releasing %s (codename %s, release date %s)',
version, codename, release_date.strftime('%d/%m/%Y'))
tags = get_git_tags()

if version in tags:
fail('Version "%s" is already tagged', version)
if release_date.date() != date.today():
fail('Release date is not today (%s != %s)')

if not git_is_clean():
fail('You have uncommitted changes in git')

set_init_version(version)
set_setup_version(version)
make_git_commit('Bump version number to %s', version)
make_git_tag(version)
build_and_upload()
set_init_version(dev_version)
set_setup_version(dev_version)


if __name__ == '__main__':
main()
13 changes: 7 additions & 6 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[build_sphinx]
source-dir = docs/
build-dir = docs/_build
all_files = 1
[egg_info]
tag_date = true

[upload_docs]
upload-dir = docs/_build/html
[aliases]
release = egg_info -RDb ''

[pytest]
norecursedirs = .* _* scripts {args}
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

setup(
name='Flask-SQLAlchemy',
version='1.0',
version='1.1-dev',
url='http://github.com/mitsuhiko/flask-sqlalchemy',
license='BSD',
author='Armin Ronacher',
Expand Down

0 comments on commit 7f5806d

Please sign in to comment.