Skip to content

Commit

Permalink
a whole swathe of release-automation improvements.
Browse files Browse the repository at this point in the history
Resolves: twisted#1668
Author: radix
Reviewer: exarkun


- Version objects now have a 'base' method, which only returns 
  major.minor.micro, never any SVN revision numbers.
- pb and vfs are now subprojects
- All versions in python code have been centralized to 
  <project>/_version.py. This file must contain a Version instance
  named 'version'.
- admin/change-versions updates _version.py files.
- subproject setup.py files no longer need to specify a version;
  it is extracted from their _version.py files.
- All of the functions in admin/change-versions have been moved
  to twisted.python.release, and most of them have had unit tests
  written for them.
- Project URLs in setup.py files have been updated to the new trac 
  locations.
- README files (including subproject and sumo) now include actual 
  version numbers, even in trunk.
- Most of the changes from warner's release branch are included in
  this one.
- setup.py and sumo-setup.py have been unified. Hooray!
- improved release-procedure.txt



git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@16792 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
  • Loading branch information
radix committed May 13, 2006
1 parent 32a137b commit 314e19a
Show file tree
Hide file tree
Showing 62 changed files with 551 additions and 387 deletions.
25 changes: 11 additions & 14 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@ higher. It can also work with ZopeX3 version 3.0.0c1 or higher.
For information about the Twisted split that happened before 2.0, see
http://twistedmatrix.com/products/splitfaq

This release of Twisted Sumo, constructed on SUMO-Date,
contains the following:

Twisted Core-SVN-Trunk
Twisted Conch Conch-SVN-Trunk
Twisted Flow Flow-SVN-Trunk
Twisted Lore Lore-SVN-Trunk
Twisted Mail Mail-SVN-Trunk
Twisted Names Names-SVN-Trunk
Twisted News News-SVN-Trunk
Twisted Pair Pair-SVN-Trunk
Twisted Runner Runner-SVN-Trunk
Twisted Web Web-SVN-Trunk
Twisted Words Words-SVN-Trunk
Twisted 2.2.0
Twisted Conch 0.6.0
Twisted Flow 0.1.0
Twisted Lore 0.1.0
Twisted Mail 0.2.0
Twisted Names 0.2.0
Twisted News 0.1.0
Twisted Pair 0.1.0
Twisted Runner 0.1.0
Twisted Web 0.5.0
Twisted Words 0.3.0
119 changes: 40 additions & 79 deletions admin/change-versions
Original file line number Diff line number Diff line change
Expand Up @@ -16,72 +16,19 @@ if string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') != -1:
sys.path.insert(0, os.curdir)
### end of preamble

import re
try:
# For platforms where this isn't automatic
import readline
except:
pass

from twisted.python import dist, reflect, release
from twisted.python import release
from os.path import join as opj
import time

class Project:
newVersionStr = None
initfile = None
name = None
pkgname = None
currentVersionStr = None
dir = None
def __init__(self, **kw):
self.__dict__.update(kw)


class Done(Exception):
pass


verstringMatcher = re.compile("^([0-9]+)\.([0-9]+)\.([0-9]+)$")
def inputNewVersion(project):
match = None
while match is None:
new_vers = raw_input("New version for %s? " % (project.name))
if not new_vers:
return None,None
if new_vers == 'done':
raise Done
match = verstringMatcher.match(new_vers)
if match is None:
print 'Invalid format. Use e.g. 2.0.0.'
major,minor,micro = match.groups()

major=int(major)
minor=int(minor)
micro=int(micro)
return new_vers, (major,minor,micro)


def gatherCurrentInfo():
projects = [Project(name='twisted', pkgname='twisted',
initfile='twisted/__init__.py',
dir='twisted')]
for pname in dist.twisted_subprojects:
dir = opj('twisted', pname)
pkgname = 'twisted.'+pname
currentVersionStr = reflect.namedModule(pkgname).__version__
projects.append(
Project(name=pname,
pkgname=pkgname,
dir=dir,
initfile=opj(dir, '__init__.py'),
currentVersionStr=currentVersionStr
)
)
return projects

def main():
projects = gatherCurrentInfo()
projects = release.gatherCurrentInfo()
print "== Current Versions =="
for proj in projects:
print "%s %s" % (proj.name.capitalize(), proj.currentVersionStr)
Expand All @@ -91,30 +38,36 @@ def main():
print "type 'done' when done"
for project in projects:
try:
project.newVersionStr = inputNewVersion(project)[0]
except Done:
input = release.inputNewVersion(project)
if input is not None:
project.newVersion = input

except release.Done:
break

## SVN-Trunk is always project-context-sensitive version number.
## Places where it shows up:
## We need to update README files and project _version.py files with
## version numbers. The _version.py files are easy; we can just
## rewrite them entirely, since they're only meant to contain the
## version assignment.

## README files, setup.py files, __init__.py files, twisted/copyright.py.
## The README files need to be string-replaced on special tags, like
## SVN-Trunk (for project-specific README files), Proj-SVN-Trunk (for
## Sumo README file).

## SUMO-Date is the date a sumo version was released. Proj-SVN-Trunk,
## where Proj is a capitalized Twisted subproject name or 'Core'. These
## only show up in the toplevel sumo README.

print "Modifying files..."
fatRepl = {'SUMO-Date': time.strftime('%Y-%m-%d')}
fatRepl = {}
for project in projects:
if project.name == 'twisted':
key = 'Core-SVN-Trunk'
else:
key = '%s-SVN-Trunk' % project.name.capitalize()
if project.newVersionStr:
val = project.newVersionStr
key = "%s %s" % (project.fullyQualifiedName(),
project.currentVersionStr)

if project.newVersion:
val = '.'.join(map(str, project.newVersion))
else:
val = project.currentVersionStr

val = "%s %s" % (project.fullyQualifiedName(), val)

fatRepl[key] = val
fatRepl = dict([(k, v) for k, v in fatRepl.items() if v != None])

Expand All @@ -125,16 +78,24 @@ def main():
return

for project in projects:
if not project.newVersionStr:
continue
print "|| Modifying %s's files." % project.pkgname
for fn in filter(os.path.exists, [project.initfile,
opj(project.dir, 'topfiles/README'),
opj(project.dir, 'topfiles/setup.py'),
opj(project.dir, 'copyright.py'),
]):
print "|| >> Modifying:", fn
release.replaceInFile(fn, {'SVN-Trunk': project.newVersionStr})
if project.newVersion:
release.replaceProjectVersion(project.versionfile,
project.newVersion)
readmefile = opj(project.dir, 'topfiles/README')
if os.path.exists(readmefile):
print "|| >> Modifying:", readmefile
if project.newVersion:
verstr = '.'.join(map(str, project.newVersion))
else:
verstr = project.currentVersionStr

key = "%s %s" % (project.fullyQualifiedName(),
project.currentVersionStr)

val = "%s %s" % (project.fullyQualifiedName(),
verstr)
release.replaceInFile(readmefile, {key: val})

if __name__=='__main__':
main()
34 changes: 21 additions & 13 deletions admin/release-procedure.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

2. svn up.

3. Write release notes in proj/topfiles/NEWS, including a date and a
version number.

4. Branch the repo to /branches/releases/<a.b>.x. That last 'x' is
3. Branch the repo to /branches/releases/<a.b>.x. That last 'x' is
literal.

5. Switch to that branch.
4. Switch to that branch.

5. Write release notes in proj/topfiles/NEWS, including a date and a
version number.

6. Run ./admin/change-versions. Specify the versions of whatever
you're releasing. Core should be versioned as release.major.minor,
Expand All @@ -33,32 +33,40 @@
svn cp -m 'Tagging for 0.2.0 release' $TREPO/branches/<a.b>.x \
$TREPO/tags/releases/<a.b.c>.

11. Distribute, announce, and so forth.
11. Merge the branch to trunk.

12. Distribute, announce, and so forth.


= RELEASING TWISTED SUMO =

1. From Twisted trunk WC, mkdir twistedballs
1. From Twisted trunk WC, mkdir twistedballs.

2. Put all current subproject tarballs into twistedballs
This step is REALLY tedious. Should figure out a better way to do this.
Just copy unchanged projects from the previous Twisted tarball.

3. Put ZopeInterface-*.tgz in twistedballs
3. Put ZopeInterface-*.tgz in twistedballs.

4. ./admin/change-versions, and make sure all the versions are
appropriately specified for the tarballs you've included.
4. ./admin/change-versions --sumo-only, and make sure all the versions
are appropriately specified for the tarballs you've
included. Eventually it shouldn't be necessary to change any
version but the Twisted one.

5. './admin/release-twisted --commands=makeBallSumo --sumo-version=a.b.x.y'
where 'a.b.x' is the version of Twisted Core contained in this
release (see point 6 in "Releasing Core or a Subproject" above),
and 'y' is simply a monotonically increasing nonnegative integer as
long as 'a.b.x' is the same as the last release.

6. Distribute, announce, etc.
6. Commit the changed README file to trunk,
author: release-twisted, reviewer: you.

7. Distribute, announce, etc.

= CREATING A NEW SUBPROJECT =

1. Add project name to twisted/python/dist.py, 'subprojects' list.
1. Add the project name to twisted/python/dist.py's list of subprojects and
setup.py's list of subprojects.

2. mkdir twisted/<proj>/topfiles

Expand Down
31 changes: 10 additions & 21 deletions admin/release-twisted
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,11 @@ sys.path.insert(0, os.curdir)
from twisted.python import usage, dist, reflect
from twisted.python.release import runChdirSafe, sh, DirectoryExists, DirectoryDoesntExist

import time, glob
import glob

packaged_projects = dist.twisted_subprojects[:]
packaged_projects.remove('web2')

core_blacklist = ['vfs', 'pb', 'flow', 'pair']

# FIXME:
# 2. If we ever do a sumo release on the same day, the version will
# conflict, since we just use %Y-%m-%d as the version...



def makeCommands():
# Yeah, I could do dynamic lookups and for loops and shit, but
Expand All @@ -49,6 +42,7 @@ def makeCommands():
'makeDocNames': makeMakeDoc('names'),
'makeDocNews': makeMakeDoc('news'),
'makeDocPair': makeMakeDoc('pair'),
'makeDocPb': makeMakeDoc('pb'),
'makeDocRunner': makeMakeDoc('runner'),
'makeDocWeb': makeMakeDoc('web'),
'makeDocWeb2': makeMakeDoc('web2'),
Expand All @@ -61,6 +55,7 @@ def makeCommands():
'makeBallNames': makeMakeBall('names'),
'makeBallNews': makeMakeBall('news'),
'makeBallPair': makeMakeBall('pair'),
'makeBallPb': makeMakeBall('pb'),
'makeBallRunner': makeMakeBall('runner'),
'makeBallWeb': makeMakeBall('web'),
'makeBallWeb2': makeMakeBall('web2'),
Expand Down Expand Up @@ -141,12 +136,6 @@ def tar(tdir):
sh('find %(tdir)s -name "*.pyc" | xargs rm -f' % locals())
sh('tar cjhf %(tdir)s.tar.bz2 %(tdir)s' % locals())

def getVersion(projdesc):
if projdesc == 'core':
return reflect.namedModule('twisted').__version__
else:
return reflect.namedModule('twisted.'+projdesc).__version__

##
# The MEAT.
##
Expand All @@ -158,7 +147,7 @@ def exportTemp(opts):


def makeDocCore(opts):
ver = getVersion('core')
ver = dist.getVersion('core')
os.chdir('Twisted.exp')

for docdir in ['howto', 'howto/tutorial', 'howto/policy', 'upgrades',
Expand All @@ -176,7 +165,7 @@ def makeMakeDoc(projname):
for sub in ('howto', 'examples'):
sub = os.path.join(base, sub)
if os.path.exists(sub):
lore(getVersion(projname), sub)
lore(dist.getVersion(projname), sub)
return makeDoc


Expand All @@ -194,7 +183,7 @@ def makeBallAll(opts):


def makeBallCore(opts):
ver = getVersion('core')
ver = dist.getVersion('core')
tdir = "TwistedCore-%s" % (ver,)
if not os.path.exists('Twisted.exp'):
raise DirectoryDoesntExist("MakeBalls: Twisted.exp doesn't exist")
Expand All @@ -203,7 +192,7 @@ def makeBallCore(opts):
os.makedirs(os.path.join(tdir, 'bin'))

twisted_subprojects = ','.join(dist.twisted_subprojects)
package_blacklist = ','.join(core_blacklist + dist.twisted_subprojects)
package_blacklist = ','.join(dist.twisted_subprojects)

sh('''
ln -s `pwd`/Twisted.exp/twisted/* %(tdir)s/twisted/
Expand All @@ -226,7 +215,7 @@ def makeBallSumo(opts):
ver = opts['sumo-version']
if not ver:
raise Exception("Please provide a --sumo-version")
basever = getVersion('core')
basever = dist.getVersion('core')
tdir = "Twisted-%s" % (ver,)
if not os.path.exists('twistedballs'):
raise Exception("Please create a 'twistedballs' directory and "
Expand All @@ -246,7 +235,7 @@ def makeBallSumo(opts):
sh('''
cp `pwd`/README %(tdir)s/
cp `pwd`/LICENSE %(tdir)s/
cp `pwd`/admin/sumo-setup.py %(tdir)s/setup.py
cp `pwd`/setup.py %(tdir)s/setup.py
''' % locals())
tar(tdir)

Expand Down Expand Up @@ -277,7 +266,7 @@ def createSubprojectDirectory(proj, version):

def makeMakeBall(proj):
def makeBall(opts):
projver = getVersion(proj)
projver = dist.getVersion(proj)
projdir = 'Twisted%s-%s' % (proj.capitalize(), projver,)
createSubprojectDirectory(proj, projver)
tar(projdir)
Expand Down
Loading

0 comments on commit 314e19a

Please sign in to comment.