From 75f9546838e595ff476cac66d1431b8761082ca4 Mon Sep 17 00:00:00 2001 From: rdhayes Date: Mon, 14 Aug 2017 17:07:00 -0700 Subject: [PATCH 01/86] upgrade google analytics to analytics.js; add new jbrowse.conf selfGoogleUsageAccount parameter (single value or comma-separated list of additional Google Analytics accounts to report page views) --- src/JBrowse/Browser.js | 79 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index 12a02ebf0..61988a03a 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -1,5 +1,3 @@ -var _gaq = _gaq || []; // global task queue for Google Analytics - define( [ 'dojo/_base/declare', 'dojo/_base/lang', @@ -1670,25 +1668,64 @@ reportUsageStats: function() { // phones home to google analytics _reportGoogleUsageStats: function( stats ) { - _gaq.push.apply( _gaq, [ - ['_setAccount', 'UA-7115575-2'], - ['_setDomainName', 'none'], - ['_setAllowLinker', true], - ['_setCustomVar', 1, 'tracks-count', stats['tracks-count'], 3 ], - ['_setCustomVar', 2, 'refSeqs-count', stats['refSeqs-count'], 3 ], - ['_setCustomVar', 3, 'refSeqs-avgLen', stats['refSeqs-avgLen'], 3 ], - ['_setCustomVar', 4, 'jbrowse-version', stats['ver'], 3 ], - ['_setCustomVar', 5, 'loadTime', stats['loadTime'], 3 ], - ['_trackPageview'] - ]); - - var ga = document.createElement('script'); - ga.type = 'text/javascript'; - ga.async = true; - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') - + '.google-analytics.com/ga.js'; - var s = document.getElementsByTagName('script')[0]; - s.parentNode.insertBefore(ga, s); + var thisB = this; + // jbrowse.org account always + var jbrowseUser = 'UA-7115575-2' + var accounts = [ jbrowseUser ]; + + // add one or more custom Google Analytics accounts from config (comma-separated) + if (thisB.config.selfGoogleUsageAccount) { + // cooerce into an array, so we handle any potential comma separated lists + var users = thisB.config.selfGoogleUsageAccount; + if( users && typeof users == 'object' && 'values' in users ) + users = users.values; + if( users && ! Array.isArray( users ) ) + users = [users]; + users.forEach(function(user) { + accounts.push(user); + }); + } + + var analyticsScript = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ \ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), \ + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) \ + })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');"; + + // set up users + var trackerNum = 1; + accounts.forEach(function(user) { + // if we're adding jbrowse.org user, also include new dimension references (replacing ga.js custom variables) + if ( user == jbrowseUser) { + analyticsScript += "ga('create', '"+user+"', 'auto', 'jbrowseTracker');"; + } + else { + analyticsScript += "ga('create', '"+user+"', 'auto', 'customTracker"+trackerNum+"');"; + trackerNum++; + } + }); + // send pageviews + var viewerNum = 1; + accounts.forEach(function(user) { + if ( user == jbrowseUser) { + // custom dimensions to replace the custom vars from older ga.js implementation + analyticsScript += "ga('jbrowseTracker.set', 'tracks-count', "+stats['tracks-count']+");"; + analyticsScript += "ga('jbrowseTracker.set', 'refSeqs-count', "+stats['refSeqs-count']+");"; + analyticsScript += "ga('jbrowseTracker.set', 'refSeqs-avgLen', "+stats['refSeqs-avgLen']+");"; + analyticsScript += "ga('jbrowseTracker.set', 'jbrowse-version', '"+stats['ver']+"');"; + analyticsScript += "ga('jbrowseTracker.set', 'loadTime', "+stats['loadTime']+");"; + analyticsScript += "ga('jbrowseTracker.send', 'pageview');"; + } + else { + analyticsScript += "ga('customTracker"+viewerNum+".send', 'pageview');"; + viewerNum++; + } + }); + + var analytics = document.createElement('script'); + analytics.innerHTML = analyticsScript; + + var thisHead = document.getElementsByTagName('head')[0]; + thisHead.appendChild(analytics); }, // phones home to custom analytics at jbrowse.org From f676ad34fff676b1b33505f043628d301cb31e17 Mon Sep 17 00:00:00 2001 From: rdhayes Date: Tue, 15 Aug 2017 11:00:58 -0700 Subject: [PATCH 02/86] address Travis build failure on mulit-line string --- src/JBrowse/Browser.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index 61988a03a..ac2628b6f 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -1686,10 +1686,10 @@ _reportGoogleUsageStats: function( stats ) { }); } - var analyticsScript = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ \ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), \ - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) \ - })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');"; + var analyticsScript = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ "; + analyticsScript += "(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), "; + analyticsScript += "m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) "; + analyticsScript += "})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');"; // set up users var trackerNum = 1; From 8831441cbcc159ac8fe9f573eb84bd990d72d555 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 6 Jul 2016 17:54:53 -0500 Subject: [PATCH 03/86] Re-enable fix for #567 --- src/JBrowse/GenomeView.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/JBrowse/GenomeView.js b/src/JBrowse/GenomeView.js index 21cafafb4..088d696b6 100755 --- a/src/JBrowse/GenomeView.js +++ b/src/JBrowse/GenomeView.js @@ -65,7 +65,7 @@ constructor: function( args ) { var stripeWidth = args.stripeWidth; var refseq = args.refSeq; var zoomLevel = args.zoomLevel; - + this.trackMod = {}; // keep a reference to the main browser object this.browser = browser; this.setFeatureFilterParentComponent( this.browser ); @@ -1114,6 +1114,7 @@ setLocation: function(refseq, startbp, endbp) { endbp = refseq.end; function removeTrack( track ) { + delete thisB.trackMod[track.name]; if (track.div && track.div.parentNode) track.div.parentNode.removeChild(track.div); }; @@ -2081,9 +2082,10 @@ showVisibleBlocks: function(updateHeight, pos, startX, endX) { showTracks: function( trackConfigs ) { // filter out any track configs that are already displayed var needed = dojo.filter( trackConfigs, function(conf) { - return this._getTracks( [conf.label] ).length == 0; + return this._getTracks( [conf.label] ).length == 0 && !this.trackMod[conf.label]; },this); if( ! needed.length ) return; + array.forEach(trackConfigs, function(ret) { this.trackMod[ret.label] = true; }, this); // insert the track configs into the trackDndWidget ( the widget // will call create() on the confs to render them) @@ -2146,6 +2148,7 @@ hideTracks: function( /**Array[String]*/ trackConfigs ) { return this._getTracks( [conf.label] ).length != 0; },this); if( ! displayed.length ) return; + array.forEach(trackConfigs, function(ret) { delete this.trackMod[ret.label]; }, this); // remove the track configs from the trackDndWidget ( the widget // will call create() on the confs to render them ) From 64f0bbbd3bae0ff7b8428d74b67b4e31f41e19c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loraine=20Gu=C3=A9guen?= Date: Fri, 2 Feb 2018 14:48:48 +0100 Subject: [PATCH 04/86] Add histograms argument to the script add-bam-track.pl --- bin/add-bam-track.pl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bin/add-bam-track.pl b/bin/add-bam-track.pl index 70304dff5..9b1ef0f85 100755 --- a/bin/add-bam-track.pl +++ b/bin/add-bam-track.pl @@ -14,6 +14,7 @@ use Pod::Usage; my $STORE_CLASS = "JBrowse/Store/SeqFeature/BAM"; +my $BIGWIG_STORE_CLASS = "JBrowse/Store/SeqFeature/BigWig"; my $ALIGNMENT_TYPE = "JBrowse/View/Track/Alignments2"; my $COVERAGE_TYPE = "JBrowse/View/Track/SNPCoverage"; @@ -21,7 +22,9 @@ my $out_file; my $label; my $bam_url; +my $bigwig_url; my $key; +my $histograms = undef; my $coverage = 0; my $classname = undef; my $min_score = undef; @@ -39,6 +42,7 @@ sub parse_options { "bam_url|u=s" => \$bam_url, "key|k=s" => \$key, "classname|c=s" => \$classname, + "histograms|h" => \$histograms, "coverage|C" => \$coverage, "min_score|s=i" => \$min_score, "max_score|S=i" => \$max_score, @@ -102,6 +106,14 @@ sub add_bam_track { } $bam_entry->{style}->{className} = $classname; } + if ($histograms) { + $bigwig_url = $bam_url; + $bigwig_url =~ s/\.bam$/\.bw/g; + $bam_entry->{histograms} = { + storeClass => $BIGWIG_STORE_CLASS, + urlTemplate => $bigwig_url + }; + } } else { $bam_entry->{min_score} = $min_score; @@ -146,6 +158,7 @@ =head1 USAGE --bam_url \ [ --key ] \ [ --classname ] \ + [ --histograms ] \ [ --coverage ] \ [ --min_score ] \ [ --max_score ] \ @@ -179,6 +192,10 @@ =head1 ARGUMENTS CSS class for display [default: bam] +=item --histograms + +display coverage depth when zoomed out (needs BW file correlated to BAM file, with same path and name but extension .bw) + =item --coverage display coverage data instead of alignments From 2cd9b786ff47550f3bb77d608a625782cc075f18 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Sat, 3 Feb 2018 14:16:41 -0800 Subject: [PATCH 05/86] remove wig2png from build --- build/Makefile | 7 ------- 1 file changed, 7 deletions(-) diff --git a/build/Makefile b/build/Makefile index 5a3fc140e..6980b4ca3 100644 --- a/build/Makefile +++ b/build/Makefile @@ -148,13 +148,6 @@ release-min-test: release-min cd $(RELEASE_MIN_DIR) && ./setup.sh legacy cd $(RELEASE_MIN_DIR) && prove -Isrc/perl5 -r -j3 tests/perl_tests; -bin/wig2png: src/wig2png/Makefile - $(MAKE) -C src/wig2png; -src/wig2png/Makefile: src/wig2png/configure - cd src/wig2png && ./configure -src/wig2png/configure: src/wig2png/configure.in - cd src/wig2png && autoconf - superclean: clean -git clean -fdx --exclude=plugins/ \ --exclude src/FileSaver/ \ From 1c9e5a1b48314ca4f9607c442e53f5331a966006 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Sun, 4 Feb 2018 12:38:42 -0800 Subject: [PATCH 06/86] insert the release tag version into the package.json files --- .travis.yml | 18 ++++++++-- build/Makefile | 2 +- .../insert_tag_version_into_package_jsons.pl | 33 +++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100755 build/insert_tag_version_into_package_jsons.pl diff --git a/.travis.yml b/.travis.yml index aa917279a..e95b338cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,8 +36,22 @@ script: - jshint src/JBrowse/ - prove -j4 -Isrc/perl5 -lr tests/perl_tests - MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/ - # only run `make release` for builds on master, or on a tag, or on a pull request - - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; fi + # if this is a release tag, then update both package.json files with the version in the tag + - | + if [[ "x$TRAVIS_TAG" != "x" ]]; then + build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json + fi + # run `make release` for builds on master, or on a tag, or on a pull request + - | + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then + make -f build/Makefile release; + fi + # if this is a release tag, then upload the built release to github releases + - | + if [[ "x$TRAVIS_TAG" != "x" ]]; then + #TODO + fi + after_failure: - cat JBrowse-1.x.x-dev/setup.log - find JBrowse-1.x.x-dev/extlib/lib/perl5 diff --git a/build/Makefile b/build/Makefile index 6980b4ca3..e3ee5577e 100644 --- a/build/Makefile +++ b/build/Makefile @@ -21,7 +21,7 @@ UNZIP=unzip -q SHASUM=shasum -all: docs bin/wig2png +all: docs release-version.txt: echo $(RELEASE_VERSION) > release-version.txt diff --git a/build/insert_tag_version_into_package_jsons.pl b/build/insert_tag_version_into_package_jsons.pl new file mode 100755 index 000000000..648f22393 --- /dev/null +++ b/build/insert_tag_version_into_package_jsons.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl + + +# this is a little script that parses the TRAVIS_TAG env variable and, if it is like "1.x.x-release", +# inserts the version into the json files listed on the command line + + +use strict; +use warnings; + +use FindBin qw($RealBin); +use lib "$RealBin/../src/perl5"; + +use JBlibs; + +use JSON 2; + +local $/; + +my $release = $ENV{TRAVIS_TAG}; +$release =~ s/\-release$// + or die "no TRAVIS_TAG env var defined or it's malformed. expecting something like '1.12.4-release'."; + +print "detected release tag $ENV{TRAVIS_TAG} for version $release\n"; + +my $json = JSON->new->pretty->canonical; +for my $filename (@ARGV) { + print "inserting version $release into $filename\n"; + my $j = $json->decode( <> ); + $j->{version} = $release; + open my $f, '>', $filename or die "$! writing $filename"; + $f->print( $json->encode($j) ); +} From a1dd4aa3156ad10675d5d020b4f3285cafa70a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loraine=20Gu=C3=A9guen?= Date: Mon, 5 Feb 2018 13:45:55 +0100 Subject: [PATCH 07/86] add time_dilation in yeast_biodb_test.py --- tests/selenium_tests/yeast_biodb_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/selenium_tests/yeast_biodb_test.py b/tests/selenium_tests/yeast_biodb_test.py index ec67faaf5..0da674065 100644 --- a/tests/selenium_tests/yeast_biodb_test.py +++ b/tests/selenium_tests/yeast_biodb_test.py @@ -79,7 +79,7 @@ def search_yal024c( self ): # Find the query box and put YAL024C into it and hit enter self.do_typed_query( 'YAL024C' ) - time.sleep(1) # cannot seem to figure out a positive wait for an element that works here :-( + time.sleep(1*JBrowseTest.time_dilation) # cannot seem to figure out a positive wait for an element that works here :-( # test that the YAL024C label appeared in the DOM (TODO: check that it's # actually centered in the window), and that the protein-coding From dfe7d2651cc5b92de438eebd521d6d7cf546e9e2 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 11:58:34 -0800 Subject: [PATCH 08/86] add under-construction release directories to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fb88b228b..40c62dabd 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ themes/*/css .sass-cache .vscode/ *driver.log +JBrowse-*/ From bbb87a164197e863ebd40b7a1b32d8b2e3f25c30 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 12:12:50 -0800 Subject: [PATCH 09/86] remove stray references to wig2png in build, etc --- .gitignore | 5 ----- build/Makefile | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 40c62dabd..739adb1c3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,14 +3,10 @@ .#* \#*\# *.index -/bin/wig2png *.pyc *TODO.txt Makefile /sample_data/json -/src/wig2png/config.log -/src/wig2png/config.status -/src/wig2png/src/config.h /docs/jsdoc/ /*-debug.html /extlib* @@ -46,7 +42,6 @@ _Inline .DS_Store blib pm_to_blib -bin/wig2png.dSYM bower_components src/dojo-themes themes/*/css diff --git a/build/Makefile b/build/Makefile index e3ee5577e..32bd27723 100644 --- a/build/Makefile +++ b/build/Makefile @@ -108,8 +108,7 @@ release-min: release-normal plugins-min for P in src docs/jsdoc tests tests_extended build; do \ rm -rf $(RELEASE_MIN_DIR)$$P; \ done; - for P in src/wig2png \ - src/dojo/dojo.js \ + for P in src/dojo/dojo.js \ `find src/ -name nls -and -type d -and -not -wholename '*/tests/*' | grep -v src/dojox/grid` \ src/dojo/resources \ src/dojox/grid \ From bd635700c59c870475f54bfc91c34a597378e94f Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 16:05:15 -0800 Subject: [PATCH 10/86] make build process work if you have not run setup.sh --- build/Makefile | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/build/Makefile b/build/Makefile index 32bd27723..485342141 100644 --- a/build/Makefile +++ b/build/Makefile @@ -59,7 +59,10 @@ release-electron-all: release-notest release-notes.html: release-notes.txt build/format_release_notes.pl $< > $@ -release-normal: superclean $(JS_SRCFILES) +node_modules: + npm install + +release-normal: superclean $(JS_SRCFILES) node_modules mkdir $(RELEASE_FULL_DIR); cp -R `ls -1d * | grep -v $(RELEASE_FULL)` $(RELEASE_FULL_DIR); rm -rf $(RELEASE_FULL_DIR)/src/*/.git $(RELEASE_FULL_DIR)/$(RELEASE_FULL) $(RELEASE_FULL_DIR)/src/util $(RELEASE_FULL_DIR)/build; @@ -148,21 +151,7 @@ release-min-test: release-min cd $(RELEASE_MIN_DIR) && prove -Isrc/perl5 -r -j3 tests/perl_tests; superclean: clean - -git clean -fdx --exclude=plugins/ \ - --exclude src/FileSaver/ \ - --exclude src/dbind/ \ - --exclude src/dgrid/ \ - --exclude src/dstore/ \ - --exclude src/dijit/ \ - --exclude src/dojo/ \ - --exclude src/dojox/ \ - --exclude src/jDataView/ \ - --exclude src/json-schema/ \ - --exclude src/jszlib/ \ - --exclude src/lazyload/ \ - --exclude src/put-selector/ \ - --exclude src/util/ \ - --exclude src/xstyle/ + git clean -fdxq --exclude=plugins clean: rm -rf docs/jsdoc *-min.js release-notes.html; From fdbb1a5e8fc05947511621123ce18dfd527a93f8 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 16:48:25 -0800 Subject: [PATCH 11/86] fix plugins exclude so that it does not apply to the plugins dirs inside the built dirs --- build/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Makefile b/build/Makefile index 485342141..f6c71e7e5 100644 --- a/build/Makefile +++ b/build/Makefile @@ -151,7 +151,7 @@ release-min-test: release-min cd $(RELEASE_MIN_DIR) && prove -Isrc/perl5 -r -j3 tests/perl_tests; superclean: clean - git clean -fdxq --exclude=plugins + git clean -fdxq --exclude=./plugins clean: rm -rf docs/jsdoc *-min.js release-notes.html; From ca0b2dfa54cc824bd330f867eabe37616dd27fac Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 17:12:05 -0800 Subject: [PATCH 12/86] first crack at moving built-release testing into travis --- .travis.yml | 31 ++++++++++++++++++++++--------- build/Makefile | 26 +++----------------------- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index e95b338cc..ba65ceaa8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,21 +30,34 @@ install: - source ~/python/bin/activate - pip install nose selenium - bash setup.sh legacy -before_script: - - ./jb_run.js -p 9000 & +# NOTE: travis supports build stages and matrixes and stuff to implement this more symbolically, +# but the shell conditionals seem more straightforward for now script: - jshint src/JBrowse/ - - prove -j4 -Isrc/perl5 -lr tests/perl_tests - - MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/ # if this is a release tag, then update both package.json files with the version in the tag - | if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json fi - # run `make release` for builds on master, or on a tag, or on a pull request + # run tests in built release for builds on master, tags, or pull reqs, otherwise run tests in root - | - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = 'continuous_deployment' || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; + for zip in JBrowse-*.zip; do + rm -rf JBrowse-*/; + unzip JBrowse-*.zip; + cp -r tests/ JBrowse-*/; + cd JBrowse-*/ + ./setup.sh legacy; + prove -Isrc/perl5 -r -j3 tests/perl_tests; + ./jb_run.js -p 9000 & + MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/; + killall jb_run.js; + done; + else + ./jb_run.js -p 9000 & + prove -j4 -Isrc/perl5 -lr tests/perl_tests + MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/ fi # if this is a release tag, then upload the built release to github releases - | @@ -53,6 +66,6 @@ script: fi after_failure: - - cat JBrowse-1.x.x-dev/setup.log - - find JBrowse-1.x.x-dev/extlib/lib/perl5 - - cat JBrowse-1.x.x-dev/src/build-report.txt + - cat JBrowse-*-dev/setup.log + - find JBrowse-*-dev/extlib/lib/perl5 + - cat JBrowse-*-dev/src/build-report.txt diff --git a/build/Makefile b/build/Makefile index f6c71e7e5..5ee431168 100644 --- a/build/Makefile +++ b/build/Makefile @@ -26,13 +26,11 @@ all: docs release-version.txt: echo $(RELEASE_VERSION) > release-version.txt -release: release-version.txt release-normal release-min release-normal-test release-min-test release-notes.html +release: release-version.txt release-normal release-min release-notes.html ls -lh *.zip $(SHASUM) *.zip -release-notest: release-version.txt release-normal release-min release-notes.html - ls -lh *.zip - $(SHASUM) *.zip +release-notest: release release-electron-darwin: release-notest cd $(RELEASE_MIN)&&./setup.sh legacy&&cd .. @@ -78,15 +76,6 @@ release-normal: superclean $(JS_SRCFILES) node_modules # zip up the dev release $(ZIP) $(RELEASE_FULL).zip $(RELEASE_FULL)/; -release-normal-test: release-normal - # unzip to make sure we are looking at what's really in the releases - rm -rf $(RELEASE_FULL_DIR); - $(UNZIP) $(RELEASE_FULL).zip - cd $(RELEASE_FULL_DIR) \ - && ./setup.sh legacy \ - && prove -Isrc/perl5 -r -j3 tests/perl_tests; - - PLUGINS = $(wildcard $(PLUGINDIR)/*) plugins-min: release-normal @@ -141,19 +130,10 @@ release-min: release-normal plugins-min # zip it up $(ZIP) $(RELEASE_MIN).zip $(RELEASE_MIN)/; -release-min-test: release-min - # unzip to make sure we are looking at what's really in the releases - rm -rf $(RELEASE_MIN_DIR); - $(UNZIP) $(RELEASE_MIN).zip - rm $(RELEASE_MIN_DIR)/sample_data/raw/volvox - cp -R docs tests* sample_data $(RELEASE_MIN_DIR); - cd $(RELEASE_MIN_DIR) && ./setup.sh legacy - cd $(RELEASE_MIN_DIR) && prove -Isrc/perl5 -r -j3 tests/perl_tests; - superclean: clean git clean -fdxq --exclude=./plugins clean: rm -rf docs/jsdoc *-min.js release-notes.html; -.PHONY: all clean superclean jbrowse docs doc release release-min release-normal release-normal-test release-min-test plugins-min +.PHONY: all clean superclean jbrowse docs doc release release-min release-normal plugins-min From 499c2c78d40f35ae5532168e6ef3a1c1e90f3596 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 17:17:51 -0800 Subject: [PATCH 13/86] update travis dist to precise --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ba65ceaa8..ad6184023 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: false -dist: trusty +dist: precise language: perl python: "2.7.10" perl: From 62ce4079770ff01286d3528bddbffed391e37605 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 17:32:33 -0800 Subject: [PATCH 14/86] prototype configuration for making github releases --- .travis.yml | 70 +++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index ad6184023..80ebcc2dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,46 +1,38 @@ sudo: false dist: precise language: perl -python: "2.7.10" +python: 2.7.10 perl: - - "5.26" - - "5.14" +- '5.26' +- '5.14' addons: apt: packages: - libdb-dev - libgd2-noxpm-dev - firefox: "58.0" + firefox: '58.0' cache: - - extlib/ - - $HOME/perl5/ +- extlib/ +- "$HOME/perl5/" before_install: - #install geckodriver for the selenium tests :-P - - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz - - mkdir geckodriver - - tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C geckodriver - - export PATH=$PATH:$PWD/geckodriver - # install perl deps - - cpanm --notest GD::Image Text::Markdown DateTime - #- cpanm --notest git://github.com/bioperl/bioperl-live.git@v1.6.x - # and jshint for the JS code - - npm install -g jshint +- wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz +- mkdir geckodriver +- tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C geckodriver +- export PATH=$PATH:$PWD/geckodriver +- cpanm --notest GD::Image Text::Markdown DateTime +- npm install -g jshint install: - - virtualenv ~/python - - source ~/python/bin/activate - - pip install nose selenium - - bash setup.sh legacy -# NOTE: travis supports build stages and matrixes and stuff to implement this more symbolically, -# but the shell conditionals seem more straightforward for now +- virtualenv ~/python +- source ~/python/bin/activate +- pip install nose selenium +- bash setup.sh legacy script: - - jshint src/JBrowse/ - # if this is a release tag, then update both package.json files with the version in the tag - - | - if [[ "x$TRAVIS_TAG" != "x" ]]; then +- jshint src/JBrowse/ +- | + if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json fi - # run tests in built release for builds on master, tags, or pull reqs, otherwise run tests in root - - | +- | if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = 'continuous_deployment' || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; for zip in JBrowse-*.zip; do @@ -59,13 +51,23 @@ script: prove -j4 -Isrc/perl5 -lr tests/perl_tests MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/ fi - # if this is a release tag, then upload the built release to github releases - - | - if [[ "x$TRAVIS_TAG" != "x" ]]; then +- | + if [[ "x$TRAVIS_TAG" != "x" ]]; then #TODO fi after_failure: - - cat JBrowse-*-dev/setup.log - - find JBrowse-*-dev/extlib/lib/perl5 - - cat JBrowse-*-dev/src/build-report.txt +- cat JBrowse-*-dev/setup.log +- find JBrowse-*-dev/extlib/lib/perl5 +- cat JBrowse-*-dev/src/build-report.txt +deploy: + provider: releases + api_key: + secure: BuOD7rqrcGKT3g0hVY5AGpJI/Kkko4DhSIYSUQ28sS2AOdoNyTD0t5doL/Kiq4BC41q198tbFFt1dnXGdo8YKpBSXO/uGUuuiGtMFHM++I84oLq20p49iyrenNZ4m/jy/Q4YtizIYLs83DVzVdQzhJ5hrTx6f+d1gc9EgaMeBF4= + file: JBrowse-1.*.zip + file_glob: true + skip_cleanup: true + on: + repo: GMOD/jbrowse +# tags: true + branch: continuous_deployment From 7541d60465b0ce5c990a4d2524356d35f4c08d33 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 5 Feb 2018 17:51:22 -0800 Subject: [PATCH 15/86] put travis dist back on trusty --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80ebcc2dd..42c77fc0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: false -dist: precise +dist: trusty language: perl python: 2.7.10 perl: From 52d43d7cc5ac42c9e1079efba696f4adb3708ad1 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 12:05:41 -0800 Subject: [PATCH 16/86] rearrange travis testing strategy --- .travis.yml | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42c77fc0b..c74a27452 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,45 +21,28 @@ before_install: - export PATH=$PATH:$PWD/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime - npm install -g jshint -install: - virtualenv ~/python - source ~/python/bin/activate - pip install nose selenium +install: - bash setup.sh legacy script: - jshint src/JBrowse/ -- | - if [[ "x$TRAVIS_TAG" != "x" ]]; then - build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json - fi -- | - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = 'continuous_deployment' || $TRAVIS_PULL_REQUEST != "false" ]]; then - make -f build/Makefile release; - for zip in JBrowse-*.zip; do - rm -rf JBrowse-*/; - unzip JBrowse-*.zip; - cp -r tests/ JBrowse-*/; - cd JBrowse-*/ - ./setup.sh legacy; - prove -Isrc/perl5 -r -j3 tests/perl_tests; - ./jb_run.js -p 9000 & - MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/; - killall jb_run.js; - done; - else - ./jb_run.js -p 9000 & - prove -j4 -Isrc/perl5 -lr tests/perl_tests - MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/ - fi -- | - if [[ "x$TRAVIS_TAG" != "x" ]]; then - #TODO - fi - +- RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))` +- if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi +- make -f build/Makefile release; +- rm -rf JBrowse-*/; +- unzip JBrowse-$RELEASE_VERSION.zip; +- cp -r tests/ JBrowse-$RELEASE_VERSION/; +- cd JBrowse-$RELEASE_VERSION/ +- ./setup.sh legacy; +- prove -Isrc/perl5 -r -j3 tests/perl_tests; +- ./jb_run.js -p 9000 & +- MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/; after_failure: -- cat JBrowse-*-dev/setup.log -- find JBrowse-*-dev/extlib/lib/perl5 -- cat JBrowse-*-dev/src/build-report.txt +- cat JBrowse-*/setup.log +- find JBrowse-*/extlib/lib/perl5 +- cat JBrowse-*/src/build-report.txt deploy: provider: releases api_key: From 75ee192eee29ffc1b6f65e6df2fee7887ab5d320 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 12:11:07 -0800 Subject: [PATCH 17/86] debugging travis build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c74a27452..3c58c2f51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ install: - bash setup.sh legacy script: - jshint src/JBrowse/ -- RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))` +- RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - make -f build/Makefile release; - rm -rf JBrowse-*/; From 02eae2721754cd2bcea198091f44e7af088cbad2 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 12:41:31 -0800 Subject: [PATCH 18/86] debugging travis build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3c58c2f51..bc68fb3f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ before_install: - mkdir geckodriver - tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C geckodriver - export PATH=$PATH:$PWD/geckodriver +- which geckodriver - cpanm --notest GD::Image Text::Markdown DateTime - npm install -g jshint - virtualenv ~/python @@ -27,6 +28,7 @@ before_install: install: - bash setup.sh legacy script: +- which geckodriver - jshint src/JBrowse/ - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi From 35920bdec33e2bb41c449c5be32e20ff578f968d Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 13:04:08 -0800 Subject: [PATCH 19/86] reduce build verbosity --- .travis.yml | 2 +- build/Makefile | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index bc68fb3f1..e23d52a16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ script: - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - make -f build/Makefile release; - rm -rf JBrowse-*/; -- unzip JBrowse-$RELEASE_VERSION.zip; +- unzip -q JBrowse-$RELEASE_VERSION.zip; - cp -r tests/ JBrowse-$RELEASE_VERSION/; - cd JBrowse-$RELEASE_VERSION/ - ./setup.sh legacy; diff --git a/build/Makefile b/build/Makefile index 5ee431168..6fb77b84b 100644 --- a/build/Makefile +++ b/build/Makefile @@ -84,7 +84,8 @@ plugins-min: release-normal node $(BASEDIR)/src/dojo/dojo.js load=build \ --require "$(JSDIR)/init.js" \ --profile "$$pdir/js/$$pname" \ - --releaseDir "$(RELEASE_FULL_DIR)/plugins/$$pname/built"; \ + --releaseDir "$(RELEASE_FULL_DIR)/plugins/$$pname/built" \ + 2>&1 | grep -v '^warn'; \ rm -rf "$(RELEASE_FULL_DIR)/plugins/$$pname/js"; \ mv "$(RELEASE_FULL_DIR)/plugins/$$pname/built/$$pname" "$(RELEASE_FULL_DIR)/plugins/$$pname/js"; \ rm -rf "$(RELEASE_FULL_DIR)/plugins/$$pname/built"; \ @@ -93,7 +94,12 @@ plugins-min: release-normal release-min: release-normal plugins-min # run the dojo build in the full dir to minify - node src/dojo/dojo.js load=build --require "$(JSDIR)/init.js" --profile "$(JSDIR)/JBrowse.profile.js" --releaseDir "$(RELEASE_FULL_DIR)/src"; + node src/dojo/dojo.js \ + load=build \ + --require "$(JSDIR)/init.js" \ + --profile "$(JSDIR)/JBrowse.profile.js" \ + --releaseDir "$(RELEASE_FULL_DIR)/src" \ + 2>&1 | grep -v '^warn'; cp -a $(RELEASE_FULL_DIR) $(RELEASE_MIN_DIR); From f383858b9baf689ae43431b35e3deb34b2405f7e Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 13:04:20 -0800 Subject: [PATCH 20/86] tweak build dir caching --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e23d52a16..1c37eb5b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,10 @@ addons: - libgd2-noxpm-dev firefox: '58.0' cache: -- extlib/ -- "$HOME/perl5/" + directories: + - extlib/ + - "$HOME/perl5/" + - node_modules/ before_install: - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz - mkdir geckodriver From fd7b27d50c4586c53128d0e94beea42e41b2d0d8 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 13:11:38 -0800 Subject: [PATCH 21/86] add ~/python to build cache --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1c37eb5b2..d3a627523 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ cache: - extlib/ - "$HOME/perl5/" - node_modules/ + - "$HOME/python/" before_install: - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz - mkdir geckodriver From e0775075eec8edc1d92275034eb0c27604581459 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 13:31:05 -0800 Subject: [PATCH 22/86] speed up build by linking already-setup dep dirs --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index d3a627523..841677f43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,8 @@ script: - unzip -q JBrowse-$RELEASE_VERSION.zip; - cp -r tests/ JBrowse-$RELEASE_VERSION/; - cd JBrowse-$RELEASE_VERSION/ +- ln -s ../node_modules +- ln -s ../extlib - ./setup.sh legacy; - prove -Isrc/perl5 -r -j3 tests/perl_tests; - ./jb_run.js -p 9000 & From 7919b76aede05b37a5e558437e6a2a51d0e227a2 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 13:39:41 -0800 Subject: [PATCH 23/86] install geckodriver in ~ so the build doesnt delete it --- .travis.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 841677f43..960b31c4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,10 +19,9 @@ cache: - "$HOME/python/" before_install: - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz -- mkdir geckodriver -- tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C geckodriver -- export PATH=$PATH:$PWD/geckodriver -- which geckodriver +- mkdir ~/geckodriver +- tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C ~/geckodriver +- export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime - npm install -g jshint - virtualenv ~/python @@ -31,7 +30,6 @@ before_install: install: - bash setup.sh legacy script: -- which geckodriver - jshint src/JBrowse/ - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi From 8ff79b89025045695fdbe42ed6f9106530d06cb0 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 13:48:45 -0800 Subject: [PATCH 24/86] skip running minification unless we are in a tag, in master, or in a pull request --- .travis.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 960b31c4e..cb8ac1769 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,13 +33,14 @@ script: - jshint src/JBrowse/ - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi -- make -f build/Makefile release; -- rm -rf JBrowse-*/; -- unzip -q JBrowse-$RELEASE_VERSION.zip; -- cp -r tests/ JBrowse-$RELEASE_VERSION/; -- cd JBrowse-$RELEASE_VERSION/ -- ln -s ../node_modules -- ln -s ../extlib +- | + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then + make -f build/Makefile release; + rm -rf JBrowse-*/; + unzip -q JBrowse-$RELEASE_VERSION.zip; + cp -r tests/ JBrowse-$RELEASE_VERSION/; + cd JBrowse-$RELEASE_VERSION/; + fi - ./setup.sh legacy; - prove -Isrc/perl5 -r -j3 tests/perl_tests; - ./jb_run.js -p 9000 & From 77ea3da494cc81bac3ffc0adbcea1198c701bb66 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 14:27:42 -0800 Subject: [PATCH 25/86] test minified testing --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cb8ac1769..de9cf4c34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ script: - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - | - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "continuous_deployment" || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; rm -rf JBrowse-*/; unzip -q JBrowse-$RELEASE_VERSION.zip; From c709c0f58daa20ca14fb3ffe6a72531e79289d02 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 16:24:08 -0800 Subject: [PATCH 26/86] add missing jDataView to min build --- build/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/build/Makefile b/build/Makefile index 6fb77b84b..5058eaf0c 100644 --- a/build/Makefile +++ b/build/Makefile @@ -120,6 +120,7 @@ release-min: release-normal plugins-min src/JBrowse \ src/perl5 \ src/dgrid/css \ + src/jDataView \ ; do \ mkdir -p `dirname $(RELEASE_MIN_DIR)$$P`; \ if [ -d $$P ]; then \ From e9b82e5565e51dce5e01e03675851c704563b130 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 16:41:34 -0800 Subject: [PATCH 27/86] fix minification for new dojo --- build/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/build/Makefile b/build/Makefile index 5058eaf0c..49f9ef645 100644 --- a/build/Makefile +++ b/build/Makefile @@ -130,8 +130,6 @@ release-min: release-normal plugins-min fi;\ done - mv $(RELEASE_MIN_DIR)/src/dojo/nls $(RELEASE_MIN_DIR)/src/nls; - find $(RELEASE_MIN_DIR) -name '*.uncompressed.js' -or -name '*.consoleStripped.js' -exec rm {} ';' # zip it up From f672f33e4ceed13d0ea04ca9d1d7a522f96053ed Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 17:03:26 -0800 Subject: [PATCH 28/86] debugging minimization some more --- build/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/Makefile b/build/Makefile index 49f9ef645..32023e399 100644 --- a/build/Makefile +++ b/build/Makefile @@ -130,6 +130,8 @@ release-min: release-normal plugins-min fi;\ done + cp -r $(RELEASE_MIN_DIR)/src/dojo/nls $(RELEASE_MIN_DIR)/src/nls; + find $(RELEASE_MIN_DIR) -name '*.uncompressed.js' -or -name '*.consoleStripped.js' -exec rm {} ';' # zip it up From d2cc019f3567007d5a9d032e86fcd29e355d2175 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 17:20:59 -0800 Subject: [PATCH 29/86] trying to get it to upload the built zip file to GH releases --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index de9cf4c34..926bf1056 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ install: script: - jshint src/JBrowse/ - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` +- BUILD_DIR=$PWD - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - | if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "continuous_deployment" || $TRAVIS_PULL_REQUEST != "false" ]]; then @@ -45,6 +46,7 @@ script: - prove -Isrc/perl5 -r -j3 tests/perl_tests; - ./jb_run.js -p 9000 & - MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/; +- cd $BUILD_DIR after_failure: - cat JBrowse-*/setup.log - find JBrowse-*/extlib/lib/perl5 From 468d65c71c26f57c4be5d550fbce6dd965e50cbd Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 17:26:15 -0800 Subject: [PATCH 30/86] remove redundant setup.sh run --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 926bf1056..339833289 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ cache: - "$HOME/perl5/" - node_modules/ - "$HOME/python/" -before_install: +install: - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz - mkdir ~/geckodriver - tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C ~/geckodriver @@ -27,8 +27,6 @@ before_install: - virtualenv ~/python - source ~/python/bin/activate - pip install nose selenium -install: -- bash setup.sh legacy script: - jshint src/JBrowse/ - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` From 85c63f597aec36d031fd0a0886dab343b6766052 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 6 Feb 2018 17:45:43 -0800 Subject: [PATCH 31/86] remove debugging code in preparation for merging --- .travis.yml | 7 +++---- release-notes.txt | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 339833289..e99d0d32c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,11 +29,11 @@ install: - pip install nose selenium script: - jshint src/JBrowse/ +- if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - BUILD_DIR=$PWD -- if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - | - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "continuous_deployment" || $TRAVIS_PULL_REQUEST != "false" ]]; then + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; rm -rf JBrowse-*/; unzip -q JBrowse-$RELEASE_VERSION.zip; @@ -58,5 +58,4 @@ deploy: skip_cleanup: true on: repo: GMOD/jbrowse -# tags: true - branch: continuous_deployment + tags: true diff --git a/release-notes.txt b/release-notes.txt index 5eb58c543..9531dcf0d 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -1,5 +1,7 @@ {{$NEXT}} +# Release 1.x.x 2018-02-06 17:04:17 America/Los_Angeles + ## Minor improvements * Fixed SEVERE performance regression that basically made flatfile-to-json.pl From 62095896673f40d9fd1d11d5de61d54bb9b92ff1 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 00:28:11 -0800 Subject: [PATCH 32/86] tweak package.json updating script to not require setup.sh to have been run --- .travis.yml | 2 +- build/insert_tag_version_into_package_jsons.pl | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index e99d0d32c..5adae4591 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ install: - mkdir ~/geckodriver - tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C ~/geckodriver - export PATH=$PATH:$HOME/geckodriver -- cpanm --notest GD::Image Text::Markdown DateTime +- cpanm --notest GD::Image Text::Markdown DateTime JSON - npm install -g jshint - virtualenv ~/python - source ~/python/bin/activate diff --git a/build/insert_tag_version_into_package_jsons.pl b/build/insert_tag_version_into_package_jsons.pl index 648f22393..9e6071465 100755 --- a/build/insert_tag_version_into_package_jsons.pl +++ b/build/insert_tag_version_into_package_jsons.pl @@ -4,15 +4,9 @@ # this is a little script that parses the TRAVIS_TAG env variable and, if it is like "1.x.x-release", # inserts the version into the json files listed on the command line - use strict; use warnings; -use FindBin qw($RealBin); -use lib "$RealBin/../src/perl5"; - -use JBlibs; - use JSON 2; local $/; From 476696b3a435c17785c2e5267b2d261b9bdfc164 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 00:57:27 -0800 Subject: [PATCH 33/86] fix release-version-inserting script --- build/insert_tag_version_into_package_jsons.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build/insert_tag_version_into_package_jsons.pl b/build/insert_tag_version_into_package_jsons.pl index 9e6071465..21954c762 100755 --- a/build/insert_tag_version_into_package_jsons.pl +++ b/build/insert_tag_version_into_package_jsons.pl @@ -9,7 +9,6 @@ use JSON 2; -local $/; my $release = $ENV{TRAVIS_TAG}; $release =~ s/\-release$// @@ -20,8 +19,13 @@ my $json = JSON->new->pretty->canonical; for my $filename (@ARGV) { print "inserting version $release into $filename\n"; - my $j = $json->decode( <> ); + my $j = do { + local $/; + open my $f, '<', $filename or die "$! reading $filename"; + $json->decode( <$f> ); + }; $j->{version} = $release; + open my $f, '>', $filename or die "$! writing $filename"; $f->print( $json->encode($j) ); } From f12e945e4bcf40146e8403a2a785addbb02b9a41 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 01:05:10 -0800 Subject: [PATCH 34/86] restrict deploys to only happen on perl 5.26 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5adae4591..b4e55d6be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,4 +58,5 @@ deploy: skip_cleanup: true on: repo: GMOD/jbrowse + perl: 5.26 tags: true From 42823fbe212d117618e0dce52721ed6179d783db Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 01:28:48 -0800 Subject: [PATCH 35/86] remove stray release date in release notes --- release-notes.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/release-notes.txt b/release-notes.txt index 9531dcf0d..5eb58c543 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -1,7 +1,5 @@ {{$NEXT}} -# Release 1.x.x 2018-02-06 17:04:17 America/Los_Angeles - ## Minor improvements * Fixed SEVERE performance regression that basically made flatfile-to-json.pl From 40d99b0af2daa9f9ce8a19a87eaefd1e7fe5db19 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 01:30:50 -0800 Subject: [PATCH 36/86] only run virtualenv if we don't have a cached python dir --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b4e55d6be..0601e4469 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ install: - export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime JSON - npm install -g jshint -- virtualenv ~/python +- if [[ ! -d ~/python ]]; then virtualenv ~/python; fi - source ~/python/bin/activate - pip install nose selenium script: From 178ad0ff1904f10a77468e7508acf7f65ae0c222 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 01:38:49 -0800 Subject: [PATCH 37/86] add ~/.nvm to build cache so that our jshint install is cached --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0601e4469..f78f7545d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ cache: - "$HOME/perl5/" - node_modules/ - "$HOME/python/" + - "$HOME/.nvm/" install: - wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz - mkdir ~/geckodriver From a18a0aa6c4de4fab57bdd6ad4617ec0255090af9 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 11:51:11 -0800 Subject: [PATCH 38/86] look for virtualenv activate script to determine whether virtualenv needs to be run, instead of just the python directory --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f78f7545d..1dc023e17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ install: - export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime JSON - npm install -g jshint -- if [[ ! -d ~/python ]]; then virtualenv ~/python; fi +- if [[ ! -f ~/python/bin/activate ]]; then virtualenv ~/python; fi - source ~/python/bin/activate - pip install nose selenium script: From 63cdc981e1ab12392b5942b24477201332810776 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 12:13:51 -0800 Subject: [PATCH 39/86] update README.md for the new release procedure --- README.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ddb102825..3b9696569 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,7 @@ This allows JBrowse to be easily integrated into other applications. `jb_setup. You can also optionally run build steps to create the minimized codebase. Extra perl dependencies Text::Markdown and DateTime are required to run the build step. - make -f build/Makefile release-notest - make -f build/Makefile release # alternate build with full test suite + make -f build/Makefile release To build the Electron app (JBrowse desktop app), run the following @@ -72,29 +71,25 @@ eggs for `selenium` and `nose` installed. Run the tests with: MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL='http://localhost/jbrowse/index.html' nosetests -Supported browsers are 'firefox', 'chrome', 'phantom', and 'travis_saucelabs'. The Sauce Labs + Travis one will only work properly in a properly configured Travis CI build environment. +Supported browsers are 'firefox', 'chrome', 'phantom', and 'travis_saucelabs'. The Sauce Labs + Travis +one will only work in a properly configured Travis CI build environment. # Cutting a JBrowse release -1. Edit the JBrowse `package.json` file and change 'version' to the version you are releasing. *Don't commit this change to the repository, it should stay as `dev` in git so that it shows up in analytics as a development version.* +NOTE: Beginning in 1.12.4, -2. Build the release packages: `make -f build/Makefile release`. The files produced during the build should not be committed to the repository either. There is also `make -f build/Makefile release-notest` for releases that don't need perl tests to be run. NOTE: you may need to use the command `ulimit -n 1000` to avoid "spawn EMFILE" build errors. +1. Make a tag in the repository for the release, named, e.g. `1.6.3-release`. This should cause Travis CI +to create a release on GitHub under https://github.com/GMOD/jbrowse/releases -3. Make a tag in the repository for the release, named, e.g. `1.6.3-release`. +1. Add release notes to the new release that Travis created. -4. `scp` the release .zip files (min and full) to jbrowse.org. +1. Write a blog post announcing the release, with links to the built releases on GitHub. -5. Add them to the Wordpress Downloads list so that we can track how -many times they are downloaded. +1. Update the "Install" page on the site to point to the newest release. -6. Write a blog post announcing the release. The `release-notes.html` -file made during the build might be useful for this. +1. Update the latest-release code checkout on the site, which the "Latest Release" demo on the jbrowse.org points to, to be an unzipped-and-set-up copy of the latest release. -7. Update the "Install" page on the site to point to the newest release. - -8. Update the latest-release code checkout on the site, which the "Latest Release" demo on the jbrowse.org points to, to be an unzipped-and-set-up copy of the latest release. - -9. Write an email announcing the release, sending to gmod-ajax, +1. Write an email announcing the release, sending to gmod-ajax, jbrowse-dev. If it is a major release, add gmod-announce and make a GMOD news item. As you can tell, this process could really use some more streamlining and automation. From 596cd970f506d7f9004a718da9c258dd3eb9ce5e Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 14:15:31 -0800 Subject: [PATCH 40/86] add wrapper script for selenium tests that reruns them if they fail once --- .travis.yml | 2 +- tests/selenium_tests/travis_wrapper.sh | 27 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100755 tests/selenium_tests/travis_wrapper.sh diff --git a/.travis.yml b/.travis.yml index 1dc023e17..4891be8c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ script: - ./setup.sh legacy; - prove -Isrc/perl5 -r -j3 tests/perl_tests; - ./jb_run.js -p 9000 & -- MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html nosetests tests/selenium_tests/; +- MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html tests/selenium_tests/travis_wrapper.sh; - cd $BUILD_DIR after_failure: - cat JBrowse-*/setup.log diff --git a/tests/selenium_tests/travis_wrapper.sh b/tests/selenium_tests/travis_wrapper.sh new file mode 100755 index 000000000..cdff2bf27 --- /dev/null +++ b/tests/selenium_tests/travis_wrapper.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# wrapper for selenium tests meant to increase the robustness of the Travis build. +# if the selenium tests fail on the first run, runs them again to make sure it +# wasn't just a random failure. + +set +e + +nosetests . +FIRST_RUN_STATUS=$? + +if [[ $FIRST_RUN_STATUS -ne 0 ]]; then + echo + echo ============= FIRST SELENIUM RUN FAILED, RETRYING TO MAKE SURE =============== + echo + nosetests . + SECOND_RUN_STATUS=$? + if [[ $SECOND_RUN_STATUS -ne 0 ]]; then + echo ============= SELENIUM TEST FAILED ON SECOND RUN ============== + exit $SECOND_RUN_STATUS + fi +else + echo ============= SELENIUM TEST PASSED ON FIRST RUN =============== + exit 0 +fi + +echo ============= SELENIUM TEST PASSED ON SECOND RUN ============== From a5c5b68b03066537687a8a376d90f94e11c917bc Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 7 Feb 2018 15:24:45 -0800 Subject: [PATCH 41/86] do selenium testing against the built release on the `dev` branch as well --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4891be8c2..274cd15ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ script: - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - BUILD_DIR=$PWD - | - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "dev" || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; rm -rf JBrowse-*/; unzip -q JBrowse-$RELEASE_VERSION.zip; From 114d2c4c0632e4e6ad9c76a883c86704e00f4e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loraine=20Gu=C3=A9guen?= Date: Thu, 8 Feb 2018 10:12:50 +0100 Subject: [PATCH 42/86] Change option name. Add URL as argument. --- bin/add-bam-track.pl | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/bin/add-bam-track.pl b/bin/add-bam-track.pl index 9b1ef0f85..33537202a 100755 --- a/bin/add-bam-track.pl +++ b/bin/add-bam-track.pl @@ -22,9 +22,8 @@ my $out_file; my $label; my $bam_url; -my $bigwig_url; my $key; -my $histograms = undef; +my $bigwigCoverage = undef; my $coverage = 0; my $classname = undef; my $min_score = undef; @@ -42,7 +41,7 @@ sub parse_options { "bam_url|u=s" => \$bam_url, "key|k=s" => \$key, "classname|c=s" => \$classname, - "histograms|h" => \$histograms, + "bigwigCoverage|b=s" => \$bigwigCoverage, "coverage|C" => \$coverage, "min_score|s=i" => \$min_score, "max_score|S=i" => \$max_score, @@ -106,12 +105,10 @@ sub add_bam_track { } $bam_entry->{style}->{className} = $classname; } - if ($histograms) { - $bigwig_url = $bam_url; - $bigwig_url =~ s/\.bam$/\.bw/g; + if ($bigwigCoverage) { $bam_entry->{histograms} = { storeClass => $BIGWIG_STORE_CLASS, - urlTemplate => $bigwig_url + urlTemplate => $bigwigCoverage }; } } @@ -158,7 +155,7 @@ =head1 USAGE --bam_url \ [ --key ] \ [ --classname ] \ - [ --histograms ] \ + [ --bigwigCoverage ] \ [ --coverage ] \ [ --min_score ] \ [ --max_score ] \ @@ -192,9 +189,9 @@ =head1 ARGUMENTS CSS class for display [default: bam] -=item --histograms +=item --bigwigCoverage -display coverage depth when zoomed out (needs BW file correlated to BAM file, with same path and name but extension .bw) +URL to BW file correlated to BAM file. Display coverage depth when zoomed out. =item --coverage From 27ae2f9a9d87c0e2c10c6daf0e7bf84dc6107c44 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Thu, 8 Feb 2018 09:54:53 -0800 Subject: [PATCH 43/86] change travis build badge to point to dev branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b9696569..6b00ade13 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build status](https://travis-ci.org/GMOD/jbrowse.svg?branch=master)](https://travis-ci.org/GMOD/jbrowse) +[![Build status](https://travis-ci.org/GMOD/jbrowse.svg?branch=dev)](https://travis-ci.org/GMOD/jbrowse) # Installing JBrowse From 8ad937de9c2a92a1bd6785ed3b9c3c6f3f189880 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:28:51 -0800 Subject: [PATCH 44/86] fill in some more things in package.json --- .travis.yml | 10 +++++++++- package.json | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4891be8c2..15e16e5f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ after_failure: - find JBrowse-*/extlib/lib/perl5 - cat JBrowse-*/src/build-report.txt deploy: - provider: releases +- provider: releases api_key: secure: BuOD7rqrcGKT3g0hVY5AGpJI/Kkko4DhSIYSUQ28sS2AOdoNyTD0t5doL/Kiq4BC41q198tbFFt1dnXGdo8YKpBSXO/uGUuuiGtMFHM++I84oLq20p49iyrenNZ4m/jy/Q4YtizIYLs83DVzVdQzhJ5hrTx6f+d1gc9EgaMeBF4= file: JBrowse-1.*.zip @@ -61,3 +61,11 @@ deploy: repo: GMOD/jbrowse perl: 5.26 tags: true +- provider: npm + email: rbuels@gmail.com + api_key: + secure: mgvlVdeMAR35C69+NERuYK4YGwbBAQsnSXS7IJhn3CRNgbtWh2zqaVV8NbHWitD9RJmocTbkIe94MfD8HfI3zBAgIVewckQ0QWMyjAJuWJR2Zw91R309aIQpbsix4kNCP9RDDrtfzovptBJ6JS8UwEk5CsQ7Wfohctek59+UnyU= + on: + repo: GMOD/jbrowse + perl: 5.26 + tags: true diff --git a/package.json b/package.json index f172d6968..a9d3483c5 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,23 @@ { - "name": "jbrowse", + "name": "@gmod/jbrowse", "main": "browser/main.js", - "version": "1.12.4-SNAPSHOT", - "description": "JBrowse - Genome Browser (Client)", + "version": "1.x.x-dev", + "description": "JBrowse - client-side genome browser", "repository": "https://github.com/GMOD/jbrowse.git", "scripts": { "postinstall": "node utils/postinstall.js", "test": "phantomjs tests/js_tests/run-jasmine.js http://localhost/jbrowse/tests/js_tests/index.html", "start": "./jb_run.js -p 8082" }, + "publishConfig": { + "access": "public" + }, + "homepage": "http://jbrowse.org", + "bugs": { + "url": "https://github.com/GMOD/jbrowse/issues", + "email": "gmod-ajax@lists.sourceforge.net" + }, + "license": "(LGPL-2.1 OR Artistic-2.0)", "dependencies": { "app-root-path": "^2.0.1", "async": "^2.5.0", From 2d965778888feb8bf6cdfdddbb989604dd581996 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:37:11 -0800 Subject: [PATCH 45/86] add some comments to travis yml --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 15e16e5f5..48aa49d55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,17 @@ install: - export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime JSON - npm install -g jshint +# only init the python virtualenv if it did not show up in our build cache - if [[ ! -f ~/python/bin/activate ]]; then virtualenv ~/python; fi - source ~/python/bin/activate - pip install nose selenium script: - jshint src/JBrowse/ +# if we have a release tag, insert its version into the ./package.json and the src/JBrowse/package.json - if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - BUILD_DIR=$PWD +# if we are building for inclusion into the `dev` branch, run the minification and test against that - | if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; @@ -51,6 +54,7 @@ after_failure: - find JBrowse-*/extlib/lib/perl5 - cat JBrowse-*/src/build-report.txt deploy: +# upload minified builds to GitHub releases - provider: releases api_key: secure: BuOD7rqrcGKT3g0hVY5AGpJI/Kkko4DhSIYSUQ28sS2AOdoNyTD0t5doL/Kiq4BC41q198tbFFt1dnXGdo8YKpBSXO/uGUuuiGtMFHM++I84oLq20p49iyrenNZ4m/jy/Q4YtizIYLs83DVzVdQzhJ5hrTx6f+d1gc9EgaMeBF4= @@ -61,6 +65,7 @@ deploy: repo: GMOD/jbrowse perl: 5.26 tags: true +# upload regular non-minified version to npm - provider: npm email: rbuels@gmail.com api_key: From 251489af1ed564e1ce5a7168d9fefab349a5a8f1 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:37:32 -0800 Subject: [PATCH 46/86] cache geckdriver in the build cache --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48aa49d55..f45c97e54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,10 +18,14 @@ cache: - node_modules/ - "$HOME/python/" - "$HOME/.nvm/" + - "~/geckodriver" install: -- wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz -- mkdir ~/geckodriver -- tar -xzf geckodriver-v0.19.1-linux64.tar.gz -C ~/geckodriver +- | + if [[ ! -f ~/geckodriver/geckodriver ]]; then + rm -rf ~/geckodriver + mkdir ~/geckodriver + wget -O - https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz | tar -xzf - -C ~/geckodriver + done - export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime JSON - npm install -g jshint From 7f882a6083fd15fba94eb6918c6b04d92167f714 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:37:56 -0800 Subject: [PATCH 47/86] update build to test against minified when running on the dev branch --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f45c97e54..9c98cd234 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - BUILD_DIR=$PWD # if we are building for inclusion into the `dev` branch, run the minification and test against that - | - if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_PULL_REQUEST != "false" ]]; then + if [[ "x$TRAVIS_TAG" != "x" || $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "dev" || $TRAVIS_PULL_REQUEST != "false" ]]; then make -f build/Makefile release; rm -rf JBrowse-*/; unzip -q JBrowse-$RELEASE_VERSION.zip; From 3e56ef1921a21a6303f319bb07984a97a9119c38 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:46:39 -0800 Subject: [PATCH 48/86] fix geckodriver caching --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c98cd234..0bcc6cbb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,13 +18,13 @@ cache: - node_modules/ - "$HOME/python/" - "$HOME/.nvm/" - - "~/geckodriver" + - "$HOME/geckodriver" install: - | if [[ ! -f ~/geckodriver/geckodriver ]]; then - rm -rf ~/geckodriver - mkdir ~/geckodriver - wget -O - https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz | tar -xzf - -C ~/geckodriver + rm -rf ~/geckodriver; + mkdir ~/geckodriver; + wget -O - https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz | tar -xzf - -C ~/geckodriver; done - export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime JSON From 070c3c2bebebe07c95adac482b89e57a6dfc97e8 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:49:45 -0800 Subject: [PATCH 49/86] fix geckodriver caching --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0bcc6cbb1..b22a26799 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ install: rm -rf ~/geckodriver; mkdir ~/geckodriver; wget -O - https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz | tar -xzf - -C ~/geckodriver; - done + fi - export PATH=$PATH:$HOME/geckodriver - cpanm --notest GD::Image Text::Markdown DateTime JSON - npm install -g jshint From 7abca80da7b693bf34bc4b2f2af825731a6b6f4d Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 11:54:51 -0800 Subject: [PATCH 50/86] apparently the selenium wrapper script is not working --- tests/selenium_tests/travis_wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/selenium_tests/travis_wrapper.sh b/tests/selenium_tests/travis_wrapper.sh index cdff2bf27..0d9b57437 100755 --- a/tests/selenium_tests/travis_wrapper.sh +++ b/tests/selenium_tests/travis_wrapper.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # wrapper for selenium tests meant to increase the robustness of the Travis build. # if the selenium tests fail on the first run, runs them again to make sure it From 8475f1a65ef84efebd865cbf1a97a7b6714bd7c3 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 12:01:02 -0800 Subject: [PATCH 51/86] run jb_run from utils --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b22a26799..e65fbab8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ script: fi - ./setup.sh legacy; - prove -Isrc/perl5 -r -j3 tests/perl_tests; -- ./jb_run.js -p 9000 & +- utils/jb_run.js -p 9000 & - MOZ_HEADLESS=1 SELENIUM_BROWSER=firefox JBROWSE_URL=http://localhost:9000/index.html tests/selenium_tests/travis_wrapper.sh; - cd $BUILD_DIR after_failure: From c8bb669a4c84caea441be701366469a6cecc9c1f Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 12:35:18 -0800 Subject: [PATCH 52/86] npm tools have to have a valid version in the package.json. sigh. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a9d3483c5..1fb69022e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@gmod/jbrowse", "main": "browser/main.js", - "version": "1.x.x-dev", + "version": "1.12.3-SNAPSHOT", "description": "JBrowse - client-side genome browser", "repository": "https://github.com/GMOD/jbrowse.git", "scripts": { From 9959aa131315b6b63eaf4c41cd51b525e961ac14 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 12:48:30 -0800 Subject: [PATCH 53/86] don't set package versions in the build process anymore, we will have to do that manually --- .travis.yml | 2 -- ...ckage_jsons.pl => set_package_versions.pl} | 19 +++++++++---------- package.json | 2 +- src/JBrowse/package.json | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) rename build/{insert_tag_version_into_package_jsons.pl => set_package_versions.pl} (59%) diff --git a/.travis.yml b/.travis.yml index e65fbab8e..30e2faeb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,6 @@ install: - pip install nose selenium script: - jshint src/JBrowse/ -# if we have a release tag, insert its version into the ./package.json and the src/JBrowse/package.json -- if [[ "x$TRAVIS_TAG" != "x" ]]; then build/insert_tag_version_into_package_jsons.pl src/JBrowse/package.json package.json; fi - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - BUILD_DIR=$PWD # if we are building for inclusion into the `dev` branch, run the minification and test against that diff --git a/build/insert_tag_version_into_package_jsons.pl b/build/set_package_versions.pl similarity index 59% rename from build/insert_tag_version_into_package_jsons.pl rename to build/set_package_versions.pl index 21954c762..f12677f84 100755 --- a/build/insert_tag_version_into_package_jsons.pl +++ b/build/set_package_versions.pl @@ -9,23 +9,22 @@ use JSON 2; - -my $release = $ENV{TRAVIS_TAG}; -$release =~ s/\-release$// - or die "no TRAVIS_TAG env var defined or it's malformed. expecting something like '1.12.4-release'."; - -print "detected release tag $ENV{TRAVIS_TAG} for version $release\n"; +my $release = shift; +$release =~ s/\-release$//; +print "setting package versions to $release\n"; my $json = JSON->new->pretty->canonical; for my $filename (@ARGV) { print "inserting version $release into $filename\n"; - my $j = do { + my $text = do { local $/; open my $f, '<', $filename or die "$! reading $filename"; - $json->decode( <$f> ); + <$f> }; - $j->{version} = $release; + + $text =~ s/"version"\s*:\s*"[^"]+"/"version": "$release"/ + or die "failed to insert version info $filename"; open my $f, '>', $filename or die "$! writing $filename"; - $f->print( $json->encode($j) ); + $f->print( $text ); } diff --git a/package.json b/package.json index 1fb69022e..07d148640 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@gmod/jbrowse", "main": "browser/main.js", - "version": "1.12.3-SNAPSHOT", + "version": "1.12.4-pre", "description": "JBrowse - client-side genome browser", "repository": "https://github.com/GMOD/jbrowse.git", "scripts": { diff --git a/src/JBrowse/package.json b/src/JBrowse/package.json index 188c2da61..5ee4c5906 100644 --- a/src/JBrowse/package.json +++ b/src/JBrowse/package.json @@ -1,6 +1,6 @@ { "name": "JBrowse", - "version": "1.x.x", + "version": "1.12.4-pre", "copyright":"© 2007-2017 The Evolutionary Software Foundation", "main": "main", "dependencies": { From 8141903e167585e92908f0e903883613ab1a68ad Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 15:32:20 -0800 Subject: [PATCH 54/86] test npm deployment --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 30e2faeb1..5f3bdc736 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,4 +75,5 @@ deploy: on: repo: GMOD/jbrowse perl: 5.26 - tags: true + #tags: true + branch: continuous_deployment From d71612a5fc04dff60cf479cf89df2220d32cfdf4 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 15:52:27 -0800 Subject: [PATCH 55/86] add --stop option to selenium travis wrapper test run to make it fail faster --- tests/selenium_tests/travis_wrapper.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/selenium_tests/travis_wrapper.sh b/tests/selenium_tests/travis_wrapper.sh index 0d9b57437..a317e14e8 100755 --- a/tests/selenium_tests/travis_wrapper.sh +++ b/tests/selenium_tests/travis_wrapper.sh @@ -6,14 +6,14 @@ set +e -nosetests . +nosetests --stop . FIRST_RUN_STATUS=$? if [[ $FIRST_RUN_STATUS -ne 0 ]]; then echo echo ============= FIRST SELENIUM RUN FAILED, RETRYING TO MAKE SURE =============== echo - nosetests . + nosetests --stop . SECOND_RUN_STATUS=$? if [[ $SECOND_RUN_STATUS -ne 0 ]]; then echo ============= SELENIUM TEST FAILED ON SECOND RUN ============== From 6b9791efeae3b10f7505650fcceff900ad606f45 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 16:36:57 -0800 Subject: [PATCH 56/86] actually, we do need to update the package versions --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5f3bdc736..960f63c85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ install: - pip install nose selenium script: - jshint src/JBrowse/ +- if [[ "x$TRAVIS_TAG" != "x" ]]; then build/set_package_versions.pl $TRAVIS_TAG src/JBrowse/package.json package.json; fi - RELEASE_VERSION=`node -e 'require("fs").readFile("src/JBrowse/package.json", (e,d)=>console.log(JSON.parse(d).version))'` - BUILD_DIR=$PWD # if we are building for inclusion into the `dev` branch, run the minification and test against that From a7c12cd4ae5c4843e4d0eeddfa2a2d8858f4fa07 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 16:37:29 -0800 Subject: [PATCH 57/86] remove npm deployment test config --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 960f63c85..ddea5cdc5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -76,5 +76,4 @@ deploy: on: repo: GMOD/jbrowse perl: 5.26 - #tags: true - branch: continuous_deployment + tags: true From b61324d7b97c73cecf69534344e737765d1f9eb0 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 16:59:11 -0800 Subject: [PATCH 58/86] add release zipfiles to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 739adb1c3..2a0daa1a8 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ themes/*/css .vscode/ *driver.log JBrowse-*/ +JBrowse-*.zip From 855b356ab9f75e062ec4f354ee9e9420f61ccb2b Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 17:00:09 -0800 Subject: [PATCH 59/86] skip cleanup for npm deploy, because we write the tag version in the package.json --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ddea5cdc5..53b87bdc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,6 +71,7 @@ deploy: # upload regular non-minified version to npm - provider: npm email: rbuels@gmail.com + skip_cleanup: true api_key: secure: mgvlVdeMAR35C69+NERuYK4YGwbBAQsnSXS7IJhn3CRNgbtWh2zqaVV8NbHWitD9RJmocTbkIe94MfD8HfI3zBAgIVewckQ0QWMyjAJuWJR2Zw91R309aIQpbsix4kNCP9RDDrtfzovptBJ6JS8UwEk5CsQ7Wfohctek59+UnyU= on: From 25bf49d5bd47c36081a86132bcc8a50c1aac8a72 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Fri, 9 Feb 2018 17:01:30 -0800 Subject: [PATCH 60/86] clarify comment in build [skip ci] --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 53b87bdc3..5e6346277 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,7 +57,7 @@ after_failure: - find JBrowse-*/extlib/lib/perl5 - cat JBrowse-*/src/build-report.txt deploy: -# upload minified builds to GitHub releases +# upload both minified and non-minified builds to GitHub releases - provider: releases api_key: secure: BuOD7rqrcGKT3g0hVY5AGpJI/Kkko4DhSIYSUQ28sS2AOdoNyTD0t5doL/Kiq4BC41q198tbFFt1dnXGdo8YKpBSXO/uGUuuiGtMFHM++I84oLq20p49iyrenNZ4m/jy/Q4YtizIYLs83DVzVdQzhJ5hrTx6f+d1gc9EgaMeBF4= From fd8083062e41225ffd77e657b38aa981999ad6b4 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 11:39:49 -0800 Subject: [PATCH 61/86] squash error in touchscreensupport when the Olde Dragging Tracke Selector is not in use. fixes #893 --- src/JBrowse/TouchScreenSupport.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/JBrowse/TouchScreenSupport.js b/src/JBrowse/TouchScreenSupport.js index 4bc2a6141..b240136c7 100644 --- a/src/JBrowse/TouchScreenSupport.js +++ b/src/JBrowse/TouchScreenSupport.js @@ -30,6 +30,9 @@ Touch = { var leftPane = document.getElementById("tracksAvail"), rightPane = document.getElementById("container"); + if (! leftPane) + return rightPane; + if (first.pageX < (leftPane.offsetLeft + leftPane.offsetWidth)) { return leftPane; } From 8bec02807b6539c43c6ddcd6168d04f63e0580ba Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 11:43:20 -0800 Subject: [PATCH 62/86] update release notes [skip ci] --- release-notes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release-notes.txt b/release-notes.txt index 3c8d2b36a..bb6b8eef3 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -42,6 +42,9 @@ running indefinitely and taking all available disk space. (pull #945, issue #946, @deepakunni3 and @rbuels) + * Fixed a "cannot read property 'offsetLeft'" error when using touch screens without + the old simple track selector active. (issue #893, @rbuels) + # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles ## Minor improvements From ce48fd063801455f6e655f8086f79503d91baf1c Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 11:52:23 -0800 Subject: [PATCH 63/86] convert indentation of add-*-track.pl scripts from tabs to spaces --- bin/add-bam-track.pl | 180 +++++++++++++-------------- bin/add-bw-track.pl | 282 +++++++++++++++++++++---------------------- 2 files changed, 231 insertions(+), 231 deletions(-) diff --git a/bin/add-bam-track.pl b/bin/add-bam-track.pl index 33537202a..f15045def 100755 --- a/bin/add-bam-track.pl +++ b/bin/add-bam-track.pl @@ -34,107 +34,107 @@ exit; sub parse_options { - my $help; - GetOptions("in|i=s" => \$in_file, - "out|o=s" => \$out_file, - "label|l=s" => \$label, - "bam_url|u=s" => \$bam_url, - "key|k=s" => \$key, - "classname|c=s" => \$classname, - "bigwigCoverage|b=s" => \$bigwigCoverage, - "coverage|C" => \$coverage, - "min_score|s=i" => \$min_score, - "max_score|S=i" => \$max_score, - "help|h" => \$help); + my $help; + GetOptions("in|i=s" => \$in_file, + "out|o=s" => \$out_file, + "label|l=s" => \$label, + "bam_url|u=s" => \$bam_url, + "key|k=s" => \$key, + "classname|c=s" => \$classname, + "bigwigCoverage|b=s" => \$bigwigCoverage, + "coverage|C" => \$coverage, + "min_score|s=i" => \$min_score, + "max_score|S=i" => \$max_score, + "help|h" => \$help); pod2usage( -verbose => 2 ) if $help; - pod2usage("Missing label option") if !$label; - pod2usage("Missing bam_url option") if !$bam_url; - pod2usage("Missing min_score option") if $coverage && !defined $min_score; - pod2usage("Missing max_score option") if $coverage && !defined $max_score; - $key ||= $label; + pod2usage("Missing label option") if !$label; + pod2usage("Missing bam_url option") if !$bam_url; + pod2usage("Missing min_score option") if $coverage && !defined $min_score; + pod2usage("Missing max_score option") if $coverage && !defined $max_score; + $key ||= $label; $in_file ||= 'data/trackList.json'; $out_file ||= $in_file; } sub add_bam_track { - my $json = new JSON; - local $/; - my $in; - $in = new IO::File($in_file) or - die "Error reading input $in_file: $!"; - my $track_list_contents = <$in>; - $in->close(); - my $track_list = $json->decode($track_list_contents); - my $bam_entry; - my $index; - my $tracks = $track_list->{tracks}; - for ($index = 0; $index < scalar(@{$tracks}); ++$index) { - my $track = $tracks->[$index]; - if ($track->{label} eq $label) { - $bam_entry = $track; - last; - } - } - if (!$bam_entry) { - $bam_entry = !$coverage ? generate_new_bam_alignment_entry() : - generate_new_bam_coverage_entry(); - push @{$track_list->{tracks}}, $bam_entry; - } - else { - if ($coverage) { - if ($bam_entry->{type} eq $ALIGNMENT_TYPE) { - $bam_entry = generate_new_bam_coverage_entry(); - $tracks->[$index] = $bam_entry; - } - } - else { - if ($bam_entry->{type} eq $COVERAGE_TYPE) { - $bam_entry = generate_new_bam_alignment_entry(); - $tracks->[$index] = $bam_entry; - } - } - } - $bam_entry->{label} = $label; - $bam_entry->{urlTemplate} = $bam_url; - $bam_entry->{key} = $key; - if (!$coverage) { + my $json = new JSON; + local $/; + my $in; + $in = new IO::File($in_file) or + die "Error reading input $in_file: $!"; + my $track_list_contents = <$in>; + $in->close(); + my $track_list = $json->decode($track_list_contents); + my $bam_entry; + my $index; + my $tracks = $track_list->{tracks}; + for ($index = 0; $index < scalar(@{$tracks}); ++$index) { + my $track = $tracks->[$index]; + if ($track->{label} eq $label) { + $bam_entry = $track; + last; + } + } + if (!$bam_entry) { + $bam_entry = !$coverage ? generate_new_bam_alignment_entry() : + generate_new_bam_coverage_entry(); + push @{$track_list->{tracks}}, $bam_entry; + } + else { + if ($coverage) { + if ($bam_entry->{type} eq $ALIGNMENT_TYPE) { + $bam_entry = generate_new_bam_coverage_entry(); + $tracks->[$index] = $bam_entry; + } + } + else { + if ($bam_entry->{type} eq $COVERAGE_TYPE) { + $bam_entry = generate_new_bam_alignment_entry(); + $tracks->[$index] = $bam_entry; + } + } + } + $bam_entry->{label} = $label; + $bam_entry->{urlTemplate} = $bam_url; + $bam_entry->{key} = $key; + if (!$coverage) { if (defined $classname) { if (! $bam_entry->{style}) { $bam_entry->{style} = {}; } $bam_entry->{style}->{className} = $classname; } - if ($bigwigCoverage) { + if ($bigwigCoverage) { $bam_entry->{histograms} = { - storeClass => $BIGWIG_STORE_CLASS, - urlTemplate => $bigwigCoverage - }; + storeClass => $BIGWIG_STORE_CLASS, + urlTemplate => $bigwigCoverage + }; } - } - else { - $bam_entry->{min_score} = $min_score; - $bam_entry->{max_score} = $max_score; - } - my $out; - $out = new IO::File($out_file, "w") or - die "Error writing output $out_file: $!"; - print $out $json->pretty->encode($track_list); - $out->close(); + } + else { + $bam_entry->{min_score} = $min_score; + $bam_entry->{max_score} = $max_score; + } + my $out; + $out = new IO::File($out_file, "w") or + die "Error writing output $out_file: $!"; + print $out $json->pretty->encode($track_list); + $out->close(); } sub generate_new_bam_alignment_entry { - return { - storeClass => $STORE_CLASS, - type => $ALIGNMENT_TYPE, - }; + return { + storeClass => $STORE_CLASS, + type => $ALIGNMENT_TYPE, + }; } sub generate_new_bam_coverage_entry { - return { - storeClass => $STORE_CLASS, - type => $COVERAGE_TYPE - }; + return { + storeClass => $STORE_CLASS, + type => $COVERAGE_TYPE + }; } __END__ @@ -149,17 +149,17 @@ =head1 NAME =head1 USAGE add_bam_track.pl - [ --in ] \ + [ --in ] \ [ --out \ - --label \ - --bam_url \ - [ --key ] \ - [ --classname ] \ - [ --bigwigCoverage ] \ - [ --coverage ] \ - [ --min_score ] \ - [ --max_score ] \ - [ --help ] + --label \ + --bam_url \ + [ --key ] \ + [ --classname ] \ + [ --bigwigCoverage ] \ + [ --coverage ] \ + [ --min_score ] \ + [ --max_score ] \ + [ --help ] =head1 ARGUMENTS diff --git a/bin/add-bw-track.pl b/bin/add-bw-track.pl index 2d408dca3..665571921 100755 --- a/bin/add-bw-track.pl +++ b/bin/add-bw-track.pl @@ -37,51 +37,51 @@ add_bw_track(); sub parse_options { - my $help; - GetOptions("in|i=s" => \$in_file, - "out|o=s" => \$out_file, - "label|l=s" => \$label, - "bw_url|u=s" => \$bw_url, - "key|k=s" => \$key, - "category|a=s" => \$category, - "plot|P" => \$plot, - "bicolor_pivot|b=s" => \$bicolor_pivot, - "pos_color|c=s" => \$pos_color, - "neg_color|C=s" => \$neg_color, - "min_score|s=i" => \$min_score, - "max_score|S=i" => \$max_score, - "clip_marker_color|M=s" => \$clip_marker_color, - "bg_color|B=s" => \$bg_color, - "height|H=s" => \$height, - "help|h" => \$help); - pod2usage( -verbose => 2 ) if $help; - pod2usage( "Missing label option" ) if !$label; - pod2usage( "Missing bw_url option" ) if !$bw_url; - $key ||= $label; + my $help; + GetOptions("in|i=s" => \$in_file, + "out|o=s" => \$out_file, + "label|l=s" => \$label, + "bw_url|u=s" => \$bw_url, + "key|k=s" => \$key, + "category|a=s" => \$category, + "plot|P" => \$plot, + "bicolor_pivot|b=s" => \$bicolor_pivot, + "pos_color|c=s" => \$pos_color, + "neg_color|C=s" => \$neg_color, + "min_score|s=i" => \$min_score, + "max_score|S=i" => \$max_score, + "clip_marker_color|M=s" => \$clip_marker_color, + "bg_color|B=s" => \$bg_color, + "height|H=s" => \$height, + "help|h" => \$help); + pod2usage( -verbose => 2 ) if $help; + pod2usage( "Missing label option" ) if !$label; + pod2usage( "Missing bw_url option" ) if !$bw_url; + $key ||= $label; $in_file ||= 'data/trackList.json'; $out_file ||= $in_file; } sub add_bw_track { - my $json = new JSON; - local $/; - my $in; - $in = new IO::File($in_file) or - die "Error reading input $in_file: $!"; - my $track_list_contents = <$in>; - $in->close(); - my $track_list = $json->decode($track_list_contents); - my $bw_entry; - - my $index; - my $tracks = $track_list->{tracks} || []; # create tracklist if not there - for ($index = 0; $index < scalar(@{$tracks}); ++$index) { - my $track = $tracks->[$index]; - if ($track->{label} eq $label) { - $bw_entry = $track; - last; - } - } + my $json = new JSON; + local $/; + my $in; + $in = new IO::File($in_file) or + die "Error reading input $in_file: $!"; + my $track_list_contents = <$in>; + $in->close(); + my $track_list = $json->decode($track_list_contents); + my $bw_entry; + + my $index; + my $tracks = $track_list->{tracks} || []; # create tracklist if not there + for ($index = 0; $index < scalar(@{$tracks}); ++$index) { + my $track = $tracks->[$index]; + if ($track->{label} eq $label) { + $bw_entry = $track; + last; + } + } # foreach my $track (@{$track_list->{tracks}}) { # if ($track->{label} eq $label) { @@ -89,101 +89,101 @@ sub add_bw_track { # last; # } # } - if (!$bw_entry) { - # $bw_entry = generate_new_bw_heatmap_entry(); - $bw_entry = !$plot ? generate_new_bw_heatmap_entry() : - generate_new_bw_plot_entry(); - - push @{$track_list->{tracks}}, $bw_entry; - } - else { - if ($plot) { - if ($bw_entry->{type} eq $HEATMAP_TYPE) { - $bw_entry = generate_new_bw_plot_entry(); - $tracks->[$index] = $bw_entry; - } - } - else { - if ($bw_entry->{type} eq $PLOT_TYPE) { - $bw_entry = generate_new_bw_heatmap_entry(); - $tracks->[$index] = $bw_entry; - } - } - } - - $bw_entry->{label} = $label; + if (!$bw_entry) { + # $bw_entry = generate_new_bw_heatmap_entry(); + $bw_entry = !$plot ? generate_new_bw_heatmap_entry() : + generate_new_bw_plot_entry(); + + push @{$track_list->{tracks}}, $bw_entry; + } + else { + if ($plot) { + if ($bw_entry->{type} eq $HEATMAP_TYPE) { + $bw_entry = generate_new_bw_plot_entry(); + $tracks->[$index] = $bw_entry; + } + } + else { + if ($bw_entry->{type} eq $PLOT_TYPE) { + $bw_entry = generate_new_bw_heatmap_entry(); + $tracks->[$index] = $bw_entry; + } + } + } + + $bw_entry->{label} = $label; $bw_entry->{autoscale} = "local"; - $bw_entry->{urlTemplate} = $bw_url; - $bw_entry->{key} = $key; - $bw_entry->{bicolor_pivot} = $bicolor_pivot; - if (defined $category) { - $bw_entry->{category} = $category; - } - else { - delete $bw_entry->{category}; - } - if (defined $min_score) { - $bw_entry->{min_score} = $min_score; - } - else { - delete $bw_entry->{min_score}; - } - if (defined $max_score) { - $bw_entry->{max_score} = $max_score; - } - else { - delete $bw_entry->{max_score}; - } - if ($pos_color) { - $bw_entry->{style}->{pos_color} = $pos_color; - } - else { - delete $bw_entry->{style}->{pos_color}; - } - if ($neg_color) { - $bw_entry->{style}->{neg_color} = $neg_color; - } - else { - delete $bw_entry->{style}->{neg_color}; - } - if ($clip_marker_color) { - $bw_entry->{style}->{clip_marker_color} = $clip_marker_color; - } - else { - delete $bw_entry->{style}->{clip_marker_color}; - } - if ($bg_color) { - $bw_entry->{style}->{bg_color} = $bg_color; - } - else { - delete $bw_entry->{style}->{bg_color}; - } - if ($height) { - $bw_entry->{style}->{height} = $height; - } - else { - delete $bw_entry->{style}->{height}; - } - delete $bw_entry->{style} if !scalar(keys %{$bw_entry->{style}}); - my $out; - $out = new IO::File($out_file, "w") or - die "Error writing output $out_file: $!"; - print $out $json->pretty->encode($track_list); - $out->close(); + $bw_entry->{urlTemplate} = $bw_url; + $bw_entry->{key} = $key; + $bw_entry->{bicolor_pivot} = $bicolor_pivot; + if (defined $category) { + $bw_entry->{category} = $category; + } + else { + delete $bw_entry->{category}; + } + if (defined $min_score) { + $bw_entry->{min_score} = $min_score; + } + else { + delete $bw_entry->{min_score}; + } + if (defined $max_score) { + $bw_entry->{max_score} = $max_score; + } + else { + delete $bw_entry->{max_score}; + } + if ($pos_color) { + $bw_entry->{style}->{pos_color} = $pos_color; + } + else { + delete $bw_entry->{style}->{pos_color}; + } + if ($neg_color) { + $bw_entry->{style}->{neg_color} = $neg_color; + } + else { + delete $bw_entry->{style}->{neg_color}; + } + if ($clip_marker_color) { + $bw_entry->{style}->{clip_marker_color} = $clip_marker_color; + } + else { + delete $bw_entry->{style}->{clip_marker_color}; + } + if ($bg_color) { + $bw_entry->{style}->{bg_color} = $bg_color; + } + else { + delete $bw_entry->{style}->{bg_color}; + } + if ($height) { + $bw_entry->{style}->{height} = $height; + } + else { + delete $bw_entry->{style}->{height}; + } + delete $bw_entry->{style} if !scalar(keys %{$bw_entry->{style}}); + my $out; + $out = new IO::File($out_file, "w") or + die "Error writing output $out_file: $!"; + print $out $json->pretty->encode($track_list); + $out->close(); } sub generate_new_bw_heatmap_entry { - return { - storeClass => $STORE_CLASS, - type => $HEATMAP_TYPE - }; + return { + storeClass => $STORE_CLASS, + type => $HEATMAP_TYPE + }; } sub generate_new_bw_plot_entry { - return { - storeClass => $STORE_CLASS, - type => $PLOT_TYPE - }; + return { + storeClass => $STORE_CLASS, + type => $PLOT_TYPE + }; } __END__ @@ -198,22 +198,22 @@ =head1 NAME =head1 USAGE add-bw-track.pl - [ --in ] \ - [ --out ] \ - --label \ - --bw_url \ - [ --key ] \ - [ --category 'Category in JBrowse' ] \ - [ --plot ] \ - [ --bicolor_pivot ] \ - [ --pos_color ] \ - [ --neg_color ] \ - [ --min_score ] \ - [ --max_score ] \ + [ --in ] \ + [ --out ] \ + --label \ + --bw_url \ + [ --key ] \ + [ --category 'Category in JBrowse' ] \ + [ --plot ] \ + [ --bicolor_pivot ] \ + [ --pos_color ] \ + [ --neg_color ] \ + [ --min_score ] \ + [ --max_score ] \ [ --clip_marker_color ] \ [ --bg_color ] \ [ --height ] \ - [ -h|--help ] + [ -h|--help ] =head1 ARGUMENTS From 923aa9b91e20cdf3f79970a4dc78ab4b70a6ea7b Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 12:18:25 -0800 Subject: [PATCH 64/86] add `--config` options to add-*-track.pl scripts, fixes #620 --- bin/add-bam-track.pl | 28 ++++++++++++-- bin/add-bw-track.pl | 7 +++- tests/perl_tests/add-bam-track.pl.t | 59 +++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 tests/perl_tests/add-bam-track.pl.t diff --git a/bin/add-bam-track.pl b/bin/add-bam-track.pl index f15045def..8a02429b7 100755 --- a/bin/add-bam-track.pl +++ b/bin/add-bam-track.pl @@ -28,6 +28,8 @@ my $classname = undef; my $min_score = undef; my $max_score = undef; +my $additional_config; +my $category; parse_options(); add_bam_track(); @@ -45,6 +47,8 @@ sub parse_options { "coverage|C" => \$coverage, "min_score|s=i" => \$min_score, "max_score|S=i" => \$max_score, + "category=s" => \$category, + "config=s" => \$additional_config, "help|h" => \$help); pod2usage( -verbose => 2 ) if $help; pod2usage("Missing label option") if !$label; @@ -52,8 +56,8 @@ sub parse_options { pod2usage("Missing min_score option") if $coverage && !defined $min_score; pod2usage("Missing max_score option") if $coverage && !defined $max_score; $key ||= $label; - $in_file ||= 'data/trackList.json'; - $out_file ||= $in_file; + $in_file ||= 'data/trackList.json'; + $out_file ||= $in_file; } @@ -68,7 +72,7 @@ sub add_bam_track { my $track_list = $json->decode($track_list_contents); my $bam_entry; my $index; - my $tracks = $track_list->{tracks}; + my $tracks = $track_list->{tracks} || []; for ($index = 0; $index < scalar(@{$tracks}); ++$index) { my $track = $tracks->[$index]; if ($track->{label} eq $label) { @@ -116,6 +120,19 @@ sub add_bam_track { $bam_entry->{min_score} = $min_score; $bam_entry->{max_score} = $max_score; } + + if( $category ) { + $bam_entry->{category} = $category; + } + + if ($additional_config) { + my $conf = $json->decode( $additional_config ); + unless ( $conf && ref $conf eq 'HASH') { + die "invalid --config option, --config must be valid JSON"; + } + %$bam_entry = (%$bam_entry, %$conf) + } + my $out; $out = new IO::File($out_file, "w") or die "Error writing output $out_file: $!"; @@ -205,6 +222,11 @@ =head1 ARGUMENTS optional maximum score to use for generating coverage plot (only applicable with --coverage option) +=item --config '{ "my_key": "my_value", ... }' + +optional additional data to include in the track configuration. Any values provided here will override +the values generated by the rest of the script. + =back =cut diff --git a/bin/add-bw-track.pl b/bin/add-bw-track.pl index 665571921..84d3ebb8e 100755 --- a/bin/add-bw-track.pl +++ b/bin/add-bw-track.pl @@ -43,7 +43,7 @@ sub parse_options { "label|l=s" => \$label, "bw_url|u=s" => \$bw_url, "key|k=s" => \$key, - "category|a=s" => \$category, + "category=s" => \$category, "plot|P" => \$plot, "bicolor_pivot|b=s" => \$bicolor_pivot, "pos_color|c=s" => \$pos_color, @@ -292,6 +292,11 @@ =head1 ARGUMENTS optional height +=item --config '{ "my_key": "my_value", ... }' + +optional additional data to include in the track configuration. Any values provided here will override +the values generated by the rest of the script. + =back =cut diff --git a/tests/perl_tests/add-bam-track.pl.t b/tests/perl_tests/add-bam-track.pl.t new file mode 100644 index 000000000..fc17d65af --- /dev/null +++ b/tests/perl_tests/add-bam-track.pl.t @@ -0,0 +1,59 @@ +use strict; +use warnings; + +use JBlibs; + +use JSON 2; +use Test::More; + +use File::Temp; +use Capture::Tiny 'capture'; + + +my $j = JSON->new->pretty->relaxed; + +my $t = File::Temp->new; +$t->print( <close; + +my $t2 = File::Temp->new; +$t2->close; + +my $data = $j->decode( do { open my $f, '<', "$t" or die; local $/; scalar <$f> } ); +is_deeply( $data, {}, 'got the right data before' ); + + +my ( $stdout, $stderr ) = capture { + system $^X, 'bin/add-bam-track.pl', ( + '--in' => $t->filename, + '--out' => $t2->filename, + '--label' => 'foo', + '--key' => 'My BAM Track', + '--category' => 'My Test Category', + '--bam_url' => '/foo/bar.bammy', + '--config' => '{ "zee": "zonker", "key": "My BAM Track Overridden" }' + ); +}; +ok( ! $?, 'script succeeded' ); +is( $stderr, '', 'nothing on stderr' ); + +$data = $j->decode( do { open my $f, '<', "$t2" or die; local $/; scalar <$f> } ); +is_deeply( $data, { + 'tracks' => [ + { + 'category' => 'My Test Category', + 'key' => 'My BAM Track Overridden', + 'label' => 'foo', + 'storeClass' => 'JBrowse/Store/SeqFeature/BAM', + 'type' => 'JBrowse/View/Track/Alignments2', + 'urlTemplate' => '/foo/bar.bammy', + 'zee' => 'zonker' + } + ] +} +, 'got the right tracklist data after' ) + or diag explain $data; + +done_testing; From 6ba9cc526f7c6fd440cdffb3d132e24f371c4afc Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 12:19:48 -0800 Subject: [PATCH 65/86] update release notes [skip ci] --- release-notes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release-notes.txt b/release-notes.txt index 3c8d2b36a..b909ef62d 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -42,6 +42,9 @@ running indefinitely and taking all available disk space. (pull #945, issue #946, @deepakunni3 and @rbuels) + * Add `--config` command-line option to `add-bw-track.pl` and `add-bam-track.pl` + scripts. Thanks to Chris Childers for suggesting this! (issue #620, @rbuels) + # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles ## Minor improvements From 1e6f250b9bb28d7d53d583d55e6b5ca2f6bd67f2 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 12:41:09 -0800 Subject: [PATCH 66/86] fix JBrowse/Util parsing of negative coordinates, fixes #769 --- release-notes.txt | 4 ++++ src/JBrowse/Util.js | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/release-notes.txt b/release-notes.txt index 3c8d2b36a..1184b4fa2 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -42,6 +42,10 @@ running indefinitely and taking all available disk space. (pull #945, issue #946, @deepakunni3 and @rbuels) + * Fixed issue in which JBrowse crashed when negative numbers were supplied for highlight + coordinates in the URL. Thanks to @h2akim for reporting, and @cmdcolin for debugging help. + (issue #769, @rbuels) + # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles ## Minor improvements diff --git a/src/JBrowse/Util.js b/src/JBrowse/Util.js index fd1841be7..069d08841 100644 --- a/src/JBrowse/Util.js +++ b/src/JBrowse/Util.js @@ -282,8 +282,12 @@ Util = { // parses a number from a locstring that's a coordinate, and // converts it from 1-based to interbase coordinates var parseCoord = function( coord ) { - coord = (coord+'').replace(/\D/g,''); + coord = coord+''; + var negative = coord.charAt(0) === '-'; + coord = coord.replace(/\D/g,''); var num = parseInt( coord, 10 ); + if( negative ) + num = -num; return typeof num == 'number' && !isNaN(num) ? num : null; }; @@ -296,7 +300,7 @@ Util = { locstring = tokens[1]; } - tokens = locstring.match( /^\s*([\d,]+)\s*\.\.+\s*([\d,]+)/ ); + tokens = locstring.match( /^\s*(-?[\d,]+)\s*\.\.+\s*(-?[\d,]+)/ ); if( tokens ) { // range of two numbers? location.start = parseCoord( tokens[1] )-1; location.end = parseCoord( tokens[2] ); @@ -309,7 +313,7 @@ Util = { } } else { // one number? - tokens = locstring.match( /^\s*([\d,]+)\b/ ); + tokens = locstring.match( /^\s*(-?[\d,]+)\b/ ); if( tokens ) { location.end = location.start = parseCoord( tokens[1] )-1; } From b41ac86b0c9a73dd0f53549a886cc3013a2c67b3 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 14:16:57 -0800 Subject: [PATCH 67/86] Revert "removed redudancy in callLocation" This reverts commit fe2883b60fcd5711d78cc988840b0db4153696d0. --- src/JBrowse/Browser.js | 65 +++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index 8c5be73e7..ca74e5648 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -2368,27 +2368,40 @@ showRegion: function( location ) { navigateTo: function(loc) { var thisB = this; this.afterMilestone( 'initView', function() { - thisB.afterMilestone( 'loadNames', function() { - // lastly, try to search our feature names for it - thisB.searchNames( loc ) - .then( function( found ) { - if( found ) - return; - - // if it's a foo:123..456 location, go there - if(!thisB.callLocation(loc)){return;} - - new InfoDialog( - { - title: 'Not found', - content: 'Not found: '+loc+'', - className: 'notfound-dialog' - }).show(); - }); + // lastly, try to search our feature names for it + thisB.searchNames( loc ) + .then( function( found ) { + if( found ) + return; + + // if it's a foo:123..456 location, go there + var location = typeof loc == 'string' ? Util.parseLocString( loc ) : loc; + // only call navigateToLocation() directly if location has start and end, otherwise try and fill in start/end from 'location' cookie + if( location && ("start" in location) && ("end" in location)) { + thisB.navigateToLocation( location ); + return; + } + // otherwise, if it's just a word (or a location with only a ref property), try to figure out what it is + else { + if( typeof loc != 'string') + loc = loc.ref; + + // is it just the name of one of our ref seqs? + var ref = thisB.findReferenceSequence( loc ); + if( ref ) { + thisB.navigateToLocation( { ref: ref.name } ); + return; + } + } - // called by default - thisB.callLocation(loc); - }); + new InfoDialog( + { + title: 'Not found', + content: 'Not found: '+loc+'', + className: 'notfound-dialog' + }).show(); + }, + thisB.callLocation(loc)); }); }, @@ -2398,17 +2411,17 @@ callLocation: function(loc){ // only call navigateToLocation() directly if location has start and end, otherwise try and fill in start/end from 'location' cookie if( location && ("start" in location) && ("end" in location)) { thisB.navigateToLocation( location ); - return false; - } - // otherwise, if it's just a word (or a location with only a ref property), try to figure out what it is - else { + return; + } + // otherwise, if it's just a word (or a location with only a ref property), try to figure out what it is + else { if( typeof loc != 'string') loc = loc.ref; // is it just the name of one of our ref seqs? var ref = thisB.findReferenceSequence( loc ); if( ref ) { - thisB.navigateToLocation( { ref: ref.name } ); - return false; + thisB.navigateToLocation( { ref: ref.name } ); + return; } } }, From 27ec453eaa1ec1d580d4c2d4cf2fb11106499c2d Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 14:17:20 -0800 Subject: [PATCH 68/86] Revert "fixed navigateTo when generate-names not run" This reverts commit b58b4f31dd7ba3e331ad2ba30023a8b2b3f8664e. --- src/JBrowse/Browser.js | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index ca74e5648..7e607e748 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -2400,32 +2400,10 @@ navigateTo: function(loc) { content: 'Not found: '+loc+'', className: 'notfound-dialog' }).show(); - }, - thisB.callLocation(loc)); + }); }); }, -callLocation: function(loc){ - var thisB=this; - var location = typeof loc == 'string' ? Util.parseLocString( loc ) : loc; - // only call navigateToLocation() directly if location has start and end, otherwise try and fill in start/end from 'location' cookie - if( location && ("start" in location) && ("end" in location)) { - thisB.navigateToLocation( location ); - return; - } - // otherwise, if it's just a word (or a location with only a ref property), try to figure out what it is - else { - if( typeof loc != 'string') - loc = loc.ref; - // is it just the name of one of our ref seqs? - var ref = thisB.findReferenceSequence( loc ); - if( ref ) { - thisB.navigateToLocation( { ref: ref.name } ); - return; - } - } -}, - findReferenceSequence: function( name ) { for( var n in this.allRefs ) { if( ! this.compareReferenceNames( n, name ) ) From 5bab8a17374abefbc1a7d4e2afc111fb9f63087a Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 16:08:07 -0800 Subject: [PATCH 69/86] rename `trackMod` -> `desiredTracks` in this stopgap race condition-squashing hack --- src/JBrowse/GenomeView.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/JBrowse/GenomeView.js b/src/JBrowse/GenomeView.js index 088d696b6..374e1b8e2 100755 --- a/src/JBrowse/GenomeView.js +++ b/src/JBrowse/GenomeView.js @@ -65,7 +65,7 @@ constructor: function( args ) { var stripeWidth = args.stripeWidth; var refseq = args.refSeq; var zoomLevel = args.zoomLevel; - this.trackMod = {}; + this.desiredTracks = {}; // keep a reference to the main browser object this.browser = browser; this.setFeatureFilterParentComponent( this.browser ); @@ -1114,7 +1114,7 @@ setLocation: function(refseq, startbp, endbp) { endbp = refseq.end; function removeTrack( track ) { - delete thisB.trackMod[track.name]; + delete thisB.desiredTracks[track.name]; if (track.div && track.div.parentNode) track.div.parentNode.removeChild(track.div); }; @@ -2082,10 +2082,10 @@ showVisibleBlocks: function(updateHeight, pos, startX, endX) { showTracks: function( trackConfigs ) { // filter out any track configs that are already displayed var needed = dojo.filter( trackConfigs, function(conf) { - return this._getTracks( [conf.label] ).length == 0 && !this.trackMod[conf.label]; + return this._getTracks( [conf.label] ).length == 0 && !this.desiredTracks[conf.label]; },this); if( ! needed.length ) return; - array.forEach(trackConfigs, function(ret) { this.trackMod[ret.label] = true; }, this); + array.forEach(trackConfigs, function(ret) { this.desiredTracks[ret.label] = true; }, this); // insert the track configs into the trackDndWidget ( the widget // will call create() on the confs to render them) @@ -2148,7 +2148,7 @@ hideTracks: function( /**Array[String]*/ trackConfigs ) { return this._getTracks( [conf.label] ).length != 0; },this); if( ! displayed.length ) return; - array.forEach(trackConfigs, function(ret) { delete this.trackMod[ret.label]; }, this); + array.forEach(trackConfigs, function(ret) { delete this.desiredTracks[ret.label]; }, this); // remove the track configs from the trackDndWidget ( the widget // will call create() on the confs to render them ) From c3ac64c69c2927262c50f76ea07268665594a174 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Mon, 12 Feb 2018 16:17:57 -0800 Subject: [PATCH 70/86] update release notes, fixes #567 [skip ci] --- release-notes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release-notes.txt b/release-notes.txt index c640f4af2..9209d3844 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -25,6 +25,10 @@ running indefinitely and taking all available disk space. (pull #945, issue #946, @deepakunni3 and @rbuels) + * Mitigate race condition that could sometimes cause duplicate tracks to be shown + when the browser is started with the `loc` query parameeter set to the name of + a feature. Thanks to Colin Diesh for the fix. (issue #567, @cmdcolin) + ... # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles From 3d94c3b485bbcc4f2520b2ebfe12bc10a6a48b96 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Mon, 12 Feb 2018 17:24:52 -0800 Subject: [PATCH 71/86] restore gradient code --- plugins/NeatCanvasFeatures/js/main.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/NeatCanvasFeatures/js/main.js b/plugins/NeatCanvasFeatures/js/main.js index cc4bee81f..74e5b652a 100644 --- a/plugins/NeatCanvasFeatures/js/main.js +++ b/plugins/NeatCanvasFeatures/js/main.js @@ -178,14 +178,14 @@ return declare( JBrowsePlugin, // Create gradient -// var grd = context.createLinearGradient(left, top, left, top+height); + var grd = context.createLinearGradient(left, top, left, top+height); -// // Add colors -// grd.addColorStop(0.000, bgcolor); -// grd.addColorStop(0.500,this.colorShift(bgcolor,2.5)); -// grd.addColorStop(0.999, bgcolor); + // Add colors + grd.addColorStop(0.000, bgcolor); + grd.addColorStop(0.500,this.colorShift(bgcolor,2.5)); + grd.addColorStop(0.999, bgcolor); -// // Fill with linear + // Fill with linear context.fillStyle = bgcolor; } From 8044e57eb0577a59ec755e3a931025d733c46d18 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Mon, 12 Feb 2018 17:42:52 -0800 Subject: [PATCH 72/86] fixup docs --- plugins/NeatCanvasFeatures/README.md | 43 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/plugins/NeatCanvasFeatures/README.md b/plugins/NeatCanvasFeatures/README.md index 2b9e8f5d6..324b766a3 100644 --- a/plugins/NeatCanvasFeatures/README.md +++ b/plugins/NeatCanvasFeatures/README.md @@ -1,24 +1,23 @@ -NeatCanvasFeatures is a JBrowse plugin. +# NeatCanvasFeatures - a JBrowse plugin. It applies intron hats and a gradient 'tubular' look to features and subfeatures of CanvasFeatures tracks. -What it does: +### What it does: - draws intron hats and inverted hats for reverse direction features. - it applies a gradient 'tubular' look to features and subfeatures, inheriting the feature colors and properties. - modifies UTR to be a outlined box, inheriting the original color. - generally functional in stand-alone JBrowse. -Install / Activate: +### Install / Activate: +For JBrowse 1.11.6+, copy the `NeatCanvasFeatures` directory to the `plugins` directory. +Add this to appropriate **trackList.json** under the plugins section (create one if it doesn't exist): -For JBrowse 1.11.6+, copy the NeatCanvasFeatures directory to the 'plugins' directory. -Add this to appropriate trackList.json under the plugins section (create one if it doesn't exist): + "plugins": [ + 'NeatCanvasFeatures' + ], - "plugins": [ - 'NeatCanvasFeatures' - ], - -For Apollo 2.x, copy the NeatCanvasFeatures directory to the web-apps/jbrowse/plugins directory. -Add this to web-apps/jbrowse/plugins/WebApollo/json/annot.json: +For Apollo 2.x, copy the NeatCanvasFeatures directory to the `web-apps/jbrowse/plugins` directory. +Add this to `web-apps/jbrowse/plugins/WebApollo/json/annot.json`: "plugins" : [ { @@ -29,22 +28,22 @@ Add this to web-apps/jbrowse/plugins/WebApollo/json/annot.json: "location" : "./plugins/NeatCanvasFeatures", "name" : "NeatCanvasFeatures" } - ], - + ], -Config Options: +### Config Options: Gradient Features are on for all HTML feature tracks by default. -They can be turned off globally in the config file by setting gradientFeatures = 0 in the plugin definition, for example: +They can be turned off globally in the config file by setting `gradientFeatures = 0` in the plugin definition, for example: - "plugins": [ - { - "name": "NeatHTMLFeatures", - "gradientFeatures": 0 - } - ], + "plugins": [ + { + "name": "NeatHTMLFeatures", + "gradientFeatures": 0 + } + ], + +When `gradientFeatures = 0` (globally off) in the plugins definition, gradient features can be enabled on per track basis with `gradientFeatures = 1` in the track configuration, for example: -When gradientFeatures = 0 (globally off) in the plugins definition, gradient features can be enabled on per track basis with gradientFeatures = 1 in the track configuration, for example: "tracks": [ { ... From aab85a1ec16d67eb03459df0f240b64ebe8f6895 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Mon, 12 Feb 2018 17:50:43 -0800 Subject: [PATCH 73/86] fixup docs --- plugins/NeatHTMLFeatures/README.md | 132 ++++++++++++++--------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/plugins/NeatHTMLFeatures/README.md b/plugins/NeatHTMLFeatures/README.md index 2e87d35fd..f2712814a 100644 --- a/plugins/NeatHTMLFeatures/README.md +++ b/plugins/NeatHTMLFeatures/README.md @@ -1,66 +1,66 @@ -#NeatHTMLFeatures - a JBrowse plugin. - -It applies intron hats and a gradient 'tubular' look to features and subfeatures of HTMLFeatures tracks. -This is refactored from HTMLFeaturesEx.js implementation and the insertion/modification to DOM elements are done out-of-band, -due to difference between HTMLFeatures and DragableHTMLFeatures feature DOMs. - -What it does: -- draws intron hats and inverted hats for reverse direction features. -- it applies a gradient 'tubular' look to features and subfeatures, inheriting the feature colors and properties. -- modifies UTR to be a outlined box, inheriting the original color. -- generally functional in stand-alone JBrowse. -- special considerations have been made for the unique way Web Apollo renders it's nested subfeatures. - - -##Install / Activate: - -For JBrowse 1.11.6+, copy the NeatHTMLFeatures directory to the 'plugins' directory. -Add this to appropriate trackList.json under the plugins section (create one if it doesn't exist): - - "plugins": [ - 'NeatHTMLFeatures' - ], - -For Apollo 2.x, copy the NeatHTMLFeatures directory to the web-apps/jbrowse/plugins directory. -Add this to web-apps/jbrowse/plugins/WebApollo/json/annot.json: - - "plugins" : [ - { - "location" : "./plugins/WebApollo", - "name" : "WebApollo" - }, - { - "location" : "./plugins/NeatHTMLFeatures", - "name" : "NeatHTMLFeatures" - } - ], - - -#Config Options: -Introns remain ON for all feature tracks. -Neat Features are ON by default, but can be disabled. -Linear Gradients are ON by default (and visible as part of neat features), but can be disabled on all tracks. - -Neat features can be turned off globally in the config file by setting neatFeatures = 0 in the plugin definition, for example: - - "plugins": [ - { - "name": "NeatHTMLFeatures", - "neatFeatures": 0 - } - ], - -When neatFeatures = 0 (globally off) in the plugins definition, gradient features can be enabled on per track basis with neatFeatures = 1 in the track configuration, for example: - - "tracks": [ - { - ... - "type" : "FeatureTrack", - "label" : "ReadingFrame", - "neatFeatures" : 1, - "linearGradient": 0, - ... - } - ] - -(note: the track-level neatFeatures option only applies when the plugin-level neatFeatures=0) +# NeatHTMLFeatures - a JBrowse plugin. + +It applies intron hats and a gradient 'tubular' look to features and subfeatures of HTMLFeatures tracks. +This is refactored from HTMLFeaturesEx.js implementation and the insertion/modification to DOM elements are done out-of-band, +due to difference between HTMLFeatures and DragableHTMLFeatures feature DOMs. + +### What it does: +- draws intron hats and inverted hats for reverse direction features. +- it applies a gradient 'tubular' look to features and subfeatures, inheriting the feature colors and properties. +- modifies UTR to be a outlined box, inheriting the original color. +- generally functional in stand-alone JBrowse. +- special considerations have been made for the unique way Web Apollo renders it's nested subfeatures. + + +### Install / Activate: + +For JBrowse 1.11.6+, copy the NeatHTMLFeatures directory to the 'plugins' directory. +Add this to appropriate trackList.json under the plugins section (create one if it doesn't exist): + + "plugins": [ + 'NeatHTMLFeatures' + ], + +For Apollo 2.x, copy the NeatHTMLFeatures directory to the `web-apps/jbrowse/plugins` directory. +Add this to `web-apps/jbrowse/plugins/WebApollo/json/annot.json`: + + "plugins" : [ + { + "location" : "./plugins/WebApollo", + "name" : "WebApollo" + }, + { + "location" : "./plugins/NeatHTMLFeatures", + "name" : "NeatHTMLFeatures" + } + ], + + +### Config Options: +Introns remain ON for all feature tracks. +Neat Features are ON by default, but can be disabled. +Linear Gradients are ON by default (and visible as part of neat features), but can be disabled on all tracks. + +NeatFeatures can be turned off globally in the config file by setting `neatFeatures = 0` in the plugin definition, for example: + + "plugins": [ + { + "name": "NeatHTMLFeatures", + "neatFeatures": 0 + } + ], + +When `neatFeatures = 0` (globally off) in the plugins definition, gradient features can be enabled on per track basis with `neatFeatures = 1` in the track configuration, for example: + + "tracks": [ + { + ... + "type" : "FeatureTrack", + "label" : "ReadingFrame", + "neatFeatures" : 1, + "linearGradient": 0, + ... + } + ] + +*note: the track-level `neatFeatures` option only applies when the plugin-level `neatFeatures=0`* From da9bd2614ee655c98ef1c248d3f348ee9eea7da8 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Mon, 12 Feb 2018 18:16:21 -0800 Subject: [PATCH 74/86] add sample image --- plugins/NeatHTMLFeatures/img/example.png | Bin 0 -> 26328 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/NeatHTMLFeatures/img/example.png diff --git a/plugins/NeatHTMLFeatures/img/example.png b/plugins/NeatHTMLFeatures/img/example.png new file mode 100644 index 0000000000000000000000000000000000000000..5efa4051b7f01ebc4fe0e2b7d3009714dab1d927 GIT binary patch literal 26328 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 literal 0 HcmV?d00001 From 244fcfe64b58b773d8ff6b3a0c4e398c990244c6 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Mon, 12 Feb 2018 18:44:47 -0800 Subject: [PATCH 75/86] add sample image --- plugins/NeatCanvasFeatures/img/example.png | Bin 0 -> 24169 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/NeatCanvasFeatures/img/example.png diff --git a/plugins/NeatCanvasFeatures/img/example.png b/plugins/NeatCanvasFeatures/img/example.png new file mode 100644 index 0000000000000000000000000000000000000000..ea13b5e782456b32a21aec7d7c3468e5388f979f GIT binary patch literal 24169 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 Date: Mon, 12 Feb 2018 18:53:09 -0800 Subject: [PATCH 76/86] cleanup warnings. use gradient mappings --- plugins/NeatCanvasFeatures/js/main.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/NeatCanvasFeatures/js/main.js b/plugins/NeatCanvasFeatures/js/main.js index 74e5b652a..320e7754a 100644 --- a/plugins/NeatCanvasFeatures/js/main.js +++ b/plugins/NeatCanvasFeatures/js/main.js @@ -33,7 +33,7 @@ return declare( JBrowsePlugin, var browser = this.browser; this.gradient = 1; - if(typeof args.gradientFeatures != 'undefined' && args.gradientFeatures == 0) { + if(typeof args.gradientFeatures !== 'undefined' && args.gradientFeatures === 0) { this.gradient = 0; } @@ -71,7 +71,7 @@ return declare( JBrowsePlugin, segments_renderFeature: function( context, fRect ) { //console.log("SegmentsEx.renderFeature fRect "); - if( this.track.displayMode != 'collapsed' ) + if( this.track.displayMode !== 'collapsed' ) context.clearRect( Math.floor(fRect.l), fRect.t, Math.ceil(fRect.w), fRect.h ); //this.renderConnector( context, fRect ); @@ -123,7 +123,7 @@ return declare( JBrowsePlugin, var _height = this._getFeatureHeight( viewInfo, subparts[i] ); if( ! _height ) return; - if( _height != overallHeight ) + if( _height !== overallHeight ) top += Math.round( (overallHeight - _height)/2 ); var height = _height / 2; @@ -160,7 +160,7 @@ return declare( JBrowsePlugin, var height = this._getFeatureHeight( viewInfo, feature ); if( ! height ) return; - if( height != overallHeight ) + if( height !== overallHeight ) top += Math.round( (overallHeight - height)/2 ); // background @@ -186,7 +186,7 @@ return declare( JBrowsePlugin, grd.addColorStop(0.999, bgcolor); // Fill with linear - context.fillStyle = bgcolor; + context.fillStyle = grd; } @@ -235,7 +235,7 @@ return declare( JBrowsePlugin, /** * Given color string in #rrggbb format, shift the color by shift % ( i.e. .20 is 20% brighter, -.30 is 30% darker. * The new string is returned. - * If color is not in #rrggbb format, just return the original value. + * If color is not in #rrggbb format, just return the original value. */ box_colorShift: function(color,shift) { @@ -345,7 +345,7 @@ function colourNameToHex(colour) { "wheat":"#f5deb3","white":"#ffffff","whitesmoke":"#f5f5f5", "yellow":"#ffff00","yellowgreen":"#9acd32"}; - if (typeof colours[colour.toLowerCase()] != 'undefined') + if (typeof colours[colour.toLowerCase()] !== 'undefined') return colours[colour.toLowerCase()]; return "#000000"; From bbd7cb1d11b15215d828351e09a742e687e7c6b0 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Mon, 12 Feb 2018 18:56:06 -0800 Subject: [PATCH 77/86] show example image in readme --- plugins/NeatCanvasFeatures/README.md | 2 ++ plugins/NeatHTMLFeatures/README.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/plugins/NeatCanvasFeatures/README.md b/plugins/NeatCanvasFeatures/README.md index 324b766a3..cf7d23f2e 100644 --- a/plugins/NeatCanvasFeatures/README.md +++ b/plugins/NeatCanvasFeatures/README.md @@ -2,6 +2,8 @@ It applies intron hats and a gradient 'tubular' look to features and subfeatures of CanvasFeatures tracks. +![](img/example.png?raw=true) + ### What it does: - draws intron hats and inverted hats for reverse direction features. - it applies a gradient 'tubular' look to features and subfeatures, inheriting the feature colors and properties. diff --git a/plugins/NeatHTMLFeatures/README.md b/plugins/NeatHTMLFeatures/README.md index f2712814a..eb38c5634 100644 --- a/plugins/NeatHTMLFeatures/README.md +++ b/plugins/NeatHTMLFeatures/README.md @@ -4,6 +4,8 @@ It applies intron hats and a gradient 'tubular' look to features and subfeatures This is refactored from HTMLFeaturesEx.js implementation and the insertion/modification to DOM elements are done out-of-band, due to difference between HTMLFeatures and DragableHTMLFeatures feature DOMs. +![](img/example.png?raw=true) + ### What it does: - draws intron hats and inverted hats for reverse direction features. - it applies a gradient 'tubular' look to features and subfeatures, inheriting the feature colors and properties. From 347bcd5f74487e34f76f023abd6496edfc0bc6c8 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 13 Feb 2018 16:03:23 -0800 Subject: [PATCH 78/86] add some more data to google analytics, change format of conf variable --- src/JBrowse/Browser.js | 62 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index f14766173..a95f70b27 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -139,7 +139,7 @@ constructor: function(params) { this.globalKeyboardShortcuts = {}; this.config = params || {}; - + // if we're in the unit tests, stop here and don't do any more initialization if( this.config.unitTestMode ) return; @@ -152,7 +152,7 @@ constructor: function(params) { // start the initialization process var thisB = this; - + dojo.addOnLoad( function() { thisB.loadConfig().then( function() { @@ -532,7 +532,7 @@ loadRefSeqs: function() { request(this.config.refSeqs.url, { handleAs: 'text', headers: { - 'X-Requested-With': null + 'X-Requested-With': null } } ) .then( function(o) { @@ -1677,17 +1677,13 @@ _reportGoogleUsageStats: function( stats ) { var jbrowseUser = 'UA-7115575-2' var accounts = [ jbrowseUser ]; - // add one or more custom Google Analytics accounts from config (comma-separated) - if (thisB.config.selfGoogleUsageAccount) { - // cooerce into an array, so we handle any potential comma separated lists - var users = thisB.config.selfGoogleUsageAccount; - if( users && typeof users == 'object' && 'values' in users ) - users = users.values; - if( users && ! Array.isArray( users ) ) - users = [users]; - users.forEach(function(user) { - accounts.push(user); - }); + // add any custom Google Analytics accounts from config (comma-separated or array) + if( this.config.googleAnalytics ) { + var userAccounts = this.config.googleAnalytics.accounts; + if( accounts && ! lang.isArray(userAccounts) ) { + userAccounts = userAccounts.replace(/^\s*|\s*$/,'').split(/\s*,\s*/) + } + accounts.push.apply( accounts, userAccounts ); } var analyticsScript = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ "; @@ -1696,40 +1692,38 @@ _reportGoogleUsageStats: function( stats ) { analyticsScript += "})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');"; // set up users - var trackerNum = 1; - accounts.forEach(function(user) { + accounts.forEach(function(user,trackerNum) { // if we're adding jbrowse.org user, also include new dimension references (replacing ga.js custom variables) if ( user == jbrowseUser) { analyticsScript += "ga('create', '"+user+"', 'auto', 'jbrowseTracker');"; } else { analyticsScript += "ga('create', '"+user+"', 'auto', 'customTracker"+trackerNum+"');"; - trackerNum++; } }); - // send pageviews - var viewerNum = 1; - accounts.forEach(function(user) { + + // send pageviews and custom variables + accounts.forEach(function(user,viewerNum) { if ( user == jbrowseUser) { - // custom dimensions to replace the custom vars from older ga.js implementation - analyticsScript += "ga('jbrowseTracker.set', 'tracks-count', "+stats['tracks-count']+");"; - analyticsScript += "ga('jbrowseTracker.set', 'refSeqs-count', "+stats['refSeqs-count']+");"; - analyticsScript += "ga('jbrowseTracker.set', 'refSeqs-avgLen', "+stats['refSeqs-avgLen']+");"; - analyticsScript += "ga('jbrowseTracker.set', 'jbrowse-version', '"+stats['ver']+"');"; - analyticsScript += "ga('jbrowseTracker.set', 'loadTime', "+stats['loadTime']+");"; - analyticsScript += "ga('jbrowseTracker.send', 'pageview');"; - } - else { + var rename = { ver: 'jbrowse-version' } + var gaData = {}; + 'tracks-count refSeqs-count refSeqs-avgLen ver loadTime electron plugins' + .split(/\s+/) + .forEach( function(key) { + gaData[rename[key]||key] = stats[key]; + }); + + analyticsScript += "ga('jbrowseTracker.send', 'pageview',"+JSON.stringify(gaData)+");"; + } + else { analyticsScript += "ga('customTracker"+viewerNum+".send', 'pageview');"; - viewerNum++; } }); - var analytics = document.createElement('script'); - analytics.innerHTML = analyticsScript; + var analyticsScriptNode = document.createElement('script'); + analyticsScriptNode.innerHTML = analyticsScript; - var thisHead = document.getElementsByTagName('head')[0]; - thisHead.appendChild(analytics); + document.getElementsByTagName('head')[0].appendChild(analyticsScriptNode); }, // phones home to custom analytics at jbrowse.org From 4a713396ec9401959d33bae959af72a49dc22da9 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 13 Feb 2018 16:04:48 -0800 Subject: [PATCH 79/86] update release notes --- release-notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release-notes.txt b/release-notes.txt index da77abdd3..112456e94 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -52,6 +52,8 @@ * Fixed a "cannot read property 'offsetLeft'" error when using touch screens without the old simple track selector active. (issue #893, @rbuels) + * Upgraded to use new Google Analytics API for usage reporting. (@rdhayes) + # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles ## Minor improvements From 1b56e6696146796a60c65d492e57d6d272b97413 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 13 Feb 2018 16:05:11 -0800 Subject: [PATCH 80/86] remove some trailing whitespace in the release notes --- release-notes.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/release-notes.txt b/release-notes.txt index 112456e94..29c87bd2a 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -14,7 +14,7 @@ * Added a `--trackConfig` option to `prepare-refseqs.pl` to allow injecting refseq configuration variables at format time. @erasche - * Added trackLabels: "no-block" config feature. Moves track labels/menus + * Added trackLabels: "no-block" config feature. Moves track labels/menus above the features so as not to obscure the features. (issue #901, #490) * Make jbrowse npm installable. thanks to @cmdcolin & @enuggetry. @@ -103,9 +103,9 @@ * Added subfeatureDetailLevel config item to make View details box only load subfeatures on demand (issue #861). - + * Added ability to draw scatter plot from BigWig tracks. Thanks to - Keiran Raine for the contribution (issue #741). + Keiran Raine for the contribution (issue #741). * Added a fullviewlink option for the URL bar to disable "View full link" attribute in embedded JBrowse. Thanks to Vivek Krishnakumar @@ -145,7 +145,7 @@ Eric Rasche for reporting (issue #673). * Fixed some issues where the Gene glyph would not layout some - features correctly. Thanks to Eric Rasche for reporting + features correctly. Thanks to Eric Rasche for reporting (issue #686). * Fixed an issue with JBrowse Desktop where saving session would not @@ -191,7 +191,7 @@ ## Bug fixes - * Fix RegexSearch plugin and NeatCanvasFeatures plugin - search track + * Fix RegexSearch plugin and NeatCanvasFeatures plugin - search track loading failure (issue #676) * Fix compat_121.html to access /css directory @@ -273,7 +273,7 @@ pointing to important data, but this is uncommon (issue #563). * Allow falsey values to be used in browser.cookie. - + * Fix minor issue where sometimes the length field of refSeqs.json was missing. @@ -419,11 +419,11 @@ chunkSizeLimit errors. Thanks to Richard Hayes for finding and debugging this issue (issue #486)! - * Fixed a bug where the Variant popup boxes would not display + * Fixed a bug where the Variant popup boxes would not display complete genotype information in previous 1.11.* versions. Thanks to Nando for reporting the bug and Colin Diesh for the bugfix (issue #488). - + * Fixed a small error that occured when using variant type tracks with the REST API. @@ -464,7 +464,7 @@ menu or by using the in-memory adaptor. Big thanks to Andrew Warren for the contribution (issue #453). - * Added a change to the highlight button to allow the user to more + * Added a change to the highlight button to allow the user to more easily clear highlights. Thanks to Paul Hale for the suggestion and Colin Diesh for the fix (issue #445). @@ -478,7 +478,7 @@ original implementation and Colin Diesh for the fix (issue #461). * Changed the CanvasFeatures 'View details' pages to display the name - and description of features in the dialog box. Thanks to Colin + and description of features in the dialog box. Thanks to Colin Diesh for the fix (issue #463). * Added a bugfix for non-compliant servers that add a trailing slash @@ -564,7 +564,7 @@ and Colin Diesh for the bugfix (issue #435) * Fixed a bug where gene features in GFF tracks would not have - arrowhead markers. Thanks to Colin Diesh for finding and fixing + arrowhead markers. Thanks to Colin Diesh for finding and fixing this issue (issue #454) # Release 1.11.2 2014-02-10 19:11:33 EST5EDT From bc92c53dff55764b31c68b48cf49c7bf63047aa9 Mon Sep 17 00:00:00 2001 From: enuggetry Date: Tue, 13 Feb 2018 16:24:41 -0800 Subject: [PATCH 81/86] beautify docs --- plugins/CategoryUrl/README.md | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/plugins/CategoryUrl/README.md b/plugins/CategoryUrl/README.md index 103c936fd..258aba230 100644 --- a/plugins/CategoryUrl/README.md +++ b/plugins/CategoryUrl/README.md @@ -1,29 +1,35 @@ -CategoryURL - JBrowse plugin +# CategoryURL - JBrowse plugin Add URL parameter "cat" to specify a category of tracks to display. All tracks with the given category will be displayed. If any "tracks" are specified in the URL, "cat" tracks will be appended to list. -Usage: Add &cat=myCategory +Usage: Add `&cat=myCategory` to the URL Result: all tracts with category "myCategory" will be displayed. -Sub-categories are supported as well (i.e. "&cat=myCategory/mySubCategory" +Sub-categories are supported as well (i.e. `&cat=myCategory/mySubCategory`) The cat= URL parameter allows the display of tracks with the given category defined in the track metadata that are used to group tracks in the hierarchical track selector. For example: -"category" : "Miscellaneous", + "category" : "Miscellaneous", Example: -http:///?data=sample_data/json/volvox&cat=Miscellaneous -http:///?data=sample_data/json/volvox&cat=Quantitative/Density -Install / Activate: + http:///?data=sample_data/json/volvox&cat=Miscellaneous + + http:///?data=sample_data/json/volvox&cat=Quantitative/Density + + +### Install / Activate: + +For JBrowse 1.11.6+, copy the `CategoryUrl` directory to the `JBrowse` plugins directory. +Add this to appropriate `trackList.json` under the plugins section (create section, if it doesn't exist): + + "plugins": [ + 'CategoryUrl' + ], + -For JBrowse 1.11.6+, copy the CategoryUrl directory to the JBrowse 'plugins' directory. -Add this to appropriate trackList.json under the plugins section (create section, if it doesn't exist): - "plugins": [ - 'CategoryUrl' - ], From 4d84ae8bfdcc0924e8a017c6cf8388fbb20ef1a8 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 13 Feb 2018 16:44:37 -0800 Subject: [PATCH 82/86] change google analytics code to refer to dimensions and metrics by number, since, while it seems to work to refer to them by name, the analytics.js docs say to refer to them by index number, so that is probably what will be more reliably supported. --- src/JBrowse/Browser.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index a95f70b27..e276b27dc 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -1705,14 +1705,16 @@ _reportGoogleUsageStats: function( stats ) { // send pageviews and custom variables accounts.forEach(function(user,viewerNum) { if ( user == jbrowseUser) { - var rename = { ver: 'jbrowse-version' } var gaData = {}; - 'tracks-count refSeqs-count refSeqs-avgLen ver loadTime electron plugins' - .split(/\s+/) - .forEach( function(key) { - gaData[rename[key]||key] = stats[key]; + var googleDimensions = 'tracks-count refSeqs-count refSeqs-avgLen ver loadTime electron plugins'; + var googleMetrics = 'loadTime'; + + googleDimensions.split(/\s+/).forEach( function(key,index) { + gaData['dimension'+(index+1)] = stats[key]; }); + gaData.metric1 = Math.round(stats.loadTime*1000); + analyticsScript += "ga('jbrowseTracker.send', 'pageview',"+JSON.stringify(gaData)+");"; } else { From 86b75b90c79d9f916f9822b7ca936067f656f021 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Tue, 13 Feb 2018 17:57:22 -0800 Subject: [PATCH 83/86] updated release notes for all issues and pulls in the 1.12.4 milestone --- release-notes.txt | 57 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/release-notes.txt b/release-notes.txt index 557be4c0e..bbc10ba74 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -4,7 +4,7 @@ * Fixed SEVERE performance regression that basically made flatfile-to-json.pl unusable on Perl 5.18 and higher. Huge thanks to Colin Diesh for tracking - this down. (issue #470, @cmdcolin) + this down. (issue #470, pull #912, @cmdcolin) * setup.sh now uses npm instead of Bower (which is deprecated) to install dependencies. @enuggetry @@ -12,20 +12,23 @@ * Removed legacy `wig-to-json.pl` and `bam-to-json.pl` scripts. @rbuels * Added a `--trackConfig` option to `prepare-refseqs.pl` to allow injecting - refseq configuration variables at format time. @erasche + refseq configuration variables at format time. (pull #884, @erasche) * Added trackLabels: "no-block" config feature. Moves track labels/menus above the features so as not to obscure the features. (issue #901, #490) - * Make jbrowse npm installable. thanks to @cmdcolin & @enuggetry. + * Added a `--category` option to `add-bw-track.pl` and `add-bam-track.pl` to + set the new track's category. Thanks to @loraine-gueguen for the implementation! + (pull #911, @loraine-gueguen) - * Change "Length on ref" to "Seq length on ref" in Alignments feature detail boxes, - so that the length on the reference appears next to the sequence length. Thanks to - @colindaven for the suggestion! + * Made jbrowse installable using `npm`. @cmdcolin and @enuggetry. - * implement express server for jbrowse for quick launch (jb_run.js). @enuggetry. + * Implemented a built-in node.js Express server `jb_run.js` for quick JBrowse launching. + @enuggetry - * jb_setup.js @enuggetry. + * Added an `--unsorted` option to `prepare-refseqs.pl` that formats reference sequences + in the same order in which they appear in the input sequence file. Thanks to + @dsenalik for the suggestion and implementation! (pull #924, @dsenalik) * Allows for dot-notation instead of JSON (pull #952) for addTracks, addBookmarks, and addStores. https://github.com/GMOD/jbrowse/pull/952. Address security concerns @@ -33,7 +36,7 @@ * If a track has no `key` set in its track configuration, JBrowse will now look for a `key` in its track metadata, and use that if it is present. Thanks to Loraine - Guéguen for the idea (issue #957). @rbuels + Guéguen for the idea (issue #957, pull #958). @rbuels * Suppress execution of biodb-to-json.pl on sample data while running setup.sh on MacOS High Sierra with stock Perl due to an issue with the stock Perl having @@ -58,6 +61,42 @@ * Upgraded to use new Google Analytics API for usage reporting. (@rdhayes) + * Fixed bug in which start/stop codons were sometimes not displayed in the sequence + track at certain zoom levels (issue #858, pull req #859, @cmdcolin) + + * Fixed a regression in which the `defaultTracks` configuration variable was no longer + respected when set to a comma-separated list. (issue #892, pull #896, @rdhayes) + + * Made a cosmetic change to Alignments track detail popups, changing "Length on ref" to + be displayed as "Seq length on ref", so that it is displayed more usefully next to + "Seq length". Thanks to @colindaven for the suggestion and implementation! + (pull #939, @colindaven) + + * Improved the error messages displayed when a JBrowse glyph class fails to load. Thanks + to @scottcain and @cmdcolin for tracking down the issue and improving the error + handling! (issue #968, @cmdcolin) + + * Added support for an `addFeatures` URL query parameter that can inject features from + the URL query string. (issue #976, @nathandunn) + + * Changed the project's `git` workflow to utilize a `dev` branch that is separate from + `master`, with `master` only being updated when a new release of JBrowse is published. + (issue #975, @enuggetry) + + * Implemented automated deployment of JBrowse releases to GitHub releases and `npm`. + Thanks to @abretaud, @nathandunn, @erasche, and @cmdcolin for valuable discussions. + (issue #822, pull #979, pull #984, @rbuels) + + * Added a `--bigwigCoverage` option to `add-bam-track.pl` to support configuring pregenerated + coverage histograms from the command line. Thanks to @loraine-gueguen for the suggestion + and implementation! (pull #972, @loraine-gueguen) + + * Improved documentation of the `CategoryURL` plugin. (pull #985, @enuggetry) + + * Re-enabled and improved documentation and configurability of the gradient colors in the + `NeatCanvasFeatures` plugin. (issue #982, pull #985, @enuggetry) + + # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles ## Minor improvements From e97ff55cf2c57c2108a36059a3a1dd0aedde4200 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 14 Feb 2018 08:56:23 -0800 Subject: [PATCH 84/86] updated release notes some more thanks to @cmdcolin for pointing out some stuff I missed! --- release-notes.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/release-notes.txt b/release-notes.txt index bbc10ba74..263993728 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -6,6 +6,15 @@ unusable on Perl 5.18 and higher. Huge thanks to Colin Diesh for tracking this down. (issue #470, pull #912, @cmdcolin) + * Added code to calculate feature density histograms for Tabix-indexed GFF3 + (`GFF3Tabix`) data sources. Thanks to @nathandunn for noticing and fixing + this! (pull #956, @nathandunn) + + * Added a new "Hide unspliced reads" menu item to Alignments and Alignments2 + tracks that filter out reads that have no `N`s in their CIGAR strings. + Thanks to Deepak Kunni and Nathan Dunn for their work on this. + (pull #921, @deepakunni3) + * setup.sh now uses npm instead of Bower (which is deprecated) to install dependencies. @enuggetry @@ -38,6 +47,17 @@ a `key` in its track metadata, and use that if it is present. Thanks to Loraine Guéguen for the idea (issue #957, pull #958). @rbuels + * Fixed bug in `maker2jbrowse` script that allows `maker2jbrowse` to be installed + in system executable directories, and adds a `--sortMem` option. + (pull #877, @cmdcolin) + + * Fixed a cosmetic/styling bug with malformed DOM structure in feature detail popup + dialogs. Thanks to Erik Rasche for noticing and fixing this! (pull #882, @erasche) + + * Added a configuration option that can disable JBrowse's behavior of updating the + browser's title text as the view changes. Thanks to Luka Jeran, Primož Hadalin, + and Nathan Dunn for this! (pull #904, @lukaw3d) + * Suppress execution of biodb-to-json.pl on sample data while running setup.sh on MacOS High Sierra with stock Perl due to an issue with the stock Perl having broken BerkeleyDB integration, which is needed by Bio::DB::SeqFeature::Store, From fcf4fa51d1dd519eb8e98c7b01fcaebd5e38eb07 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 14 Feb 2018 13:00:05 -0800 Subject: [PATCH 85/86] Revert "Merge pull request #985 from GMOD/fix_neatcf" This reverts commit e9c13c168515d5c3439fbdc58c0d33d073fd2598, reversing changes made to 89bcd35d0ec4c6bcc1e30d2a47df0896f38fc8b7. --- plugins/CategoryUrl/README.md | 30 ++--- plugins/NeatCanvasFeatures/README.md | 45 ++++--- plugins/NeatCanvasFeatures/img/example.png | Bin 24169 -> 0 bytes plugins/NeatCanvasFeatures/js/main.js | 26 ++-- plugins/NeatHTMLFeatures/README.md | 134 ++++++++++----------- plugins/NeatHTMLFeatures/img/example.png | Bin 26328 -> 0 bytes 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 plugins/NeatCanvasFeatures/img/example.png delete mode 100644 plugins/NeatHTMLFeatures/img/example.png diff --git a/plugins/CategoryUrl/README.md b/plugins/CategoryUrl/README.md index 258aba230..103c936fd 100644 --- a/plugins/CategoryUrl/README.md +++ b/plugins/CategoryUrl/README.md @@ -1,35 +1,29 @@ -# CategoryURL - JBrowse plugin +CategoryURL - JBrowse plugin Add URL parameter "cat" to specify a category of tracks to display. All tracks with the given category will be displayed. If any "tracks" are specified in the URL, "cat" tracks will be appended to list. -Usage: Add `&cat=myCategory` to the URL +Usage: Add &cat=myCategory Result: all tracts with category "myCategory" will be displayed. -Sub-categories are supported as well (i.e. `&cat=myCategory/mySubCategory`) +Sub-categories are supported as well (i.e. "&cat=myCategory/mySubCategory" The cat= URL parameter allows the display of tracks with the given category defined in the track metadata that are used to group tracks in the hierarchical track selector. For example: - "category" : "Miscellaneous", +"category" : "Miscellaneous", Example: +http:///?data=sample_data/json/volvox&cat=Miscellaneous +http:///?data=sample_data/json/volvox&cat=Quantitative/Density - http:///?data=sample_data/json/volvox&cat=Miscellaneous - - http:///?data=sample_data/json/volvox&cat=Quantitative/Density - - -### Install / Activate: - -For JBrowse 1.11.6+, copy the `CategoryUrl` directory to the `JBrowse` plugins directory. -Add this to appropriate `trackList.json` under the plugins section (create section, if it doesn't exist): - - "plugins": [ - 'CategoryUrl' - ], - +Install / Activate: +For JBrowse 1.11.6+, copy the CategoryUrl directory to the JBrowse 'plugins' directory. +Add this to appropriate trackList.json under the plugins section (create section, if it doesn't exist): + "plugins": [ + 'CategoryUrl' + ], diff --git a/plugins/NeatCanvasFeatures/README.md b/plugins/NeatCanvasFeatures/README.md index cf7d23f2e..2b9e8f5d6 100644 --- a/plugins/NeatCanvasFeatures/README.md +++ b/plugins/NeatCanvasFeatures/README.md @@ -1,25 +1,24 @@ -# NeatCanvasFeatures - a JBrowse plugin. +NeatCanvasFeatures is a JBrowse plugin. It applies intron hats and a gradient 'tubular' look to features and subfeatures of CanvasFeatures tracks. -![](img/example.png?raw=true) - -### What it does: +What it does: - draws intron hats and inverted hats for reverse direction features. - it applies a gradient 'tubular' look to features and subfeatures, inheriting the feature colors and properties. - modifies UTR to be a outlined box, inheriting the original color. - generally functional in stand-alone JBrowse. -### Install / Activate: -For JBrowse 1.11.6+, copy the `NeatCanvasFeatures` directory to the `plugins` directory. -Add this to appropriate **trackList.json** under the plugins section (create one if it doesn't exist): +Install / Activate: + +For JBrowse 1.11.6+, copy the NeatCanvasFeatures directory to the 'plugins' directory. +Add this to appropriate trackList.json under the plugins section (create one if it doesn't exist): - "plugins": [ - 'NeatCanvasFeatures' - ], + "plugins": [ + 'NeatCanvasFeatures' + ], -For Apollo 2.x, copy the NeatCanvasFeatures directory to the `web-apps/jbrowse/plugins` directory. -Add this to `web-apps/jbrowse/plugins/WebApollo/json/annot.json`: +For Apollo 2.x, copy the NeatCanvasFeatures directory to the web-apps/jbrowse/plugins directory. +Add this to web-apps/jbrowse/plugins/WebApollo/json/annot.json: "plugins" : [ { @@ -30,22 +29,22 @@ Add this to `web-apps/jbrowse/plugins/WebApollo/json/annot.json`: "location" : "./plugins/NeatCanvasFeatures", "name" : "NeatCanvasFeatures" } - ], + ], -### Config Options: -Gradient Features are on for all HTML feature tracks by default. -They can be turned off globally in the config file by setting `gradientFeatures = 0` in the plugin definition, for example: +Config Options: +Gradient Features are on for all HTML feature tracks by default. - "plugins": [ - { - "name": "NeatHTMLFeatures", - "gradientFeatures": 0 - } - ], +They can be turned off globally in the config file by setting gradientFeatures = 0 in the plugin definition, for example: -When `gradientFeatures = 0` (globally off) in the plugins definition, gradient features can be enabled on per track basis with `gradientFeatures = 1` in the track configuration, for example: + "plugins": [ + { + "name": "NeatHTMLFeatures", + "gradientFeatures": 0 + } + ], +When gradientFeatures = 0 (globally off) in the plugins definition, gradient features can be enabled on per track basis with gradientFeatures = 1 in the track configuration, for example: "tracks": [ { ... diff --git a/plugins/NeatCanvasFeatures/img/example.png b/plugins/NeatCanvasFeatures/img/example.png deleted file mode 100644 index ea13b5e782456b32a21aec7d7c3468e5388f979f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24169 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 From f742408dca00d42cf51bdf0ad778a5936b0db0d2 Mon Sep 17 00:00:00 2001 From: Robert Buels Date: Wed, 14 Feb 2018 14:25:41 -0800 Subject: [PATCH 86/86] update release notes, improve issue, pull, and person linking in release notes HTML script --- build/format_release_notes.pl | 2 ++ release-notes.txt | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build/format_release_notes.pl b/build/format_release_notes.pl index 939f8f8eb..74738514f 100755 --- a/build/format_release_notes.pl +++ b/build/format_release_notes.pl @@ -7,4 +7,6 @@ local $/; my $html = markdown( scalar <> ); $html =~ s!issue \#(\d+)!issue #$1!g; +$html =~ s!pull ( request)?\#(\d+)!issue #$2!g; +$html =~ s!(\W)\@(\w+)!$1\@$2!g; print $html; diff --git a/release-notes.txt b/release-notes.txt index 263993728..f25f1a424 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -113,10 +113,6 @@ * Improved documentation of the `CategoryURL` plugin. (pull #985, @enuggetry) - * Re-enabled and improved documentation and configurability of the gradient colors in the - `NeatCanvasFeatures` plugin. (issue #982, pull #985, @enuggetry) - - # Release 1.12.3 2017-05-02 19:20:01 America/Los_Angeles ## Minor improvements