]>
git.proxmox.com Git - libgit2.git/blob - script/release.py
e0f29538e7b605598950d79808fb36b09154cc27
3 from collections
import namedtuple
15 class Error(Exception):
18 class Version(object):
19 def __init__(self
, version
):
20 versions
= version
.split(sep
='.')
21 if len(versions
) < 2 or len(versions
) > 3:
22 raise Error("Invalid version string '{}'".format(version
))
23 self
.major
= int(versions
[0])
24 self
.minor
= int(versions
[1])
25 self
.revision
= int(versions
[2]) if len(versions
) == 3 else 0
28 return '{}.{}.{}'.format(self
.major
, self
.minor
, self
.revision
)
30 def __eq__(self
, other
):
31 return self
.major
== other
.major
and self
.minor
== other
.minor
and self
.revision
== other
.revision
33 def verify_version(version
):
35 'VERSION': [ '"{}"'.format(version
), None ],
36 'VER_MAJOR': [ str(version
.major
), None ],
37 'VER_MINOR': [ str(version
.minor
), None ],
38 'VER_REVISION': [ str(version
.revision
), None ],
39 'VER_PATCH': [ '0', None ],
40 'SOVERSION': [ '"{}.{}"'.format(version
.major
, version
.minor
), None ],
43 with
open('include/git2/version.h') as f
:
46 for key
in expected
.keys():
47 define
= '#define LIBGIT2_{} '.format(key
)
49 if line
.startswith(define
):
50 expected
[key
][1] = line
[len(define
):].strip()
53 raise Error("version.h: missing define for '{}'".format(key
))
55 for k
, v
in expected
.items():
57 raise Error("version.h: define '{}' does not match (got '{}', expected '{}')".format(k
, v
[0], v
[1]))
59 def generate_relnotes(tree
, version
):
60 with
open('docs/changelog.md') as f
:
63 if not lines
[0].startswith('v'):
64 raise Error("changelog.md: missing section for v{}".format(version
))
66 v
= Version(lines
[0][1:].strip())
68 raise Error("changelog.md: invalid version string {}".format(lines
[0].strip()))
70 raise Error("changelog.md: changelog version doesn't match (got {}, expected {})".format(v
, version
))
71 if not lines
[1].startswith('----'):
72 raise Error("changelog.md: missing version header")
74 raise Error("changelog.md: missing newline after version header")
76 for i
, line
in enumerate(lines
[3:]):
77 if not line
.startswith('v'):
80 Version(line
[1:].strip())
85 raise Error("changelog.md: cannot find section header of preceding release")
87 return ''.join(lines
[3:i
+ 3]).strip()
90 process
= subprocess
.run([ 'git', *args
], stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
91 if process
.returncode
!= 0:
92 raise Error('Failed executing git {}: {}'.format(' '.join(args
), process
.stderr
.decode()))
95 def post(url
, data
, contenttype
, user
, password
):
96 request
= urllib
.request
.Request(url
, data
=data
)
97 request
.add_header('Accept', 'application/json')
98 request
.add_header('Content-Type', contenttype
)
99 request
.add_header('Content-Length', len(data
))
100 request
.add_header('Authorization', 'Basic ' + base64
.b64encode('{}:{}'.format(user
, password
).encode()).decode())
103 response
= urllib
.request
.urlopen(request
)
104 if response
.getcode() != 201:
105 raise Error("POST to '{}' failed: {}".format(url
, response
.reason
))
106 except urllib
.error
.URLError
as e
:
107 raise Error("POST to '{}' failed: {}".format(url
, e
))
108 data
= json
.load(response
)
112 def generate_asset(version
, tree
, archive_format
):
113 Asset
= namedtuple('Asset', ['name', 'label', 'mimetype', 'data'])
114 mimetype
= 'application/{}'.format('gzip' if archive_format
== 'tar.gz' else 'zip')
116 "libgit2-{}.{}".format(version
, archive_format
), "Release sources: libgit2-{}.{}".format(version
, archive_format
), mimetype
,
117 git('archive', '--format', archive_format
, '--prefix', 'libgit2-{}/'.format(version
), tree
)
122 "tag_name": 'v' + str(args
.version
),
123 "name": 'libgit2 v' + str(args
.version
),
124 "target_commitish": git('rev-parse', args
.tree
).decode().strip(),
125 "body": generate_relnotes(args
.tree
, args
.version
),
128 generate_asset(args
.version
, args
.tree
, 'tar.gz'),
129 generate_asset(args
.version
, args
.tree
, 'zip'),
133 for k
, v
in params
.items():
134 print('{}: {}'.format(k
, v
))
136 print('asset: name={}, label={}, mimetype={}, bytes={}'.format(asset
.name
, asset
.label
, asset
.mimetype
, len(asset
.data
)))
140 url
= 'https://api.github.com/repos/{}/releases'.format(args
.repository
)
141 response
= post(url
, json
.dumps(params
).encode(), 'application/json', args
.user
, args
.password
)
143 raise Error('Could not create release: ' + str(e
))
147 url
= list(urllib
.parse
.urlparse(response
['upload_url'].split('{?')[0]))
148 url
[4] = urllib
.parse
.urlencode({ 'name': asset
.name
, 'label': asset
.label
})
149 post(urllib
.parse
.urlunparse(url
), asset
.data
, asset
.mimetype
, args
.user
, args
.password
)
151 raise Error('Could not upload asset: ' + str(e
))
154 parser
= argparse
.ArgumentParser(description
='Create a libgit2 release')
155 parser
.add_argument('--tree', default
='HEAD', help='tree to create release for (default: HEAD)')
156 parser
.add_argument('--dryrun', action
='store_true', help='generate release, but do not post it')
157 parser
.add_argument('--repository', default
='libgit2/libgit2', help='GitHub repository to create repository in')
158 parser
.add_argument('--user', help='user to authenitcate as')
159 parser
.add_argument('--password', help='password to authenticate with')
160 parser
.add_argument('version', type=Version
, help='version of the new release')
161 args
= parser
.parse_args()
163 verify_version(args
.version
)
166 if __name__
== '__main__':