Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: sitescripts/extensions/bin/createNightlies.py

Issue 29323474: Issue 2896 - Automate uploading of Firefox development builds to AMO (Closed)
Left Patch Set: Created Aug. 12, 2015, 11:45 a.m.
Right Patch Set: Cleaned up imports Created Aug. 13, 2015, 12:59 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # coding: utf-8 1 # coding: utf-8
2 2
3 # This file is part of the Adblock Plus web scripts, 3 # This file is part of the Adblock Plus web scripts,
4 # Copyright (C) 2006-2015 Eyeo GmbH 4 # Copyright (C) 2006-2015 Eyeo GmbH
5 # 5 #
6 # Adblock Plus is free software: you can redistribute it and/or modify 6 # Adblock Plus is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3 as 7 # it under the terms of the GNU General Public License version 3 as
8 # published by the Free Software Foundation. 8 # published by the Free Software Foundation.
9 # 9 #
10 # Adblock Plus is distributed in the hope that it will be useful, 10 # Adblock Plus is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details. 13 # GNU General Public License for more details.
14 # 14 #
15 # You should have received a copy of the GNU General Public License 15 # You should have received a copy of the GNU General Public License
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
17 17
18 """ 18 """
19 19
20 Nightly builds generation script 20 Nightly builds generation script
21 ================================ 21 ================================
22 22
23 This script generates nightly builds of extensions, together 23 This script generates nightly builds of extensions, together
24 with changelogs and documentation. 24 with changelogs and documentation.
25 25
26 """ 26 """
27 27
28 import sys, os, os.path, subprocess, ConfigParser, json, hashlib 28 import ConfigParser
Felix Dahlke 2015/08/13 12:52:27 Nit: Might be a good opportunity to clean the comm
Wladimir Palant 2015/08/13 13:00:40 As I said, I intentionally didn't clean up the imp
29 import tempfile, shutil, urlparse, pipes, time, urllib2, struct
30 import cookielib 29 import cookielib
30 from datetime import datetime
31 import hashlib
31 import HTMLParser 32 import HTMLParser
33 import json
32 import logging 34 import logging
33 from datetime import datetime 35 import os
36 import pipes
37 import shutil
38 import struct
39 import subprocess
40 import sys
41 import tempfile
42 import time
34 from urllib import urlencode 43 from urllib import urlencode
44 import urllib2
45 import urlparse
35 from xml.dom.minidom import parse as parseXml 46 from xml.dom.minidom import parse as parseXml
36 from sitescripts.utils import get_config, get_template 47
37 from sitescripts.extensions.utils import ( 48 from sitescripts.extensions.utils import (
38 compareVersions, Configuration, 49 compareVersions, Configuration,
39 writeAndroidUpdateManifest 50 writeAndroidUpdateManifest
40 ) 51 )
52 from sitescripts.utils import get_config, get_template
41 53
42 MAX_BUILDS = 50 54 MAX_BUILDS = 50
43 55
44 56
45 class NightlyBuild(object): 57 class NightlyBuild(object):
46 """ 58 """
47 Performs the build process for an extension, 59 Performs the build process for an extension,
48 generating changelogs and documentation. 60 generating changelogs and documentation.
49 """ 61 """
50 62
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 password = get_config().get('extensions', 'amo_password') 396 password = get_config().get('extensions', 'amo_password')
385 397
386 slug = self.config.galleryID 398 slug = self.config.galleryID
387 login_url= 'https://addons.mozilla.org/en-US/firefox/users/login' 399 login_url= 'https://addons.mozilla.org/en-US/firefox/users/login'
388 upload_url = 'https://addons.mozilla.org/en-US/developers/addon/%s/upload' % slug 400 upload_url = 'https://addons.mozilla.org/en-US/developers/addon/%s/upload' % slug
389 add_url = 'https://addons.mozilla.org/en-US/developers/addon/%s/versions/add ' % slug 401 add_url = 'https://addons.mozilla.org/en-US/developers/addon/%s/versions/add ' % slug
390 402
391 cookie_jar = cookielib.CookieJar() 403 cookie_jar = cookielib.CookieJar()
392 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar)) 404 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar))
393 405
394 def load_url(url, data=None): 406 def load_url(url, data=None):
Sebastian Noack 2015/08/12 13:29:26 Any reason, why you don'T simply use urllib3.reque
Wladimir Palant 2015/08/12 13:34:10 Yes, urllib3 doesn't support cookie jars.
395 content_type = 'application/x-www-form-urlencoded' 407 content_type = 'application/x-www-form-urlencoded'
396 if isinstance(data, dict): 408 if isinstance(data, dict):
397 if any(isinstance(v, tuple) for v in data.itervalues()): 409 if any(isinstance(v, tuple) for v in data.itervalues()):
398 data, content_type = urllib3.filepost.encode_multipart_formdata(data) 410 data, content_type = urllib3.filepost.encode_multipart_formdata(data)
399 else: 411 else:
400 data = urlencode(data.items()) 412 data = urlencode(data.items())
401 413
402 request = urllib2.Request(url, data, headers={'Content-Type': content_type }) 414 request = urllib2.Request(url, data, headers={'Content-Type': content_type })
403 response = opener.open(request) 415 response = opener.open(request)
404 try: 416 try:
405 return response.read() 417 return response.read()
406 finally: 418 finally:
407 response.close() 419 response.close()
408 420
409 class CSRFParser(HTMLParser.HTMLParser): 421 class CSRFParser(HTMLParser.HTMLParser):
Sebastian Noack 2015/08/12 13:29:26 Don't we already use minidom somewhere else? That
Wladimir Palant 2015/08/12 13:34:10 Does minidom parse HTML? Not that I know.
Felix Dahlke 2015/08/13 12:52:27 I've used BeautifulSoup for this kind of stuff. Bu
Sebastian Noack 2015/08/18 09:04:13 Alright, minidom is only for XML, though it also w
410 result = None 422 result = None
411 dummy_exception = Exception() 423 dummy_exception = Exception()
412 424
413 def __init__(self, data): 425 def __init__(self, data):
414 HTMLParser.HTMLParser.__init__(self) 426 HTMLParser.HTMLParser.__init__(self)
415 try: 427 try:
416 self.feed(data) 428 self.feed(data)
417 self.close() 429 self.close()
418 except Exception, e: 430 except Exception, e:
419 if e != self.dummy_exception: 431 if e != self.dummy_exception:
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 upload_response = json.loads(load_url( 465 upload_response = json.loads(load_url(
454 upload_url, 466 upload_url,
455 { 467 {
456 'csrfmiddlewaretoken': csrf_token, 468 'csrfmiddlewaretoken': csrf_token,
457 'upload': (os.path.basename(self.path), file.read(), 'application/x-xp install'), 469 'upload': (os.path.basename(self.path), file.read(), 'application/x-xp install'),
458 } 470 }
459 )) 471 ))
460 472
461 # Wait for validation to finish 473 # Wait for validation to finish
462 while not upload_response.get('validation'): 474 while not upload_response.get('validation'):
463 time.sleep(2) 475 time.sleep(2)
Sebastian Noack 2015/08/12 13:29:26 I suppose there is no way to get notified when it'
Wladimir Palant 2015/08/12 13:34:10 No, it's exactly how the web interface does it - b
464 upload_response = json.loads(load_url( 476 upload_response = json.loads(load_url(
465 upload_url + '/' + upload_response.get('upload') 477 upload_url + '/' + upload_response.get('upload')
466 )) 478 ))
467 479
468 if upload_response['validation'].get('errors', 0): 480 if upload_response['validation'].get('errors', 0):
Sebastian Noack 2015/08/12 13:29:26 Nit: Omit the default value? None evaluates to Fal
Wladimir Palant 2015/08/12 13:34:10 Yes, I considered it but the default value indicat
469 raise Exception('Build failed AMO validation, see https://addons.mozilla.o rg%s' % upload_response.get('full_report_url')) 481 raise Exception('Build failed AMO validation, see https://addons.mozilla.o rg%s' % upload_response.get('full_report_url'))
470 482
471 # Add version 483 # Add version
472 add_response = json.loads(load_url( 484 add_response = json.loads(load_url(
473 add_url, 485 add_url,
474 { 486 {
475 'csrfmiddlewaretoken': csrf_token, 487 'csrfmiddlewaretoken': csrf_token,
476 'upload': upload_response.get('upload'), 488 'upload': upload_response.get('upload'),
477 'source': ('', '', 'application/octet-stream'), 489 'source': ('', '', 'application/octet-stream'),
478 'beta': 'on', 490 'beta': 'on',
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 self.readSafariMetadata() 577 self.readSafariMetadata()
566 else: 578 else:
567 self.readGeckoMetadata() 579 self.readGeckoMetadata()
568 580
569 # create development build 581 # create development build
570 self.build() 582 self.build()
571 583
572 # write out changelog 584 # write out changelog
573 self.writeChangelog(self.getChanges()) 585 self.writeChangelog(self.getChanges())
574 586
575 # write update.rdf file 587 # write update manifest
576 self.writeUpdateManifest() 588 if self.config.type != 'gecko':
589 self.writeUpdateManifest()
577 590
578 # update documentation 591 # update documentation
579 self.updateDocs() 592 self.updateDocs()
580 593
581 # retire old builds 594 # retire old builds
582 versions = self.retireBuilds() 595 versions = self.retireBuilds()
583 596
584 if self.config.type == 'ie': 597 if self.config.type == 'ie':
585 self.writeIEUpdateManifest(versions) 598 self.writeIEUpdateManifest(versions)
586 599
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 except Exception, ex: 634 except Exception, ex:
622 logging.error("The build for %s failed:", repo) 635 logging.error("The build for %s failed:", repo)
623 logging.exception(ex) 636 logging.exception(ex)
624 637
625 file = open(nightlyConfigFile, 'wb') 638 file = open(nightlyConfigFile, 'wb')
626 nightlyConfig.write(file) 639 nightlyConfig.write(file)
627 640
628 641
629 if __name__ == '__main__': 642 if __name__ == '__main__':
630 main() 643 main()
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld