I've put some print in packaging.py to help debugging. Here's what I have changed: def install_pipeline_deps(self, extension, css_bundles, js_bundles): ... ... with open(package_file, 'w') as fp: fp.write(json.dumps( { 'name': '%s-extension' % os.path.basename(os.getcwd()), 'private': 'true', 'devDependencies': {}, 'dependencies': dependencies, }, indent=2))
old_cwd = os.getcwd() os.chdir(build_dir) * print 'PIPELINE_LESS_BINARY = {}'.format(pipeline_settings.LESS_BINARY)* * print 'PIPELINE_UGLIFYJS_BINARY = {}'.format(pipeline_settings.UGLIFYJS_BINARY)* self.npm_install() And the output is: PIPELINE_LESS_BINARY = /src2/rb-extension-pack/fortinet/build/node_modules/ less/bin/lessc PIPELINE_UGLIFYJS_BINARY = /src2/rb-extension-pack/fortinet/build/ node_modules/uglifyjs/bin/uglifyjs Also build/node_modules.. created in extention directory, so the path is correct at this point On Monday, June 12, 2017 at 5:17:15 PM UTC-7, Christian Hammond wrote: > > Hi Kevin, > > printing in settings.py won't tell you anything of value. Those are the > correct locations at the time that settings.py loaded, but they're > overridden during the packaging process. The locations mentioned in my > previous e-mail are where that happens. Solving this will require narrowing > down the locations where the path is correct and where it's incorrect in > that process. > > Christian > > On Mon, Jun 12, 2017 at 2:49 PM, Kevin Yu <sams...@gmail.com <javascript:> > > wrote: > >> Hi Christian, >> >> Thanks for trying out. I also did some debugging to see if I can find any >> information. I added some print in the settings.py >> >> PIPELINE_LESS_BINARY = os.path.join(NODE_PATH, 'less', 'bin', 'lessc') >> PIPELINE_UGLIFYJS_BINARY = os.path.join(NODE_PATH, 'uglifyjs', 'bin', >> 'uglifyjs') >> print 'PIPELINE_UGLIFYJS_BINARY = {}'.format(PIPELINE_UGLIFYJS_BINARY) >> print 'PIPELINE_LESS_BINARY = {}'.format(PIPELINE_LESS_BINARY) >> >> >> >> And this is what I see in the log: >> >> [Mon Jun 12 14:47:50.821618 2017] [:error] [pid 12918:tid >> 140227234481920] PIPELINE_UGLIFYJS_BINARY = >> /usr/local/lib/python2.7/dist-packages/ReviewBoard-2.5.12-py2.7.egg/reviewboard/../node_modules/uglifyjs/bin/uglifyjs >> [Mon Jun 12 14:47:50.821692 2017] [:error] [pid 12918:tid >> 140227234481920] PIPELINE_LESS_BINARY = >> /usr/local/lib/python2.7/dist-packages/ReviewBoard-2.5.12-py2.7.egg/reviewboard/../node_modules/less/bin/lessc >> >> >> >> On Saturday, June 10, 2017 at 1:43:26 AM UTC-7, Christian Hammond wrote: >>> >>> Right. We override this though in djblets/extensions/packaging.py in >>> install_pipeline_deps(). We compute the path to the extension's >>> node_modules and its lessc, and we set that in settings. >>> >>> I tested locally and it's performing as expected for me. Review Board's >>> lessc isn't being used, but the extension's is. So something's going wrong >>> here with the paths. >>> >>> How comfortable are you debugging Python? I'm curious as to whether >>> pipeline_settings.LESS_BINARY in install_pipeline_deps() is being correctly >>> set. >>> >>> Christian >>> >>> On Fri, Jun 9, 2017 at 5:51 PM, Kevin Yu <sams...@gmail.com> wrote: >>> >>>> Looks like the path to the npm_modules are prepopulated based on the >>>> following code in settings.py: >>>> # Static media setup >>>> if RUNNING_TEST: >>>> PIPELINE_COMPILERS = [] >>>> else: >>>> PIPELINE_COMPILERS = [ >>>> 'djblets.pipeline.compilers.es6.ES6Compiler', >>>> 'djblets.pipeline.compilers.less.LessCompiler', >>>> ] >>>> >>>> NODE_PATH = os.path.join(REVIEWBOARD_ROOT, '..', 'node_modules') >>>> >>>> >>>> >>>> On Friday, June 9, 2017 at 5:44:51 PM UTC-7, Kevin Yu wrote: >>>>> >>>>> Thanks Christian for the quick reply! much appreciated. >>>>> >>>>> It was installed using easy_install under Ubuntu. >>>>> >>>>> On Friday, June 9, 2017 at 5:38:11 PM UTC-7, Christian Hammond wrote: >>>>>> >>>>>> Hi Kevin, >>>>>> >>>>>> I actually don't believe this is related in this case. It looks like >>>>>> the extension packaging stage is trying to locate the lessc path >>>>>> relative >>>>>> to Review Board, which is not correct. It should be locating it from the >>>>>> extension package. It sets the path prior to building the extension to >>>>>> the >>>>>> place in your tree, which, based on that output, should be populated... >>>>>> >>>>>> I have to run right now, but let me play around with this when I get >>>>>> back and see if I can reproduce this. >>>>>> >>>>>> In the meantime, how do you install Review Board? Are you using >>>>>> easy_install or yum? >>>>>> >>>>>> Christian >>>>>> >>>>>> On Fri, Jun 9, 2017 at 5:34 PM, Kevin Yu <sams...@gmail.com> wrote: >>>>>> >>>>>>> I just saw on >>>>>>> https://www.reviewboard.org/docs/manual/dev/extending/extensions/static-files/, >>>>>>> >>>>>>> it says >>>>>>> >>>>>>> Static bundles are packaged along with your extension automatically. >>>>>>> You don’t have to do anything special. You will, however, need some >>>>>>> node.js <https://nodejs.org/> dependencies in order to package >>>>>>> static media bundles. >>>>>>> >>>>>>> *If you’re running Review Board 2.5.7+, these dependencies will be >>>>>>> installed for you when you begin to build the package.* >>>>>>> >>>>>>> *If you’re running an older version, you will need to manually >>>>>>> install them yourself. First, make sure you have a modern version of >>>>>>> node.js installed and then run:* >>>>>>> >>>>>>> $ sudo npm install -g less uglifyjs >>>>>>> >>>>>>> I am wondering if this is related... >>>>>>> >>>>>>> On Friday, June 9, 2017 at 4:41:10 PM UTC-7, Kevin Yu wrote: >>>>>>>> >>>>>>>> On our server, we had reviewboard core 2.5.6.1 running with our own >>>>>>>> extension. it was all fine until we recently upgraded reviewboard core >>>>>>>> to >>>>>>>> 2.5.12. After the upgrade, we can't run python setup.py -v build >>>>>>>> anymore... >>>>>>>> The error is as follows: >>>>>>>> devops@Reviewboard-Test-trunk:/tmp/ReviewBoardExt$ python setup.py >>>>>>>> -v build >>>>>>>> running build >>>>>>>> running build_py >>>>>>>> running build_static_files >>>>>>>> Installing node packages... >>>>>>>> npm http GET https://registry.npmjs.org/uglifyjs/2.4.10 >>>>>>>> npm http GET https://registry.npmjs.org/less/2.7.1 >>>>>>>> npm http 304 https://registry.npmjs.org/less/2.7.1 >>>>>>>> npm http 304 https://registry.npmjs.org/uglifyjs/2.4.10 >>>>>>>> npm WARN deprecated uglifyjs@2.4.10: uglifyjs is deprecated - use >>>>>>>> uglify-js instead. >>>>>>>> npm WARN engine less@2.7.1: wanted: {"node":">=0.12"} (current: >>>>>>>> {"node":"v0.10.25","npm":"1.3.10"}) >>>>>>>> npm http GET https://registry.npmjs.org/source-map/0.1.34 >>>>>>>> npm http GET https://registry.npmjs.org/yargs >>>>>>>> npm http GET https://registry.npmjs.org/async >>>>>>>> npm http GET https://registry.npmjs.org/uglify-to-browserify >>>>>>>> npm http 304 https://registry.npmjs.org/source-map/0.1.34 >>>>>>>> npm http 304 https://registry.npmjs.org/yargs >>>>>>>> npm http 304 https://registry.npmjs.org/async >>>>>>>> npm http 304 https://registry.npmjs.org/uglify-to-browserify >>>>>>>> npm http GET https://registry.npmjs.org/amdefine >>>>>>>> npm http 304 https://registry.npmjs.org/amdefine >>>>>>>> npm http GET https://registry.npmjs.org/errno >>>>>>>> npm http GET https://registry.npmjs.org/graceful-fs >>>>>>>> npm http GET https://registry.npmjs.org/image-size >>>>>>>> npm http GET https://registry.npmjs.org/mime >>>>>>>> npm http GET https://registry.npmjs.org/mkdirp >>>>>>>> npm http GET https://registry.npmjs.org/promise >>>>>>>> npm http GET https://registry.npmjs.org/source-map >>>>>>>> npm http 304 https://registry.npmjs.org/errno >>>>>>>> npm http 304 https://registry.npmjs.org/graceful-fs >>>>>>>> npm http 304 https://registry.npmjs.org/image-size >>>>>>>> npm http 304 https://registry.npmjs.org/mime >>>>>>>> npm http 304 https://registry.npmjs.org/promise >>>>>>>> npm http 304 https://registry.npmjs.org/source-map >>>>>>>> npm http 304 https://registry.npmjs.org/mkdirp >>>>>>>> npm http GET https://registry.npmjs.org/prr >>>>>>>> npm http 304 https://registry.npmjs.org/prr >>>>>>>> npm http GET https://registry.npmjs.org/minimist/0.0.8 >>>>>>>> npm http 304 https://registry.npmjs.org/minimist/0.0.8 >>>>>>>> npm http GET https://registry.npmjs.org/asap >>>>>>>> npm http 304 https://registry.npmjs.org/asap >>>>>>>> uglifyjs@2.4.10 node_modules/uglifyjs >>>>>>>> ├── uglify-to-browserify@1.0.2 >>>>>>>> ├── async@0.2.10 >>>>>>>> ├── yargs@1.3.3 >>>>>>>> └── source-map@0.1.34 (amdefine@1.0.1) >>>>>>>> >>>>>>>> less@2.7.1 node_modules/less >>>>>>>> ├── graceful-fs@4.1.11 >>>>>>>> ├── mime@1.3.6 >>>>>>>> ├── image-size@0.5.4 >>>>>>>> ├── errno@0.1.4 (prr@0.0.0) >>>>>>>> ├── mkdirp@0.5.1 (minimist@0.0.8) >>>>>>>> ├── promise@7.1.1 (asap@2.0.5) >>>>>>>> └── source-map@0.5.6 >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/css/rev_req_det.less' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/account_handler.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/branch_builds.js' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/js/views/bootstrap.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/apprreqView.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/test_cvrg_rprt.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/ftnchkHoldItView.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/sel_rqst_4_det_copy.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/approval_status_View.js' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/js/views/dashboard.js' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/js/views/rqst_descr.js' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/js/views/cm_portalView.js' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/Remove.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/fortinet.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/forti...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/d...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/teamlead.png' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/images/favicon_notify.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/Create.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/ftnt.ico' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/u...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/shipit-grey.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/teaml...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/Up.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/Bottom.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/bot...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/stop16.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/cre...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/rem...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/shipit.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/shi...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/sto...@2x.png' >>>>>>>> Copying '/tmp/ReviewBoardExt/fortinet/static/images/Down.png' >>>>>>>> Copying >>>>>>>> '/tmp/ReviewBoardExt/fortinet/static/images/shipit-g...@2x.png' >>>>>>>> Traceback (most recent call last): >>>>>>>> File "setup.py", line 27, in <module> >>>>>>>> 'evolutions/*.*', >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/ReviewBoard-2.5.12-py2.7.egg/reviewboard/extensions/packaging.py", >>>>>>>> >>>>>>>> line 48, in setup >>>>>>>> setuptools_setup(**setup_kwargs) >>>>>>>> File "/usr/lib/python2.7/distutils/core.py", line 151, in setup >>>>>>>> dist.run_commands() >>>>>>>> File "/usr/lib/python2.7/distutils/dist.py", line 953, in >>>>>>>> run_commands >>>>>>>> self.run_command(cmd) >>>>>>>> File "/usr/lib/python2.7/distutils/dist.py", line 972, in >>>>>>>> run_command >>>>>>>> cmd_obj.run() >>>>>>>> File "/usr/lib/python2.7/distutils/command/build.py", line 128, >>>>>>>> in run >>>>>>>> self.run_command(cmd_name) >>>>>>>> File "/usr/lib/python2.7/distutils/cmd.py", line 326, in >>>>>>>> run_command >>>>>>>> self.distribution.run_command(command) >>>>>>>> File "/usr/lib/python2.7/distutils/dist.py", line 972, in >>>>>>>> run_command >>>>>>>> cmd_obj.run() >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Djblets-0.9.7-py2.7.egg/djblets/extensions/packaging.py", >>>>>>>> >>>>>>>> line 422, in run >>>>>>>> self.run_command('build_static_files') >>>>>>>> File "/usr/lib/python2.7/distutils/cmd.py", line 326, in >>>>>>>> run_command >>>>>>>> self.distribution.run_command(command) >>>>>>>> File "/usr/lib/python2.7/distutils/dist.py", line 972, in >>>>>>>> run_command >>>>>>>> cmd_obj.run() >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Djblets-0.9.7-py2.7.egg/djblets/extensions/packaging.py", >>>>>>>> >>>>>>>> line 290, in run >>>>>>>> self._build_static_media(extension) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Djblets-0.9.7-py2.7.egg/djblets/extensions/packaging.py", >>>>>>>> >>>>>>>> line 360, in _build_static_media >>>>>>>> call_command('collectstatic', interactive=False, verbosity=2) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Django-1.6.11-py2.7.egg/django/core/management/__init__.py", >>>>>>>> >>>>>>>> line 159, in call_command >>>>>>>> return klass.execute(*args, **defaults) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Django-1.6.11-py2.7.egg/django/core/management/base.py", >>>>>>>> >>>>>>>> line 285, in execute >>>>>>>> output = self.handle(*args, **options) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Django-1.6.11-py2.7.egg/django/core/management/base.py", >>>>>>>> >>>>>>>> line 415, in handle >>>>>>>> return self.handle_noargs(**options) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Django-1.6.11-py2.7.egg/django/contrib/staticfiles/management/commands/collectstatic.py", >>>>>>>> >>>>>>>> line 173, in handle_noargs >>>>>>>> collected = self.collect() >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/Django-1.6.11-py2.7.egg/django/contrib/staticfiles/management/commands/collectstatic.py", >>>>>>>> >>>>>>>> line 119, in collect >>>>>>>> for original_path, processed_path, processed in processor: >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/storage.py", >>>>>>>> >>>>>>>> line 32, in post_process >>>>>>>> packager.pack_stylesheets(package) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/packager.py", >>>>>>>> >>>>>>>> line 94, in pack_stylesheets >>>>>>>> variant=package.variant, **kwargs) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/packager.py", >>>>>>>> >>>>>>>> line 103, in pack >>>>>>>> paths = self.compile(package.paths, force=True) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/packager.py", >>>>>>>> >>>>>>>> line 97, in compile >>>>>>>> return self.compiler.compile(paths, force=force) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/compilers/__init__.py", >>>>>>>> >>>>>>>> line 55, in compile >>>>>>>> return list(executor.map(_compile, paths)) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/futures-3.0.5-py2.7.egg/concurrent/futures/_base.py", >>>>>>>> >>>>>>>> line 581, in result_iterator >>>>>>>> yield future.result() >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/futures-3.0.5-py2.7.egg/concurrent/futures/_base.py", >>>>>>>> >>>>>>>> line 405, in result >>>>>>>> return self.__get_result() >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/futures-3.0.5-py2.7.egg/concurrent/futures/thread.py", >>>>>>>> >>>>>>>> line 55, in run >>>>>>>> result = self.fn(*self.args, **self.kwargs) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/compilers/__init__.py", >>>>>>>> >>>>>>>> line 40, in _compile >>>>>>>> outdated=outdated, force=force) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/compilers/less.py", >>>>>>>> >>>>>>>> line 22, in compile_file >>>>>>>> return self.execute_command(command, cwd=dirname(infile)) >>>>>>>> File >>>>>>>> "/usr/local/lib/python2.7/dist-packages/django_pipeline-1.3.27-py2.7.egg/pipeline/compilers/__init__.py", >>>>>>>> >>>>>>>> line 99, in execute_command >>>>>>>> raise CompilerError(stderr) >>>>>>>> pipeline.exceptions.CompilerError: /bin/sh: 1: >>>>>>>> /usr/local/lib/python2.7/dist-packages/ReviewBoard-2.5.12-py2.7.egg/reviewboard/../node_modules/less/bin/lessc: >>>>>>>> >>>>>>>> not found >>>>>>>> >>>>>>>> The path it tries to find lessc seems wrong as well. the lessc >>>>>>>> should be in /usr/local/bin/lessc. >>>>>>>> >>>>>>>> Has anyone run into the same issue? >>>>>>>> >>>>>>> -- >>>>>>> Supercharge your Review Board with Power Pack: >>>>>>> https://www.reviewboard.org/powerpack/ >>>>>>> Want us to host Review Board for you? Check out RBCommons: >>>>>>> https://rbcommons.com/ >>>>>>> Happy user? Let us know! https://www.reviewboard.org/users/ >>>>>>> --- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "reviewboard" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>> send an email to reviewboard...@googlegroups.com. >>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Christian Hammond >>>>>> President/CEO of Beanbag <https://www.beanbaginc.com/> >>>>>> Makers of Review Board <https://www.reviewboard.org/> >>>>>> >>>>> -- >>>> Supercharge your Review Board with Power Pack: >>>> https://www.reviewboard.org/powerpack/ >>>> Want us to host Review Board for you? Check out RBCommons: >>>> https://rbcommons.com/ >>>> Happy user? Let us know! https://www.reviewboard.org/users/ >>>> --- >>>> You received this message because you are subscribed to the Google >>>> Groups "reviewboard" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to reviewboard...@googlegroups.com. >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> >>> >>> >>> -- >>> Christian Hammond >>> President/CEO of Beanbag <https://www.beanbaginc.com/> >>> Makers of Review Board <https://www.reviewboard.org/> >>> >> -- >> Supercharge your Review Board with Power Pack: >> https://www.reviewboard.org/powerpack/ >> Want us to host Review Board for you? Check out RBCommons: >> https://rbcommons.com/ >> Happy user? Let us know! https://www.reviewboard.org/users/ >> --- >> You received this message because you are subscribed to the Google Groups >> "reviewboard" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to reviewboard...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > > > -- > Christian Hammond > President/CEO of Beanbag <https://www.beanbaginc.com/> > Makers of Review Board <https://www.reviewboard.org/> > -- Supercharge your Review Board with Power Pack: https://www.reviewboard.org/powerpack/ Want us to host Review Board for you? Check out RBCommons: https://rbcommons.com/ Happy user? Let us know! https://www.reviewboard.org/users/ --- You received this message because you are subscribed to the Google Groups "reviewboard" group. To unsubscribe from this group and stop receiving emails from it, send an email to reviewboard+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.