diff --git a/build.xml b/build.xml
index a720ea167..320e30502 100644
--- a/build.xml
+++ b/build.xml
@@ -222,6 +222,9 @@
+
+
+
diff --git a/changelog.py b/changelog.py
new file mode 100755
index 000000000..48f0c3f14
--- /dev/null
+++ b/changelog.py
@@ -0,0 +1,108 @@
+import os, os.path, sys, re
+import json, urllib2
+from pprint import pprint
+from urlparse import urlparse
+import base64
+import optparse, ast
+
+class PreemptiveBasicAuthHandler(urllib2.BaseHandler):
+ def __init__(self, password_mgr=None):
+ if password_mgr is None:
+ password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
+ self.passwd = password_mgr
+ self.add_password = self.passwd.add_password
+
+ def http_request(self,req):
+ uri = req.get_full_url()
+ user, pw = self.passwd.find_user_password(None,uri)
+ if pw is None: return req
+ raw = "%s:%s" % (user, pw)
+ auth = 'Basic %s' % base64.b64encode(raw).strip()
+ req.add_unredirected_header('Authorization', auth)
+ return req
+
+ def https_request(self,req):
+ return self.http_request(req)
+
+def read_url(url):
+ handler = PreemptiveBasicAuthHandler()
+ handler.add_password(None, 'ci.jenkins.minecraftforge.net', 'console_script', 'dc6d48ca20a474beeac280a9a16a926e')
+ file = urllib2.build_opener(handler).open(url)
+ data = file.read()
+ file.close()
+ return data
+
+def getBuildInfo(url, current_version=None):
+ data = read_url(url)
+ data = ast.literal_eval(data)['allBuilds']
+ data = sorted(data, key=lambda key: key['number'], reverse=False)
+
+ items = []
+ output = []
+
+ for build in data:
+ build['actions'] = filter(lambda act: act is not None, build['actions'])
+ build['actions'] = filter(lambda act: 'text' in act, build['actions'])
+ build['actions'] = filter(lambda act: not ' ' in act['text'], build['actions'])
+ if len(build['actions']) == 0:
+ build['version'] = current_version
+ current_version = None
+ else:
+ build['version'] = build['actions'][0]['text']
+ build['items'] = build['changeSet']['items']
+ if build['result'] != 'SUCCESS':
+ items += build['items']
+ else:
+ build['items'] = items + build['items']
+ items = []
+ output += [build]
+ build.pop('changeSet')
+ build.pop('actions')
+ return sorted(output, key=lambda key: key['number'], reverse=True)
+
+def add_latest_build(url, builds, current_version=None):
+ data = read_url(url)
+ data = ast.literal_eval(data)
+ number = data['number']
+
+ if builds[0]['number'] == data['number']:
+ return builds
+
+ build = {
+ 'number' : data['number'],
+ 'result' : 'SUCCESS', #Currently build should always be success... Else things derp after words
+ 'version' : current_version,
+ 'items' : data['changeSet']['items']
+ }
+ return [build] + builds
+
+def make_changelog(job_path, target_build, change_file, current_version=None):
+ builds = getBuildInfo('%s/api/python?tree=allBuilds[result,number,actions[text],changeSet[items[author[fullName],comment]]]&pretty=true' % job_path, current_version)
+ builds = add_latest_build('%s/lastBuild/api/python?pretty=true&tree=number,changeSet[items[author[fullName],comment]]' % job_path, builds, current_version)
+
+ log = [ "Changelog:" ]
+
+ for build in builds:
+ if int(build['number']) > target_build: continue
+ if len(build['items']) == 0: continue
+ log.append('')
+ if build['version'] is None:
+ log.append('Build %s' % build['number'])
+ else:
+ log.append('Build %s' % build['version'])
+ for change in build['items']:
+ comments = filter(lambda cmt: len(cmt) > 0, change['comment'].split('\n'))
+ if len(comments) > 1:
+ log.append('\t' + change['author'])
+ for comment in comments:
+ log.append('\t\t' + comment)
+ elif len(comments) == 1:
+ log.append('\t%s: %s' % (change['author'], comments[0]))
+
+ file = open(change_file, 'wb')
+ for line in log:
+ file.write('%s\n' % line)
+ file.close()
+
+if __name__ == '__main__':
+ make_changelog("http://ci.jenkins.minecraftforge.net/job/BiomesOPlenty/", 70000, 'changelog.txt', 'pinecone')
\ No newline at end of file