From de72e2579d8c6e0693a3ba0cc52e1304d55966d9 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Tue, 23 Jan 2024 16:01:53 +0000 Subject: [PATCH 01/18] Fixed correct pp collection root for MiSeq. pp data collections should always be per product regardless of the instrument type and should be uploaded under the common iRODS pp collection root. --- .../function/pp_data_to_irods_archiver.pm | 17 ++++++++- t/20-function-pp_data_to_irods_archiver.t | 36 ++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/npg_pipeline/function/pp_data_to_irods_archiver.pm b/lib/npg_pipeline/function/pp_data_to_irods_archiver.pm index 504cb841..8c4addba 100644 --- a/lib/npg_pipeline/function/pp_data_to_irods_archiver.pm +++ b/lib/npg_pipeline/function/pp_data_to_irods_archiver.pm @@ -16,6 +16,15 @@ has '+irods_root_collection_ns' => ( default => __PACKAGE__->irods_pp_root_collection(), ); +##### +# per_product_archive attribute is inherited by this class from +# npg_pipeline::product::release::irods via the parent class. +# The builder method is overwritten here to return true regardless of the +# instrument type. +sub _build_per_product_archive { + return 1; +} + sub create { my $self = shift; @@ -123,6 +132,12 @@ npg_pipeline::function::pp_data_to_irods_archiver =head2 irods_root_collection_ns +=head2 per_product_archive + +Inherited from npg_pipeline::product::release::irods via the parent class. +The builder method is overwritten here to return true regardless of the +instrument type. + =head2 create =head1 DIAGNOSTICS @@ -156,7 +171,7 @@ Marina Gourtovaia =head1 LICENSE AND COPYRIGHT -Copyright (C) 2020,2022 Genome Research Ltd. +Copyright (C) 2020,2022,2024 Genome Research Ltd. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/t/20-function-pp_data_to_irods_archiver.t b/t/20-function-pp_data_to_irods_archiver.t index f5c8de77..c7fa7c3c 100644 --- a/t/20-function-pp_data_to_irods_archiver.t +++ b/t/20-function-pp_data_to_irods_archiver.t @@ -4,7 +4,7 @@ use Cwd; use Math::Random::Secure qw(srand); use JSON; use File::Slurp; -use Test::More tests => 4; +use Test::More tests => 5; use Test::Exception; use File::Copy::Recursive qw(fcopy dircopy); use File::Temp qw(tempdir); @@ -17,6 +17,10 @@ dircopy("t/data/novaseq/$rf_name", $runfolder_path); my $bbc_path = join q[/], $runfolder_path, 'Data/Intensities/BAM_basecalls_20200710-105415'; +# restart dir is no longer created if not present because it is +# now present in all runfolders +mkdir $bbc_path . q(/irods_publisher_restart_files/); + local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = join q[/], $bbc_path, 'metadata_cache_34576/samplesheet_34576.csv'; @@ -75,10 +79,6 @@ subtest 'create job definition' => sub { # seed the random number generator. srand('1x4y5z8k'); - # restart dir is no longer created if not present because it is - # now present in all runfolders - mkdir $bbc_path . q(/irods_publisher_restart_files/); - my $archiver = $pkg->new( %init, timestamp => '20200806-130730', @@ -156,4 +156,30 @@ subtest 'create job definition' => sub { }; +subtest 'create job definition, MiSeq run' => sub { + plan tests => 3; + + unlink "$runfolder_path/RunParameters.xml"; + unlink "$runfolder_path/RunInfo.xml"; + + fcopy 't/data/miseq/46761_runParameters.xml', + "$runfolder_path/runParameters.xml"; + fcopy 't/data/miseq/46761_RunInfo.xml', + "$runfolder_path/RunInfo.xml"; + + my $ss_path = $ENV{NPG_CACHED_SAMPLESHEET_FILE}; + my @lines = read_file($ss_path); + write_file($ss_path, @lines[0 .. 4]); # Two header lines and three samples + # from lane 1. + my $ds = $pkg->new(%init)->create(); + my $num_expected = 3; + is(scalar @{$ds}, $num_expected, "expected $num_expected definitions"); + my $d = $ds->[0]; + ok (!$d->excluded, 'function is not excluded'); + my $expected = 'npg_publish_tree.pl' . + q( --collection /seq/illumina/pp/runs/34/34576/lane1/plex1) . + q( --source ) . $bbc_path . q(/pp_archive/lane1/plex1); + like ($d->command, qr/$expected/, 'correct data source and destination'); +}; + unlink $syslog_config; From 13d391f878b9350f94acd4dace772fec46367b3a Mon Sep 17 00:00:00 2001 From: jmtcsngr Date: Wed, 24 Jan 2024 15:22:34 +0000 Subject: [PATCH 02/18] prep release 67.1.1 --- Changes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changes b/Changes index af13f472..28b2b586 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,9 @@ LIST OF CHANGES --------------- +release 67.1.1 + - Fixed correct pp collection root for MiSeq + release 67.1.0 - Fix typo in analysis specific overrides for bwa_als_se mapping to bwa0_6 - Add in use of autosome target regions for BGE libraries in seq_alignment From c7483621e4100f1d493fb3f80b64f30817d64ed8 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Thu, 25 Jan 2024 18:35:53 +0000 Subject: [PATCH 03/18] Added a log message about deletable shadow folders. Deletable shadow folders are detected, but not considered as deletable for now. They are flagged in the log of the npg_run_is_deletable script. --- lib/npg_pipeline/validation.pm | 24 +++++++++- t/10-validation.t | 80 ++++++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/lib/npg_pipeline/validation.pm b/lib/npg_pipeline/validation.pm index 305cd95a..e11c77f2 100644 --- a/lib/npg_pipeline/validation.pm +++ b/lib/npg_pipeline/validation.pm @@ -29,7 +29,9 @@ with qw{npg_pipeline::validation::common our $VERSION = '0'; Readonly::Array my @NPG_DELETABLE_UNCOND => ('run cancelled', 'data discarded'); -Readonly::Array my @NPG_DELETABLE_STATES => (@NPG_DELETABLE_UNCOND,'qc complete'); +Readonly::Scalar my $QC_COMPLETE_STATUS => q[qc complete]; +Readonly::Array my @NPG_DELETABLE_STATES => + (@NPG_DELETABLE_UNCOND, $QC_COMPLETE_STATUS); Readonly::Scalar my $MIN_KEEP_DAYS => 14; Readonly::Scalar my $UNREALISTIC_NUM_STAGING_PP_FILES => 10_000; Readonly::Scalar my $DEFAULT_IRODS_ROOT => q[/seq]; @@ -457,6 +459,16 @@ sub run { $self->_flagged_as_not_deletable() and return 0; + # For now just inform about a deletable shadow run folder. The folder + # will be deleted manually. + # Later, when we gain confidence, we might return 1 here, which will + # result in the automatic deletion. + if ($self->_is_deletable_shadow_runfolder()) { + $self->info(sprintf 'Shadow runfolder %s for run %i can be deleted', + $self->runfolder_path, $self->id_run); + return 0; + } + my $deletable = $self->_npg_tracking_deletable('unconditional'); my $vars_set = 0; @@ -993,6 +1005,16 @@ sub _file_archive_deletable { return $deletable; } +sub _is_deletable_shadow_runfolder { + my $self = shift; + if ( ($self->runfolder_path() =~ m{/incoming/}xms) && + ($self->_run_status_obj->description eq $QC_COMPLETE_STATUS) && + !$self->tracking_run->is_tag_set($STAGING_TAG)) { + return 1; + } + return 0; +} + ########################################################### # The code of this function was copied from # L diff --git a/t/10-validation.t b/t/10-validation.t index 09ca512e..56b720af 100644 --- a/t/10-validation.t +++ b/t/10-validation.t @@ -1,11 +1,11 @@ use strict; use warnings; -use Test::More tests => 8; +use Test::More tests => 9; use Test::Exception; use Test::Warn; use Test::Trap qw/ :warn /; use File::Path qw/ make_path /; -use File::Slurp qw/ write_file /; +use File::Slurp qw/ read_file write_file /; use File::Copy; use Log::Log4perl qw/ :levels /; use File::Temp qw/ tempdir /; @@ -19,7 +19,7 @@ use_ok ('npg_pipeline::validation'); my $util = t::util->new(); my $logfile = join q[/], $util->temp_directory(), 'logfile'; Log::Log4perl->easy_init({layout => '%d %-5p %c - %m%n', - level => $WARN, + level => $INFO, file => $logfile, utf8 => 1}); @@ -358,4 +358,78 @@ subtest 'presence of onboard analysis results' => sub { 'NovaSeq - no onboard analysis - deletable'); }; +subtest 'shadow runfolder' => sub { + plan tests => 7; + + my $id_run = 35348; + my $run_row = $tracking_schema->resultset('Run')->find($id_run); + $run_row or die "Run $id_run is missing from the test tracking database"; + + my $staging_path = tempdir(CLEANUP => 1); + $run_row->update({folder_path_glob => "$staging_path/*/"}); + + my $runfolder_path = join q[/], $staging_path, 'incoming', + $run_row->folder_name; + make_path($runfolder_path); + copy('t/data/novaseq/35843_RunInfo.xml',"$runfolder_path/RunInfo.xml"); + copy('t/data/novaseq/35843_RunParameters.xml',"$runfolder_path/RunParameters.xml"); + + my $qc_status = 'archival pending'; + my $status_disc_row = $tracking_schema->resultset('RunStatusDict') + ->search({description => $qc_status})->next(); + my $rs = $tracking_schema->resultset('RunStatus'); + map { $_->update({iscurrent => 0}) } $rs->search({id_run => $id_run})->all(); + $rs->create({ + id_run_status_dict => $status_disc_row->id_run_status_dict, + id_run => $id_run, + id_user => 1, + iscurrent => 1 + }); + ok ($run_row->current_run_status_description() eq $qc_status, + "current status is '$qc_status'"); + $run_row->set_tag('joe_admin','staging'); + + my $v = npg_pipeline::validation->new( + qc_schema => $qc_schema, + npg_tracking_schema => $tracking_schema, + id_run => $id_run, + runfolder_path => $runfolder_path + ); + ok (!$v->_is_deletable_shadow_runfolder(), 'shadow run folder is not deletable'); + + $qc_status = 'qc complete'; + $status_disc_row = $tracking_schema->resultset('RunStatusDict') + ->search({description => $qc_status})->next(); + map { $_->update({iscurrent => 0}) } $rs->search({id_run => $id_run})->all(); + $rs->create({ + id_run_status_dict => $status_disc_row->id_run_status_dict, + id_run => $id_run, + id_user => 1, + iscurrent => 1 + }); + ok ($run_row->current_run_status_description() eq $qc_status, + "current status is '$qc_status'"); + + $v = npg_pipeline::validation->new( + qc_schema => $qc_schema, + npg_tracking_schema => $tracking_schema, + id_run => $id_run, + runfolder_path => $runfolder_path + ); + ok (!$v->_is_deletable_shadow_runfolder(), 'shadow run folder is not deletable'); + + $run_row->unset_tag('staging'); + $v = npg_pipeline::validation->new( + qc_schema => $qc_schema, + npg_tracking_schema => $tracking_schema, + id_run => $id_run, + runfolder_path => $runfolder_path + ); + ok ($v->_is_deletable_shadow_runfolder(), 'shadow run folder is deletable'); + ok (!$v->run(), q[..., but the return value is 'not deletable']); + like (read_file($logfile), + qr/Shadow runfolder $runfolder_path for run $id_run can be deleted/, + 'expected info in the log file'); +}; + 1; From 0f79fd87da5731b7f63f92dc33dc7f264f35e77a Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Thu, 1 Feb 2024 14:22:12 +0000 Subject: [PATCH 04/18] Removed cache_merge_component pipeline function. This function was used by the URB project, no longer required. --- MANIFEST | 2 - .../function_list_post_qc_review.json | 18 -- lib/npg_pipeline/base/options.pm | 14 - .../function/cache_merge_component.pm | 197 ------------- lib/npg_pipeline/pluggable/registry.pm | 1 - t/20-function-cache_merge_component.t | 267 ------------------ 6 files changed, 499 deletions(-) delete mode 100644 lib/npg_pipeline/function/cache_merge_component.pm delete mode 100644 t/20-function-cache_merge_component.t diff --git a/MANIFEST b/MANIFEST index 2d93e029..4450e22e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -38,7 +38,6 @@ lib/npg_pipeline/function/autoqc.pm lib/npg_pipeline/function/autoqc/generic.pm lib/npg_pipeline/function/autoqc_archiver.pm lib/npg_pipeline/function/bqsr_calc.pm -lib/npg_pipeline/function/cache_merge_component.pm lib/npg_pipeline/function/cluster_count.pm lib/npg_pipeline/function/current_analysis_link.pm lib/npg_pipeline/function/definition.pm @@ -104,7 +103,6 @@ t/20-function-autoqc.t t/20-function-autoqc-generic.t t/20-function-autoqc_archiver.t t/20-function-bqsr_calc.t -t/20-function-cache_merge_component.t t/20-function-cluster_count.t t/20-function-current_analysis_link.t t/20-function-definition.t diff --git a/data/config_files/function_list_post_qc_review.json b/data/config_files/function_list_post_qc_review.json index 8d31602c..c95821eb 100644 --- a/data/config_files/function_list_post_qc_review.json +++ b/data/config_files/function_list_post_qc_review.json @@ -26,11 +26,6 @@ "source": "update_ml_warehouse", "target": "archive_to_s3" }, - { - "relation": "dependsOn", - "source": "update_ml_warehouse", - "target": "cache_merge_component" - }, { "relation": "dependsOn", "source": "archive_run_data_to_irods", @@ -56,11 +51,6 @@ "source": "archive_irods_locations_to_ml_warehouse", "target": "run_run_archived" }, - { - "relation": "dependsOn", - "source": "cache_merge_component", - "target": "run_run_archived" - }, { "relation": "dependsOn", "source": "run_run_archived", @@ -204,14 +194,6 @@ "resources": {} } }, - { - "id": "cache_merge_component", - "label": "cache_merge_component", - "metadata": { - "description": "Cached products that are due for a top-up in a directory outside the run folder (if configured)", - "resources": {} - } - }, { "id": "upload_auto_qc_to_qc_database", "label": "upload_auto_qc_to_qc_database", diff --git a/lib/npg_pipeline/base/options.pm b/lib/npg_pipeline/base/options.pm index 5c6e4555..05aa75d8 100644 --- a/lib/npg_pipeline/base/options.pm +++ b/lib/npg_pipeline/base/options.pm @@ -62,20 +62,6 @@ sub _default_to_local { return $self->local; } -=head2 no_cache_merge_component - -Switches off caching of data products suitable for later merging - -=cut - -has q{no_cache_merge_component} => ( - isa => q{Bool}, - is => q{ro}, - lazy => 1, - builder => '_default_to_local', - documentation => q{Switches off caching of data products suitable for later merging.}, -); - =head2 no_s3_archival Switches off archival to s3. diff --git a/lib/npg_pipeline/function/cache_merge_component.pm b/lib/npg_pipeline/function/cache_merge_component.pm deleted file mode 100644 index b26afe6f..00000000 --- a/lib/npg_pipeline/function/cache_merge_component.pm +++ /dev/null @@ -1,197 +0,0 @@ -package npg_pipeline::function::cache_merge_component; - -use namespace::autoclean; - -use File::Basename; -use File::Spec::Functions qw{catdir catfile}; -use Moose; -use MooseX::StrictConstructor; -use Readonly; -use List::Util qw(all); - -extends 'npg_pipeline::base_resource'; - -with qw{npg_pipeline::product::cache_merge}; - -Readonly::Scalar my $LINK_EXECUTABLE => 'ln'; - -our $VERSION = '0'; - -=head2 create - - Arg [1] : None - - Example : my $defs = $obj->create - Description: Create per-product data file function definitions - for caching files eligible as top-up candidates. - - Returntype : ArrayRef[npg_pipeline::function::definition] - -=cut - -sub create { - my ($self) = @_; - - my $id_run = $self->id_run(); - my $job_name = sprintf q{%s_%d}, $LINK_EXECUTABLE, $id_run; - - my @products = $self->no_cache_merge_component ? () : - grep { $self->is_cacheable($_) } - @{$self->products->{data_products}}; - my @definitions = (); - - foreach my $product (@products) { - my $destdir = $self->merge_component_cache_dir($product); - - my @file_paths = $self->expected_files($product); - $self->_check_files(@file_paths); - - my @commands; - foreach my $file_path (@file_paths) { - my $filename = basename($file_path); - - push @commands, sprintf q{%s %s %s}, - $LINK_EXECUTABLE, $file_path, $destdir; - } - - my $command = join q{ && }, qq(mkdir -p $destdir), reverse @commands; - $self->debug("Adding command '$command'"); - - push @definitions, $self->create_definition({ - job_name => $job_name, - command => $command, - composition => $product->composition() - }) - } - - if (not @definitions) { - push @definitions, $self->create_excluded_definition(); - } - - return \@definitions; -} - -sub _check_files { - my ($self, @file_paths) = @_; - - my @missing = grep { not -e } @file_paths; - - if (@missing) { - $self->logcroak('Failed to cache files; the following files ', - 'are missing: ', join q{ }, @missing); - } - - return; -} - -=head2 is_cacheable - - Arg [1] : npg_pipeline::product - - Example : $obj->is_cacheable($product) - Description: Return true if the product should be cached for a later - top-up or merge - cache is configured, seq QC Pass, - lib QC undecided - - Returntype : Bool - -=cut - -sub is_cacheable { - my ($self, $product) = @_; - - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - if ($self->is_release_data($product) and - $self->merge_component_study_cache_dir($product)) { - - my @seqqc = $product->final_seqqc_objs($self->qc_schema); - @seqqc or $self->logcroak("Product $name, $rpt are not all Final seq QC values"); - - if(not all { $_->is_accepted } @seqqc) { - $self->info("Product $name, $rpt are not all Final Accepted seq QC values"); - return 0; - } - - my $libqc_obj = $product->final_libqc_obj($self->qc_schema); - # Lib outcomes are not available for full lane libraries, so the code below - # might give an error when absence of QC outcome is legitimate. - $libqc_obj or $self->logcroak("Product $name, $rpt is not Final lib QC value"); - if (not $libqc_obj->is_undecided) { - $self->info("Product $name, $rpt has Final lib QC value which is not undecided and so is NOT eligible for caching"); - return 0; - } - - return 1; - } - - $self->info("Study for product $name, $rpt is NOT configured for caching"); - return 0; -} - -__PACKAGE__->meta->make_immutable; - -1; - -__END__ - -=head1 NAME - -npg_pipeline::function::cache_merge_component - -=head1 SYNOPSIS - - my $obj = npg_pipeline::function::cache_merge_component->new - (runfolder_path => $runfolder_path); - -=head1 DESCRIPTION - -Caches a data product ready for merging with top-up data. - -Caching is configured per-study using the configuration file -product_release.yml, see npg_pipeline::product::release. - - -=head1 SUBROUTINES/METHODS - -=head1 BUGS AND LIMITATIONS - -=head1 INCOMPATIBILITIES - -=head1 DIAGNOSTICS - -=head1 CONFIGURATION AND ENVIRONMENT - -=head1 DEPENDENCIES - -=over - -=item Moose - -=item MooseX::StrictConstructor - -=item Readonly - -=back - -=head1 AUTHOR - -David K. Jackson - -=head1 LICENSE AND COPYRIGHT - -Copyright (C) 2019 Genome Research Ltd. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . diff --git a/lib/npg_pipeline/pluggable/registry.pm b/lib/npg_pipeline/pluggable/registry.pm index 20760681..8e6afff6 100644 --- a/lib/npg_pipeline/pluggable/registry.pm +++ b/lib/npg_pipeline/pluggable/registry.pm @@ -58,7 +58,6 @@ Readonly::Hash my %REGISTRY => ( 'bam_cluster_counter_check'=> {'cluster_count' => 'create'}, 'seqchksum_comparator' => {'seqchksum_comparator' => 'create'}, 'archive_to_s3' => {'s3_archiver' => 'create'}, - 'cache_merge_component' => {'cache_merge_component' => 'create'}, 'archive_to_irods_samplesheet' => {'seq_to_irods_archiver' => {method => 'create', lims_driver_type =>'samplesheet'}}, diff --git a/t/20-function-cache_merge_component.t b/t/20-function-cache_merge_component.t deleted file mode 100644 index c34e8d78..00000000 --- a/t/20-function-cache_merge_component.t +++ /dev/null @@ -1,267 +0,0 @@ -use strict; -use warnings; - -use File::Temp; -use Log::Log4perl qw[:levels]; -use File::Temp qw[tempdir]; -use Test::More tests => 8; -use Test::Exception; -use File::Copy::Recursive qw[dircopy]; -use t::util; - -my $temp_dir = tempdir(CLEANUP => 1); -Log::Log4perl->easy_init({level => $INFO, - layout => '%d %p %m %n', - file => join(q[/], $temp_dir, 'logfile')}); - -{ - package TestDB; - use Moose; - - with 'npg_testing::db'; -} - -# See README in fixtures for a description of the test data. -my $qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); - -local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . - 'Data/Intensities/BAM_basecalls_20180805-013153/' . - 'metadata_cache_26291/samplesheet_26291.csv'; - -my $pkg = 'npg_pipeline::function::cache_merge_component'; -use_ok($pkg); - -my $runfolder_path = 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX'; -my $copy = join q[/], $temp_dir, '180709_A00538_0010_BH3FCMDRXX'; -dircopy $runfolder_path, $copy or die 'Failed to copy run folder'; -$runfolder_path = $copy; - -my $timestamp = '20180701-123456'; - -my $default = { - default => { - minimum_cpu => 1, - memory => 2 - } -}; - -subtest 'local and no_cache_merge_component' => sub { - plan tests => 7; - - my $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - local => 1, - resource => $default - ); - ok($cacher->no_cache_merge_component, 'no_cache_merge_component flag is set to true'); - my $ds = $cacher->create; - is(scalar @{$ds}, 1, 'one definition is returned'); - isa_ok($ds->[0], 'npg_pipeline::function::definition'); - is($ds->[0]->excluded, 1, 'function is excluded'); - - $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - no_cache_merge_component => 1, - resource => $default - ); - ok(!$cacher->local, 'local flag is false'); - $ds = $cacher->create; - is(scalar @{$ds}, 1, 'one definition is returned'); - is($ds->[0]->excluded, 1, 'function is excluded'); -}; - -subtest 'create' => sub { - plan tests => 4 + (1 + 13) * 4; - - #Tags 7, 8, 1, 11, 2, 5 - preliminary results - - my $cacher; - lives_ok { - $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => $default - ); - } 'cacher created ok'; - - throws_ok {$cacher->create} - qr/Product 26291\#1, 26291:1:1;26291:2:1 is not Final lib QC value/, - 'error since some results are preliminary'; - - my $rs = $qc->resultset('MqcLibraryOutcomeEnt'); - # Make all outcomes final - while (my $row = $rs->next) { - if (!$row->has_final_outcome) { - my $shift = $row->is_undecided ? 1 : 2; - $row->update({id_mqc_outcome => $row->id_mqc_outcome + $shift}); - } - } - - my @defs = @{$cacher->create}; - my $num_defs_observed = scalar @defs; - my $num_defs_expected = 4; - cmp_ok($num_defs_observed, '==', $num_defs_expected, - "create returns $num_defs_expected definitions when caching"); - - my @archived_rpts; - foreach my $def (@defs) { - push @archived_rpts, - [map { [$_->id_run, $_->position, $_->tag_index] } - map {$_->components_list} grep {defined} $def->composition]; - } - - is_deeply(\@archived_rpts, - [ - [[26291, 1, 5], [26291, 2, 5]], - [[26291, 1, 6], [26291, 2, 6]], - [[26291, 1,11], [26291, 2,11]], - [[26291, 1,12], [26291, 2,12]] - ], - 'four undecided final cached') - or diag explain \@archived_rpts; - - my $cmd_patt = qr|^ln $runfolder_path/.*/archive/plex\d+/.* /tmp/npg_seq_pipeline/cache_merge_component_test/\w{2}/\w{2}/\w{64}$|; - - foreach my $def (@defs) { - is($def->created_by, $pkg, "created_by is $pkg"); - is($def->identifier, 26291, "identifier is set correctly"); - - my $cmd = $def->command; - my @parts = split / && /, $cmd; # Deconstruct the command - like(shift @parts, qr|^mkdir -p /tmp/npg_seq_pipeline/cache_merge_component_test/\w{2}/\w{2}/\w{64}$|); - foreach my $part (@parts) { - like($part, $cmd_patt, "$cmd matches $cmd_patt"); - } - } -}; - -subtest 'abort_on_missing_files' => sub { - plan tests => 2; - - my $cacher; - lives_ok { - $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => $default - ); - } 'cacher created ok'; - - my $to_move = "$runfolder_path/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex12/26291#12.cram"; - my $moved = $to_move . '_moved'; - rename $to_move, $moved or die 'failed to move test file'; - - dies_ok { - $cacher->create; - } 'aborts okay'; - - rename $moved, $to_move or die 'failed to move test file'; -}; - -subtest 'abort_on_missing_lib_qc' => sub { - plan tests => 2; - - $qc->resultset(q(MqcLibraryOutcomeEnt))->search({})->first->delete; - my $cacher; - lives_ok { - $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => $default - ); - } 'cacher created ok'; - - dies_ok { - $cacher->create; - } 'aborts okay'; -}; - -subtest 'no_cache_study' => sub { - plan tests => 2; - - my $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_off", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => $default - ); - - my @defs = @{$cacher->create}; - my $num_defs_observed = scalar @defs; - my $num_defs_expected = 1; - cmp_ok($num_defs_observed, '==', $num_defs_expected, - "create returns $num_defs_expected definitions when not archiving") or - diag explain \@defs; - - is($defs[0]->composition, undef, 'definition has no composition') or - diag explain \@defs; -}; - -subtest 'create_with_failed_lane' => sub { - plan tests => 3; - - $qc->resultset(q(MqcOutcomeEnt))->search({id_run=>26291, position=>1})->first->toggle_final_outcome(q(fakeuser)); - my $cacher; - lives_ok { - $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => $default - ); - } 'cacher created ok'; - - my @defs = @{$cacher->create}; - my $num_defs_observed = scalar @defs; - my $num_defs_expected = 1; # single "excluded" - cmp_ok($num_defs_observed, '==', $num_defs_expected, - "create returns $num_defs_expected definitions when caching"); - ok($defs[0] && $defs[0]->excluded, "excluded") -}; - -subtest 'abort_on_missing_seq_qc' => sub { - plan tests => 2; - - $qc->resultset(q(MqcOutcomeEnt))->search({id_run=>26291, position=>1})->first->delete; - my $cacher; - lives_ok { - $cacher = $pkg->new - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => $default - ); - } 'cacher created ok'; - - dies_ok { - $cacher->create; - } 'aborts okay'; -}; - From 609ff8695ab8bbc464e386993143d2270bc85de1 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Thu, 1 Feb 2024 17:23:15 +0000 Subject: [PATCH 05/18] Removed functionality for archival to s3. This was needed for the URB project, is no longer in use. Also removed from npg_pipeline::validation checks for data being uploaded to third party cloud locations. --- MANIFEST | 11 - .../function_list_post_qc_review.json | 18 - lib/npg_pipeline/base/options.pm | 14 - lib/npg_pipeline/function/s3_archiver.pm | 222 ------ lib/npg_pipeline/pluggable/registry.pm | 1 - lib/npg_pipeline/product/cache_merge.pm | 117 ---- lib/npg_pipeline/product/release.pm | 289 +------- lib/npg_pipeline/validation.pm | 37 - lib/npg_pipeline/validation/s3.pm | 384 ---------- t/10-validation-s3.t | 662 ------------------ t/10-validation.t | 14 +- t/15-product-release.t | 434 +----------- t/20-function-s3_archiver.t | 322 --------- .../config/archive_off/product_release.yml | 15 - .../config/archive_on/product_release.yml | 19 - .../config/date_binning/product_release.yml | 23 - .../default_s3_archival/product_release.yml | 19 - .../disregard_qc_outcome/product_release.yml | 32 - .../config/empty_default/product_release.yml | 2 - .../multiple_configs/product_release.yml | 37 - .../config/no_config/product_release.yml | 11 - .../config/notify_off/product_release.yml | 16 - .../config/notify_on/product_release.yml | 17 - .../config/pp_archival/product_release.yml | 8 - .../pp_archival/product_release_no_array.yml | 8 - .../product_release_no_filters.yml | 8 - .../product_release_no_include.yml | 8 - .../config/qc_review/product_release.yml | 6 - .../undef_qc_accept/product_release.yml | 34 - 29 files changed, 11 insertions(+), 2777 deletions(-) delete mode 100644 lib/npg_pipeline/function/s3_archiver.pm delete mode 100644 lib/npg_pipeline/product/cache_merge.pm delete mode 100644 lib/npg_pipeline/validation/s3.pm delete mode 100644 t/10-validation-s3.t delete mode 100644 t/20-function-s3_archiver.t delete mode 100644 t/data/release/config/date_binning/product_release.yml delete mode 100644 t/data/release/config/default_s3_archival/product_release.yml delete mode 100644 t/data/release/config/disregard_qc_outcome/product_release.yml delete mode 100644 t/data/release/config/empty_default/product_release.yml delete mode 100644 t/data/release/config/multiple_configs/product_release.yml delete mode 100644 t/data/release/config/no_config/product_release.yml delete mode 100644 t/data/release/config/undef_qc_accept/product_release.yml diff --git a/MANIFEST b/MANIFEST index 4450e22e..b90f71d1 100644 --- a/MANIFEST +++ b/MANIFEST @@ -49,7 +49,6 @@ lib/npg_pipeline/function/p4_stage1_analysis.pm lib/npg_pipeline/function/stage2pp.pm lib/npg_pipeline/function/pp_data_to_irods_archiver.pm lib/npg_pipeline/function/run_data_to_irods_archiver.pm -lib/npg_pipeline/function/s3_archiver.pm lib/npg_pipeline/function/seq_alignment.pm lib/npg_pipeline/function/seq_to_irods_archiver.pm lib/npg_pipeline/function/seqchksum_comparator.pm @@ -61,7 +60,6 @@ lib/npg_pipeline/pluggable.pm lib/npg_pipeline/pluggable/central.pm lib/npg_pipeline/pluggable/registry.pm lib/npg_pipeline/product.pm -lib/npg_pipeline/product/cache_merge.pm lib/npg_pipeline/product/chunk.pm lib/npg_pipeline/product/release.pm lib/npg_pipeline/product/release/irods.pm @@ -72,7 +70,6 @@ lib/npg_pipeline/validation/autoqc.pm lib/npg_pipeline/validation/common.pm lib/npg_pipeline/validation/entity.pm lib/npg_pipeline/validation/irods.pm -lib/npg_pipeline/validation/s3.pm MANIFEST This list of files README README.md @@ -94,7 +91,6 @@ t/10-script-job_env_to_threads.t t/10-validation-autoqc.t t/10-validation-entity.t t/10-validation-irods.t -t/10-validation-s3.t t/10-validation.t t/15-pipeline_launcher_scripts.t t/15-product-release.t @@ -114,7 +110,6 @@ t/20-function-p4_stage1_analysis.t t/20-function-stage2pp.t t/20-function-pp_data_to_irods_archiver.t t/20-function-run_data_to_irods_archiver.t -t/20-function-s3_archiver.t t/20-function-seq_alignment.t t/20-function-seq_to_irods_archiver.t t/20-function-seqchksum_comparator.t @@ -1081,20 +1076,14 @@ t/data/release/config/archive_off/product_release.yml t/data/release/config/archive_on/product_release.yml t/data/release/config/bqsr_off/product_release.yml t/data/release/config/bqsr_on_study_specific/product_release.yml -t/data/release/config/default_s3_archival/product_release.yml -t/data/release/config/disregard_qc_outcome/product_release.yml -t/data/release/config/empty_default/product_release.yml t/data/release/config/haplotype_caller_bqsr_on_study_specific/product_release.yml t/data/release/config/haplotype_caller_off_study_specific_reference/product_release.yml t/data/release/config/haplotype_caller_on/product_release.yml t/data/release/config/haplotype_caller_on_study_specific/product_release.yml t/data/release/config/haplotype_caller_on_study_specific_reference/product_release.yml -t/data/release/config/multiple_configs/product_release.yml -t/data/release/config/no_config/product_release.yml t/data/release/config/notify_off/product_release.yml t/data/release/config/notify_on/product_release.yml t/data/release/config/qc_review/product_release.yml -t/data/release/config/undef_qc_accept/product_release.yml t/data/release/config/pp_archival/product_release.yml t/data/release/config/pp_archival/product_release_no_array.yml t/data/release/config/pp_archival/product_release_no_filters.yml diff --git a/data/config_files/function_list_post_qc_review.json b/data/config_files/function_list_post_qc_review.json index c95821eb..6bd3e415 100644 --- a/data/config_files/function_list_post_qc_review.json +++ b/data/config_files/function_list_post_qc_review.json @@ -21,11 +21,6 @@ "source": "update_ml_warehouse", "target": "archive_run_data_to_irods" }, - { - "relation": "dependsOn", - "source": "update_ml_warehouse", - "target": "archive_to_s3" - }, { "relation": "dependsOn", "source": "archive_run_data_to_irods", @@ -41,11 +36,6 @@ "source": "archive_pp_data_to_irods", "target": "archive_irods_locations_to_ml_warehouse" }, - { - "relation": "dependsOn", - "source": "archive_to_s3", - "target": "run_run_archived" - }, { "relation": "dependsOn", "source": "archive_irods_locations_to_ml_warehouse", @@ -186,14 +176,6 @@ } } }, - { - "id": "archive_to_s3", - "label": "archive_to_s3", - "metadata": { - "description": "Upload of the main pipeline products to a cloud location (if configured)", - "resources": {} - } - }, { "id": "upload_auto_qc_to_qc_database", "label": "upload_auto_qc_to_qc_database", diff --git a/lib/npg_pipeline/base/options.pm b/lib/npg_pipeline/base/options.pm index 05aa75d8..fe228ef9 100644 --- a/lib/npg_pipeline/base/options.pm +++ b/lib/npg_pipeline/base/options.pm @@ -62,20 +62,6 @@ sub _default_to_local { return $self->local; } -=head2 no_s3_archival - -Switches off archival to s3. - -=cut - -has q{no_s3_archival} => ( - isa => q{Bool}, - is => q{ro}, - lazy => 1, - builder => '_default_to_local', - documentation => q{Switches off archival to s3.}, -); - =head2 no_warehouse_update Switches off updating the NPG warehouse. diff --git a/lib/npg_pipeline/function/s3_archiver.pm b/lib/npg_pipeline/function/s3_archiver.pm deleted file mode 100644 index 70c9a6de..00000000 --- a/lib/npg_pipeline/function/s3_archiver.pm +++ /dev/null @@ -1,222 +0,0 @@ -package npg_pipeline::function::s3_archiver; - -use namespace::autoclean; - -use File::Basename; -use File::Slurp; -use MIME::Base64 qw( encode_base64 ); -use Moose; -use MooseX::StrictConstructor; -use Readonly; - -use npg_qc::Schema; - -extends 'npg_pipeline::base_resource'; - -with qw{npg_pipeline::product::release}; - -# gsutil -Readonly::Scalar my $ARCHIVE_EXECUTABLE => 'gsutil'; -# gsutil - -our $VERSION = '0'; - -has '+qc_schema' => ( - lazy => 1, - builder => '_build_qc_schema', -); -sub _build_qc_schema { - return npg_qc::Schema->connect(); -} - -=head2 create - - Arg [1] : None - - Example : my $defs = $obj->create - Description: Create per-product data file function definitions. - - Returntype : ArrayRef[npg_pipeline::function::definition] - -=cut - -sub create { - my ($self) = @_; - - my $job_name = join q[_], $ARCHIVE_EXECUTABLE, $self->label; - - my @products = $self->no_s3_archival ? () : - grep { $self->is_s3_releasable($_) } - @{$self->products->{data_products}}; - my @definitions = (); - - foreach my $product (@products) { - - # This is required for our initial customer, but we should arrange - # an alternative for when supplier_name is not provided - my $supplier_name = $product->lims->sample_supplier_name(); - $supplier_name or - $self->logcroak(sprintf q{Missing supplier name for product %s, %s}, - $product->file_name_root(), $product->rpt_list()); - - my @file_paths = sort _cram_last $self->expected_files($product); - $self->_check_files(@file_paths); - - # gsutil - my @aws_args = qw{cp}; - - my $base_url = $self->s3_url($product); - $self->info("Using base S3 URL '$base_url'"); - - my $url = $base_url; - if ($self->s3_date_binning($product)) { - my ($date, $time) = split /-/msx, $self->timestamp(); - $url = "$url/$date"; - } - - my $env = q{}; - my $profile = $self->s3_profile($product); - if ($profile) { - $self->info(q{Using S3 client profile 'boto-}, $profile, q{'}); - - ## no critic (ValuesAndExpressions::RequireInterpolationOfMetachars) - $env = 'export BOTO_CONFIG=$HOME/.gcp/boto-' . $profile . q{;}; - ## use critic - } - else { - $self->info('Using the default S3 client profile'); - } - - my @commands; - foreach my $file_path (@file_paths) { - my $filename = basename($file_path); - my $file_url = "$url/$supplier_name/$filename"; - - push @commands, join q{ }, - $ARCHIVE_EXECUTABLE, - $self->_base64_encoded_md5_gsutil_arg($file_path), - @aws_args, $file_path, $file_url; - } - - my $command = join q{ && }, reverse @commands; - if ($env) { - $command = "$env $command"; - } - $self->debug("Adding command '$command'"); - - push @definitions, $self->create_definition({ - job_name => $job_name, - command => $command, - composition => $product->composition() - }); - } - - if (not @definitions) { - push @definitions, $self->create_excluded_definition(); - } - - return \@definitions; -} - -sub _check_files { - my ($self, @file_paths) = @_; - - my @missing; - foreach my $file_path (@file_paths) { - if (not -e $file_path) { - push @missing, $file_path; - } - } - - if (@missing) { - $self->logcroak('Failed to send files to S3; the following files ', - 'are missing: ', join q{ }, @missing); - } - - return; -} - -sub _base64_encoded_md5_gsutil_arg { -# if there is a corresponding .md5 file for the given path, use its contents to -# add an MD5 header for the data being uploaded. - my ($self, $path) = @_; - $path .= q(.md5); - if (not -e $path){ return; } - my ($md5) = read_file($path) =~ m/^(\S{32})(?!\S)/smx; - if (not $md5) { $self->logcroak("Found md5 file for $path without valid md5 value"); } - return q(-h Content-MD5:).(encode_base64((pack q(H*),$md5),q())) -} - -## no critic (ValuesAndExpressions::ProhibitMagicNumbers) -sub _cram_last { - return $a =~ /[.]cram$/msx ? 1 : -1; -} -## use critic - -__PACKAGE__->meta->make_immutable; - -1; - -__END__ - -=head1 NAME - -npg_pipeline::function::s3_archiver - -=head1 SYNOPSIS - - my $obj = npg_pipeline::function::s3_archiver->new - (runfolder_path => $runfolder_path); - -=head1 DESCRIPTION - -Uploads files for a data product to S3. - -Upload is configured per-study using the configuration file -product_release.yml, see npg_pipeline::product::release. - - -=head1 SUBROUTINES/METHODS - -=head1 BUGS AND LIMITATIONS - -=head1 INCOMPATIBILITIES - -=head1 DIAGNOSTICS - -=head1 CONFIGURATION AND ENVIRONMENT - -=head1 DEPENDENCIES - -=over - -=item JSON - -=item Moose - -=item Readonly - -=item npg_qc::Schema - -=back - -=head1 AUTHOR - -Keith James - -=head1 LICENSE AND COPYRIGHT - -Copyright (C) 2018,2019,2020 Genome Research Ltd. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . diff --git a/lib/npg_pipeline/pluggable/registry.pm b/lib/npg_pipeline/pluggable/registry.pm index 8e6afff6..f22ecf99 100644 --- a/lib/npg_pipeline/pluggable/registry.pm +++ b/lib/npg_pipeline/pluggable/registry.pm @@ -57,7 +57,6 @@ Readonly::Hash my %REGISTRY => ( 'bam_cluster_counter_check'=> {'cluster_count' => 'create'}, 'seqchksum_comparator' => {'seqchksum_comparator' => 'create'}, - 'archive_to_s3' => {'s3_archiver' => 'create'}, 'archive_to_irods_samplesheet' => {'seq_to_irods_archiver' => {method => 'create', lims_driver_type =>'samplesheet'}}, diff --git a/lib/npg_pipeline/product/cache_merge.pm b/lib/npg_pipeline/product/cache_merge.pm deleted file mode 100644 index 002ab1a9..00000000 --- a/lib/npg_pipeline/product/cache_merge.pm +++ /dev/null @@ -1,117 +0,0 @@ -package npg_pipeline::product::cache_merge; - -use namespace::autoclean; - -use Data::Dump qw[pp]; -use Moose::Role; -use File::Spec::Functions qw{catdir}; - -with qw{npg_pipeline::product::release}; - -our $VERSION = '0'; - -=head1 NAME - -npg_pipeline::product::cache_merge - -=head1 SYNOPSIS - -=head1 DESCRIPTION - -A role providing locations of directories in which to cache data -products ready for a merge with top-up data. - -=head1 SUBROUTINES/METHODS - -=head2 merge_component_study_cache_dir - - Arg [1] : npg_pipeline::product - - Example : $obj->merge_component_cache_dir($product) - Description: Returns a study-specific directory in which to cache data - products ready for a merge with top-up data or an undefined - value if not configured. The directory might not exist. - - Returntype : Str - -=cut - -sub merge_component_study_cache_dir { - my ($self, $product) = @_; - - my $dir = $self->find_study_config($product)->{merge}->{component_cache_dir}; - if (ref $dir) { - $self->logconfess('Invalid directory in configuration file: ', pp($dir)); - } - - return $dir; -} - -=head2 merge_component_cache_dir - - Arg [1] : npg_pipeline::product - - Example : $obj->merge_component_cache_dir($product) - Description: Returns a product-specific directory in which to cache data - products ready for a merge with top-up data or an undefined - value if not configured. The directory might not exist. - - Returntype : Str - -=cut - -sub merge_component_cache_dir { - my ($self, $product) = @_; - my $study_dir = $self->merge_component_study_cache_dir($product); - my $dir; - if ($study_dir) { - my $digest = $product->composition()->digest(); - $dir = catdir($study_dir, substr($digest,0,2), substr($digest,2,2), $digest); - } - return $dir; -} - -1; - -__END__ - -=head1 BUGS AND LIMITATIONS - -=head1 INCOMPATIBILITIES - -=head1 DIAGNOSTICS - -=head1 CONFIGURATION AND ENVIRONMENT - -=head1 DEPENDENCIES - -=over - -=item Data::Dump - -=item Moose::Role - -=item File::Spec::Functions - -=back - -=head1 AUTHOR - -David K. Jackson - -=head1 LICENSE AND COPYRIGHT - -Copyright (C) 2019 Genome Research Ltd. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . diff --git a/lib/npg_pipeline/product/release.pm b/lib/npg_pipeline/product/release.pm index 72f4f556..56f3f6ce 100644 --- a/lib/npg_pipeline/product/release.pm +++ b/lib/npg_pipeline/product/release.pm @@ -12,12 +12,8 @@ with qw{WTSI::DNAP::Utilities::Loggable our $VERSION = '0'; -Readonly::Scalar our $S3_RELEASE => q{s3}; Readonly::Scalar our $IRODS_RELEASE => q{irods}; Readonly::Scalar our $IRODS_PP_RELEASE => q{irods_pp}; -Readonly::Scalar my $QC_OUTCOME_MATTERS_KEY => q{qc_outcome_matters}; -Readonly::Scalar my $ACCEPT_UNDEF_QC_OUTCOME_KEY => q{accept_undef_qc_outcome}; -Readonly::Scalar my $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY => q{s3}; =head1 SUBROUTINES/METHODS @@ -104,161 +100,6 @@ sub is_release_data { return 1; } -=head2 has_qc_for_release - - Arg [1] : npg_pipeline::product - - Example : $obj->has_qc_for_release($product) - Description: Return true if the product has passed all QC necessary - to be released. - - Returntype : Bool - -=cut - -sub has_qc_for_release { - my ($self, $product) = @_; - - $product or $self->logconfess('A product argument is required'); - - my $qc_db_accessor = 'qc_schema'; - $self->can($qc_db_accessor) or $self->logcroak( - "$qc_db_accessor attribute should be implemented"); - $self->$qc_db_accessor or $self->logcroak( - "$qc_db_accessor connection should be defined"); - - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - my $accept_undef_qc_outcome = - $self->accept_undef_qc_outcome($product,$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY); - - my @seqqc = $product->seqqc_objs($self->$qc_db_accessor); - - if (!@seqqc) {#if seqqc outcome is undef - if ($accept_undef_qc_outcome) { - return 1; - } else { - $self->logcroak('Seq QC is not defined'); - } - } - - #if seqqc is not final - if (any {not $_->has_final_outcome} @seqqc) { - $self->logcroak("Product $name, $rpt are not all Final seq QC values"); - } - - #seqqc is FINAL from this point - #returning early if any seqqc is FINAL REJECTED - if (any {$_->is_rejected} @seqqc) { - return 0; - } - - #seqqc is FINAL ACCEPTED from this point - my $libqc_obj = $product->libqc_obj($self->$qc_db_accessor);# getting regular lib values - #checking if libqc is undef - $libqc_obj or $self->logcroak('lib QC is undefined'); - - if (not $libqc_obj->has_final_outcome ) {# if libqc is not final - $self->logcroak("Product $name, $rpt is not Final lib QC value"); - } - - #libqc is final from this point - #if it's neither rejected nor accepted it's undecided - return $libqc_obj->is_accepted ? 1 - : ($libqc_obj->is_rejected ? 0 - : ($accept_undef_qc_outcome ? 1 : 0)); -} - -=head2 qc_outcome_matters - - Arg [1] : npg_pipeline::product - Arg [2] : Str - - Example : $obj->qc_outcome_matters($product, q[s3]) - Description: Returns a boolean value indicating whether or not QC outcome - matters for the product to be archived by an archiver given - by the second argument. - - Returntype : Bool - -=cut - -sub qc_outcome_matters { - my ($self, $product, $archiver) = @_; - $product or $self->logconfess('A product argument is required'); - $archiver or $self->logconfess('An archiver argument is required'); - return $self->find_study_config($product)->{$archiver}->{$QC_OUTCOME_MATTERS_KEY}; -} - -=head2 accept_undef_qc_outcome - - Arg [1] : npg_pipeline::product - Arg [2] : Str - - Example : $obj->accept_undef_qc_outcome($product, q[s3]) - Description: Returns a boolean value indicating whether or not QC outcome - can be undefined for the product to be archived by an archiver given - by the second argument. - - Returntype : Bool - -=cut - -sub accept_undef_qc_outcome { - my ($self, $product,$archiver) = @_; - $product or $self->logconfess('A product argument is required'); - $archiver or $self->logconfess('An archiver argument is required'); - return $self->find_study_config($product)->{$archiver}->{$ACCEPT_UNDEF_QC_OUTCOME_KEY}; -} - -=head2 customer_name - - Arg [1] : npg_pipeline::product - - Example : $obj->customer_name($product) - Description: Return a name for the customer to whom data are being - released. - - Returntype : Str - -=cut - -sub customer_name { - my ($self, $product) = @_; - - my $customer_name = $self->find_study_config($product) - ->{$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY}->{customer_name}; - $customer_name or - $self->logcroak( - sprintf q{Missing %s archival customer name in configuration file for product %s}, - $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY, $product->composition->freeze()); - - if (ref $customer_name) { - $self->logconfess('Invalid customer name in configuration file: ', - pp($customer_name)); - } - - return $customer_name; -} - -=head2 receipts_location - - Arg [1] : npg_pipeline::product - - Example : $obj->receipts_location($product); - Description: Return location of the receipts for S3 submission, - the value might be undefined. - - Returntype : Str - -=cut - -sub receipts_location { - my ($self, $product) = @_; - return $self->find_study_config($product) - ->{$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY}->{receipts}; -} - =head2 is_for_release Arg [1] : npg_pipeline::product or st::api::lims or similar @@ -276,7 +117,7 @@ sub receipts_location { sub is_for_release { my ($self, $product, $type_of_release) = @_; - my @rtypes = ($IRODS_RELEASE, $IRODS_PP_RELEASE, $S3_RELEASE); + my @rtypes = ($IRODS_RELEASE, $IRODS_PP_RELEASE); $type_of_release or $self->logcroak(q[A defined type_of_release argument is required, ], @@ -295,134 +136,6 @@ sub is_for_release { return; } -=head2 is_for_s3_release - - Arg [1] : npg_pipeline::product - - Example : $obj->is_for_s3_release($product) - Description: Return true if the product is configured for cloud archivel. - Raise an error if no cloud URL has been configured. - - Returntype : Bool - -=cut - -sub is_for_s3_release { - my ($self, $product) = @_; - - $product or $self->logconfess('A product argument is required'); - - my $name = $product->file_name_root(); - my $description = $product->composition->freeze(); - - my $enable = $self->is_for_release($product, $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY); - - if ($enable and not $self->s3_url($product)) { - $self->logconfess("Configuration error for product $name, $description: " , - "$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY release is enabled but no URL was provided"); - } - - $self->info(sprintf 'Product %s, %s is %sfor %s release', - $name, $description, $enable ? q[] : q[NOT ], $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY); - - return $enable; -} - -=head2 s3_url - - Arg [1] : npg_pipeline::product - - Example : $obj->s3_url($product) - Description: Return a cloud URL for release of the product or undef - if there is no URL. - - Returntype : Str - -=cut - -sub s3_url { - my ($self, $product) = @_; - - my $url = $self->find_study_config($product) - ->{$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY}->{url}; - if (ref $url) { - $self->logconfess(sprintf 'Invalid %s URL in configuration file: %', - $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY, pp($url)); - } - - return $url; -} - -=head2 s3_profile - - Arg [1] : npg_pipeline::product - - Example : $obj->s3_profile($product) - Description: Return a cloud profile name for release of the product or - undef if there is no profile. A profile is a named set of - credentials used by some cloud client software. - - Returntype : Str - -=cut - -sub s3_profile { - my ($self, $product) = @_; - - my $profile = $self->find_study_config($product) - ->{$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY}->{profile}; - if (ref $profile) { - $self->logconfess('Invalid %s profile in configuration file: ', - $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY, pp($profile)); - } - - return $profile; -} - -=head2 s3_date_binning - - Arg [1] : npg_pipeline::product - - Example : $obj->s3_date_binning($product) - Description: Return true if a date of processing element is to be added - as the root of the object prefix the S3 bucket. e.g. - - ./2019-01-31/... - - Returntype : Bool - -=cut - -sub s3_date_binning { - my ($self, $product) = @_; - - return $self->find_study_config($product) - ->{$CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY}->{date_binning}; -} - -=head2 is_s3_releasable - - Arg [1] : npg_pipeline::product - - Example : $obj->is_for_s3_release($product) - Description: Return true if the product is to be archived to a cloud - destination. If the QC outcome matters for being releasable, - the product's QC outcome should be compatible with being - released. - - Returntype : Bool - -=cut - -sub is_s3_releasable { - my ($self, $product) = @_; - - return $self->is_release_data($product) && - $self->is_for_s3_release($product) && - ( !$self->qc_outcome_matters($product, $CLOUD_ARCHIVE_PRODUCT_CONFIG_KEY) || - $self->has_qc_for_release($product) ); -} - =head2 haplotype_caller_enable Arg [1] : npg_pipeline::product diff --git a/lib/npg_pipeline/validation.pm b/lib/npg_pipeline/validation.pm index 305cd95a..3296d9f8 100644 --- a/lib/npg_pipeline/validation.pm +++ b/lib/npg_pipeline/validation.pm @@ -17,7 +17,6 @@ use npg_tracking::glossary::composition; use npg_pipeline::cache; use npg_pipeline::validation::entity; use npg_pipeline::validation::irods; -use npg_pipeline::validation::s3; use npg_pipeline::validation::autoqc; use WTSI::NPG::iRODS; use npg_qc::Schema; @@ -193,17 +192,6 @@ has q{remove_staging_tag} => ( q{Toggles an option to remove run's staging tag, false by default}, ); -=head2 no_s3_archival - -Boolean attribute, toggles s3 check, false by default. - -=cut - -has q{+no_s3_archival} => ( - documentation => - q{Toggles an option to check for data in s3, false by default}, -); - ############## Other public attributes ########################### ##### @@ -469,7 +457,6 @@ sub run { $self->_staging_deletable() && $self->_irods_seq_deletable() && $self->_irods_seq_onboard_deletable() && - $self->_s3_deletable() && $self->_autoqc_deletable() && $self->_file_archive_deletable ); @@ -933,30 +920,6 @@ sub _staging_deletable { return $deletable; } -sub _s3_deletable { - my $self = shift; - $self->debug('Examining files reported to be in s3'); - - if ($self->no_s3_archival) { - $self->info('s3 check ignored'); - push @{$self->eligible_product_entities}, @{$self->product_entities}; - return 1; - } - - my $v = npg_pipeline::validation::s3->new( - product_entities => $self->product_entities, - file_extension => $self->file_extension, - qc_schema => $self->qc_schema - ); - my $deletable = $v->fully_archived(); - push @{$self->eligible_product_entities}, @{$v->eligible_product_entities}; - - my $m = sprintf 'Files in s3: run %i %sdeletable', - $self->id_run , $deletable ? q[] : q[NOT ]; - $self->info($m); - return $deletable; -} - sub _file_archive_deletable { my $self = shift; $self->debug('Checking that each product is archived in at least ' . diff --git a/lib/npg_pipeline/validation/s3.pm b/lib/npg_pipeline/validation/s3.pm deleted file mode 100644 index edc57be2..00000000 --- a/lib/npg_pipeline/validation/s3.pm +++ /dev/null @@ -1,384 +0,0 @@ -package npg_pipeline::validation::s3; - -use Moose; -use MooseX::StrictConstructor; -use namespace::autoclean; -use Readonly; -use Perl6::Slurp; -use English qw/ -no_match_vars /; -use List::MoreUtils qw/ any /; -use File::Spec::Functions qw/ catfile /; - -with qw/ npg_pipeline::product::cache_merge - npg_pipeline::validation::common /; - -our $VERSION = '0'; - -Readonly::Scalar my $RECIEPT_FILE_NAME_PATTERN => - qr{/returned_20[[:digit:]]{2} # year - (?:-[[:digit:]]{2}) # -month - (?:-[[:digit:]]{2}) # -date - [.]txt[.]bz2\Z}smx; -Readonly::Scalar my $RECIEPT_ROW_DELIM => qq[\t]; -Readonly::Scalar my $RECIEPT_NUM_COLUMNS => 4; -Readonly::Scalar my $RECIEPT_RECEIVED_FLAG => q[correct]; - -=head1 NAME - -npg_pipeline::validation::s3 - -=head1 SYNOPSIS - - my $v = npg_pipeline::validation::s3->new( - product_entities => $product_entities, - ); - my $deletable = $v->fully_archived(); - my @archived_entities = $v->eligible_product_entities(); - -=head1 DESCRIPTION - -Validation of files present in a pre-configures remote location -against files present on staging. Only files that belong -to products that should have been arcived to this location are -considered. Customer's receipts are used to confirm that data -product files have been received by a customer. If no receipt -is available for a data product, we expect that either the -product has failed QC or, where appropriate, it is a candidate -for topping up. If neither of the latter assumtions is true, the -product is not consided successfully archived. - -The validation is implemented as an evaluation of a number of -conditions, such as received by the customer, passed QC assessment, -failed QC assessment, available in a merged component cache. - -The rules for the QC assessment are set in -C. If the QC assessmen is relevant -for the study, checking it at the point of data deletion ensures -that there has not been a change in the QC status of the product, -which alters the way the product should have been archived. - -=head1 SUBROUTINES/METHODS - -=head2 qc_schema - -Attribute, required, DBIx schema object for the QC database. - -=cut - -has 'qc_schema' => ( - isa => 'npg_qc::Schema', - is => 'ro', - required => 1, -); - -=head2 file_extension - -Attribute, inherited from npg_pipeline::validation::common - -=head2 product_entities - -Inherited from npg_pipeline::validation::common - -=head2 eligible_product_entities - -Inherited from npg_pipeline::validation::common - -=head2 build_eligible_product_entities - -Builder method for the eligible_product_entities attribute. - -=cut - -sub build_eligible_product_entities { - my $self = shift; - @{$self->product_entities} - or $self->logcroak('product_entities array cannot be empty'); - my @p = - grep { $self->is_release_data($_->target_product) && - $self->is_for_s3_release($_->target_product) } - @{$self->product_entities}; - return \@p; -} - -=head2 fully_archived - -Returns true if each of the products eligible for s3 archival is -either archived or satisfies a condition that makes archival of this -product in its current state unnecessary. - -=cut - -sub fully_archived { - my $self = shift; - - my $archived = 1; - # No early return after the $archived flag is flipped to false. - # Looping over all products to give a full report in the log, - # retain the value of teh flag once it was flipped to false. - foreach my $p (map { $_->target_product } - @{$self->eligible_product_entities}) { - - my $received = $self->_received_by_customer($p); - my $passed = $self->_passed_qc_assessment($p); - - ( $received and $passed ) or - ( $self->accept_undef_qc_outcome($p, 's3') - ? (($received or $passed) and ($archived = 0)) - : ($self->_failed_qc_assessment($p) - or $self->_saved4topup($p) - or ($archived = 0)) ); - } - - return $archived; -} - -has '_cached_receipts' => ( - isa => q{HashRef}, - is => q{ro}, - lazy_build => 1, -); -sub _build__cached_receipts { - my $self = shift; - - my $cache = {}; - my $dirs = {}; - foreach my $e (@{$self->eligible_product_entities}) { - - my $p = $e->target_product; - my $dir = $self->receipts_location($p); - (defined $dir) or $self->logcroak( - 'Failed to retrieve receipts location for ' . - $p->composition->freeze()); - next if $dirs->{$dir}; # Already dealt with this directory - - ##### - # Look at all relevant to this product's study receipts. - # - $self->debug("Looking at receipts in $dir"); - $dirs->{$dir} = 1; - my @sample_receipts = (); - opendir my $dh, $dir or $self->logcroak( - "Failed to open receipts directory $dir for reading: $OS_ERROR"); - while (readdir $dh) { # this way of iteration requires Perl 5.012 - my $path = join q[/], $dir, $_; - next if (not -f $path); - push @sample_receipts, @{$self->_read_receipt_file($path)}; - } - closedir $dh; - - ##### - # Cache all records. Not all records are for files from this run. - # Probably none of the records are relevant to this run. - # - foreach my $receipt (@sample_receipts) { - my ($file_name, $h) = $self->_parse_receipt($receipt); - ##### - # We expect one record per file. If there are multiple records, they - # should be identical. - # - if ($cache->{$file_name}) { - my $m = "for $file_name record in one of the receipts in $dir"; - if ($h->{'sample'} ne $cache->{$file_name}->{'sample'}) { - $self->logcroak("Mismatching sample names $m"); - } - if ($h->{'flag'} != $cache->{$file_name}->{'flag'}) { - $self->logcroak("Mismatching flags $m"); - } - $self->logwarn("Duplicate record $m"); - } else { - $cache->{$file_name} = $h; - } - } - } - - return $cache; -} - -sub _read_receipt_file { - my ($self, $path) = @_; - - my @receipts = (); - if ($path =~ /$RECIEPT_FILE_NAME_PATTERN/smx) { - $self->debug("Reading receipt file $path"); - # slurp is no good for capturing errors. If something went - # wrong, the @receipts list will be empty. - @receipts = slurp q[-|], 'bzcat', $path; - if (@receipts) { - my $header = shift @receipts; # remove header row - ($header =~ /\ABucket[ ]key/xms) or - $self->logwarn("Unexpected header $header in $path"); - @receipts or $self->logwarn("Only header in $path"); - } else { - $self->logwarn("Failed to read $path"); - } - } else { - $self->logwarn("Skipped $path - not a receipt?"); - } - - return \@receipts; -} - -sub _parse_receipt { - my ($self, $receipt) = @_; - ##no critic (BuiltinFunctions::ProhibitComplexMappings) - ##no critic (ControlStructures::ProhibitMutatingListFunctions) - my @sample_data = grep { $_ ne q[] } - map { s/\A\s//smxg; $_ } - map { s/\s\Z//smxg; $_ } - split /\t/smx, $receipt; - ##use critic - (@sample_data == $RECIEPT_NUM_COLUMNS) or - (@sample_data == ($RECIEPT_NUM_COLUMNS - 1)) or $self->logcroak( - "Missing columns or data in '$receipt'"); - my ($sample, $file_name) = split /\//smx, $sample_data[0]; - ($sample && $file_name) or $self->logcroak( - "Failed to get sample and file name from '$receipt'"); - - my $flag = (($sample_data[$RECIEPT_NUM_COLUMNS - 1] || q[]) eq - $RECIEPT_RECEIVED_FLAG) ? 1 : 0; - - return ($file_name, {sample => $sample, flag => $flag}); -} - -sub _received_by_customer { - my ($self, $product) = @_; - - my $received = 0; - my $file_name = $product->file_name(ext => $self->file_extension); - my $receipt = $self->_cached_receipts->{$file_name}; - my $desc = $product->composition->freeze(); - - if ($receipt) { - my $sample_name = $product->lims->sample_supplier_name(); - $sample_name or $self->logcroak("Product $desc: missing supplier name"); - ($sample_name eq $receipt->{'sample'}) or - $self->logcroak(sprintf - 'Our supplier sample name %s for file %s product %s ' . - 'differes from acknowledged sample name %s', - $sample_name, $file_name, $desc, $receipt->{'sample'}); - $received = $receipt->{'flag'}; - } else { - $self->logwarn("No receipt for file $file_name, product $desc"); - } - - return $received; -} - -sub _passed_qc_assessment { - my ($self, $product) = @_; - - my $passed = 1; - if ($self->qc_outcome_matters($product, 's3')) { - $passed = $self->has_qc_for_release($product); - $passed or $self->logwarn(sprintf 'Product %s failed QC assessment', - $product->composition->freeze()); - } - - return $passed; -} - -sub _failed_qc_assessment { - my ($self, $product) = @_; - - my $failed = 0; - my $desc = $product->composition->freeze(); - - my @seqqc = $product->final_seqqc_objs($self->qc_schema); - @seqqc or $self->logcroak("Product $desc - not all final seq QC outcomes"); - - $failed = any { $_->is_rejected } @seqqc; - if (!$failed) { - my $libqc_obj = $product->final_libqc_obj($self->qc_schema); - $libqc_obj or $self->logcroak("Product $desc - not final lib QC outcome"); - $failed = $libqc_obj->is_rejected; - } - $self->logwarn(sprintf 'Product %s %s QC', - $desc, $failed ? 'failed' : 'did not fail' ); - - return $failed; -} - -sub _saved4topup { - my ($self, $product) = @_; - - my $saved = 0; - my $desc = $product->composition->freeze(); - - my $cache_dir = $self->merge_component_cache_dir($product); - if ($cache_dir) { - my $file_path = catfile($cache_dir, - $product->file_name(ext => $self->file_extension)); - if (-f $file_path) { - $saved = 1; - } - $self->logwarn(sprintf 'Product %s: cached file %s %sfound', - $desc, $file_path, $saved ? q[] : 'not '); - } else { - $self->logwarn("Product $desc: product cache directory not configured"); - } - - return $saved; -} - -__PACKAGE__->meta->make_immutable; - -1; - -__END__ - -=head1 DIAGNOSTICS - -=head1 CONFIGURATION AND ENVIRONMENT - -=head1 DEPENDENCIES - -=over - -=item Moose - -=item MooseX::StrictConstructor - -=item namespace::autoclean - -=item Readonly - -=item Perl6::Slurp - -=item English - -=item List::MoreUtils - -=item File::Spec::Functions - -=item npg_pipeline::product::cache_merge - -=back - -=head1 INCOMPATIBILITIES - -=head1 BUGS AND LIMITATIONS - -=head1 AUTHOR - -Marina Gourtovaia - -=head1 LICENSE AND COPYRIGHT - -Copyright (C) 2019,2020,2021 Genome Research Ltd. - -This file is part of NPG. - -NPG is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -=cut diff --git a/t/10-validation-s3.t b/t/10-validation-s3.t deleted file mode 100644 index e8e8bf74..00000000 --- a/t/10-validation-s3.t +++ /dev/null @@ -1,662 +0,0 @@ -use strict; -use warnings; -use Test::More tests => 11; -use Test::Exception; -use Test::Warn; -use Test::Trap qw/ :warn/; -use Log::Log4perl qw/ :levels/; -use File::Copy; -use File::Slurp qw/read_file/; -use File::Which; -use File::Path qw/make_path/; -use Moose::Meta::Class; -use YAML qw/LoadFile Dump/; -use IO::Compress::Bzip2; - -use st::api::lims; -use t::util; - -use_ok('npg_pipeline::product'); -use_ok('npg_pipeline::validation::entity'); -use_ok ('npg_pipeline::validation::s3'); - -my $util = t::util->new(); -my $dir = $util->temp_directory(); -Log::Log4perl->easy_init({layout => '%d %-5p %c - %m%n', - level => $WARN, - file => join(q[/], $dir, 'logfile'), - utf8 => 1}); -my $logger = Log::Log4perl->get_logger(q[]); - -my $qc_schema = Moose::Meta::Class->create_anon_class( - roles => [qw/npg_testing::db/])->new_object() - ->create_test_db(q[npg_qc::Schema], 't/data/qc_outcomes/fixtures'); - -my $config_dir = join q[/], $dir, 'config'; -my $pr_file = 't/data/release/config/archive_on/product_release.yml'; -mkdir $config_dir or die "Failed to create $config_dir"; -copy $pr_file, $config_dir; -copy 'data/config_files/general_values.ini', $config_dir; - -my $receipts_dir = join q[/], $dir, 'receipts'; -mkdir $receipts_dir or die "Failed to create $receipts_dir"; -my $cache_dir = join q[/], $dir, 'cache'; -mkdir $cache_dir or die "Failed to create $cache_dir"; - -subtest 'run with no s3 archival' => sub { - plan tests => 2; - - my $pconfig_content = read_file join(q[/], $config_dir, 'product_release.yml'); - my $study_id = 3573; - ok ($pconfig_content !~ /study_id: \"$study_id\"/xms, - 'no product release config for this run study'); - - local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = q{t/data/miseq/samplesheet_16850.csv}; - - my @ets = map { - npg_pipeline::validation::entity->new( - staging_archive_root => q[t], - target_product => npg_pipeline::product->new( - rpt_list => $_, - lims => st::api::lims->new(rpt_list => $_) - ) - ) - } map { qq[16850:1:$_] } (0 .. 2); - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - ok ($v->fully_archived, 'nothing in a run is archivable to s3 - archived'); -}; - -local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - q{t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/} . - q{BAM_basecalls_20180805-013153/metadata_cache_26291/samplesheet_26291.csv}; - -my @ets = map { - npg_pipeline::validation::entity->new( - staging_archive_root => q[t], - target_product => npg_pipeline::product->new( - rpt_list => $_, - lims => st::api::lims->new(rpt_list => $_) - ) - ) -} map { qq[26291:1:$_;26291:2:$_] } (0 .. 12,888); - -subtest 'checking receipts - errors and boundary cases' => sub { - plan tests => 6; - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - throws_ok { $v->fully_archived } - qr/Failed to retrieve receipts location/, - 'error if no receipt location configured'; - - copy 't/data/release/config/default_s3_archival/product_release.yml', - $config_dir; - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - throws_ok { $v->fully_archived } - qr/Failed to open receipts directory \/tmp\/receipts\/does\/not\/exist for reading/, - 'error if receipts location does not exist'; - - my $h = LoadFile($pr_file); - $h->{study}->[0]->{s3}->{receipts} = $receipts_dir; - my $file = join q[/], $config_dir, 'product_release.yml'; - open my $fh, '>', $file or die "Failed to open file $file for writing"; - print $fh (Dump $h) or die "Failed to write to $file"; - close $fh or warn "Failed to close file handle to $file"; - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - lives_ok {$v->_cached_receipts} 'no error with no receipts'; - is (keys %{$v->_cached_receipts}, 0, 'no receipts cached'); - my $received = 1; - my $product = $ets[1]->target_product; - - warning_like {$received = $v->_received_by_customer($product)} - qr/No receipt for file 26291#1.cram/, 'no receipt - warning'; - ok(!$received, 'not received'); -}; - -subtest 'reading receipts' => sub { - plan tests => 17; - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - my @paths = map { "$dir/$_" } - qw/ returned_20-02-04.txt.bz2 - 2019-02-04.txt.bz2 - returned_2019-02-04.txt - returned_2019-02-1.txt.bz2 - returned_2019-02.txt.bz2 /; - for my $p (@paths) { - my $r; - warning_like { $r = $v->_read_receipt_file($p) } - qr/not a receipt/, 'warning about unexpected file name'; - ok (($r and !@{$r}), 'empty array returned'); - } - - my $p = "$dir/returned_2019-02-04.txt.bz2"; - my $r; - warning_like { $r = $v->_read_receipt_file($p) } - qr/Failed to read/, 'failure to read a file warning'; - ok (($r and !@{$r}), 'empty array returned'); - - SKIP: { - skip 'bzcat executable not available', 5 unless which('bzcat'); - - open my $fh, '>', $p or die "Failed to open $p for writing"; - print $fh 'some text' or die "Failed to write to $p"; - close $fh or warn "Failed to close a file handle to $p\n"; - warning_like { $r = $v->_read_receipt_file($p) } - qr/Failed to read/, 'failure to read a file warning'; - ok (($r and !@{$r}), 'empty array returned'); - - my $z = new IO::Compress::Bzip2 $p, AutoClose => 1; - my $header = 'Some Bucket key WSI_MD5 SBG_MD5 Match?'; - $z->print($header); - $z->close(); - warnings_like { $r = $v->_read_receipt_file($p) } - [qr/Unexpected header $header/, qr/Only header/], - 'warning about a mismatched and only header'; - ok (($r and !@{$r}), 'empty array returned'); - - my $content = "Bucket key WSI_MD5 SBG_MD5 Match?\n" . - "First line \n Second line"; - $z = new IO::Compress::Bzip2 $p, AutoClose => 1; - $z->print($content); - $z->close(); - is_deeply ($v->_read_receipt_file($p), - ["First line \n",' Second line'], 'file read correctly'); - } -}; - -subtest 'parsing receipts' => sub { - plan tests => 12; - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - my $r = " sample/file \t4567 4567\t "; - throws_ok {$v->_parse_receipt($r)} - qr/Missing columns or data in '$r'/, 'error parsing receipt'; - $r = " sample/file\t\t4567"; - throws_ok {$v->_parse_receipt($r)} - qr/Missing columns or data in '$r'/, 'error parsing receipt'; - - $r = "27773#9.cram\tf2eb\tf2eb\tcorrect\n"; - throws_ok {$v->_parse_receipt($r)} - qr/Failed to get sample and file name from '$r'/, - 'error parsing receipt'; - - $r = "sample1/27773#9.cram\tf2eb\tf2eb\tcorrect\n"; - my @a = $v->_parse_receipt($r); - ok ((@a and @a==2), 'two-member list returned'); - is ($a[0], '27773#9.cram', 'file name returned'); - is_deeply ($a[1], {sample => 'sample1', flag => 1}, - 'sample and flag returned'); - - $r = "sample1/27773#9.cram\tf2eb\tb2eb\tnot correct"; - @a = $v->_parse_receipt($r); - ok ((@a and @a==2), 'two-member list returned'); - is ($a[0], '27773#9.cram', 'file name returned'); - is_deeply ($a[1], {sample => 'sample1', flag => 0}, - 'sample and flag returned'); - - $r = "sample1/27773#9.cram\tf2eb\tmissing\n"; - @a = $v->_parse_receipt($r); - ok ((@a and @a==2), 'two-member list returned'); - is ($a[0], '27773#9.cram', 'file name returned'); - is_deeply ($a[1], {sample => 'sample1', flag => 0}, - 'sample and flag returned'); -}; - -subtest 'caching receipts' => sub { - plan tests => 5; - - my $content1 = <<'END_CONTENT1'; -Bucket key WSI_MD5 SBG_MD5 Match? -6005537/27998#20.cram b60e062281b1f17da4056c9073884856 b60e062281b1f17da4056c9073884856 correct -6007303/27977#12.cram 36a28b5039e54393fcaad5c24f990838 36a28b5039e54393fcaad5c24f990838 correct -6010298/28029#3.cram a428c5abd61fa7fb0256d2c9fad0e36f a428c5abd61fa7fb0256d2c9fad0e36f correct -6011309/28013#18.cram 43d67e73d228e6ad524800b9a498cb20 43d67e73d228e6ad524800b9a498cb20 correct -6012496/27772#17.cram dba4995012539011b4076a14232a91e0 dba4995012539011b4076a14232a91e0 correct -END_CONTENT1 - - my $p1 = "$receipts_dir/returned_2019-02-04.txt.bz2"; - my $z = new IO::Compress::Bzip2 $p1, AutoClose => 1; - $z->print($content1); - $z->close(); - - my $content2 = <<'END_CONTENT2'; -Bucket key WSI_MD5 SBG_MD5 Match? -xxx/27772#17.cram dba4995012539011b4076a14232a91e0 dba4995012539011b4076a14232a91e0 correct -6013647/28032#8.cram 31d9b2c1a0bad8e556cf92a671d89ccd 31d9b2c1a0bad8e556cf92a671d89ccd correct -6016940/27772#19.cram 8be03f3e8bd2e921b81bae34b6def980 8be03f3e8bd2e921b81bae34b6def980 correct -6020632/28011#24.cram 0c7e9fc4aef271c179b4acf13a8c6a54 0c7e9fc4aef271c179b4acf13a8c6a54 correct -6021330/27826#7.cram bd86af24d6dc3adc1194afdda0e5ca51 bd86af24d6dc3adc1194afdda0e5ca51 correct -6022249/28062#16.cram c91275b3e68e6a1fc5711a1215ac87c6 c91275b3e68e6a1fc5711a1215ac87c6 correct -END_CONTENT2 - - my $p2 = "$receipts_dir/returned_2019-02-05.txt.bz2"; - $z = new IO::Compress::Bzip2 $p2, AutoClose => 1; - $z->print($content2); - $z->close(); - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - throws_ok { $v->_cached_receipts() } - qr/Mismatching sample names for 27772\#17\.cram/, - 'mismatching sample names - error'; - - $content2 = <<'END_CONTENT2'; -Bucket key WSI_MD5 SBG_MD5 Match? -6012496/27772#17.cram dba4995012539011b4076a14232a91e0 dba4995012539011b4076a14232a91e0 not correct -6013647/28032#8.cram 31d9b2c1a0bad8e556cf92a671d89ccd 31d9b2c1a0bad8e556cf92a671d89ccd correct -6016940/27772#19.cram 8be03f3e8bd2e921b81bae34b6def980 8be03f3e8bd2e921b81bae34b6def980 correct -6020632/28011#24.cram 0c7e9fc4aef271c179b4acf13a8c6a54 0c7e9fc4aef271c179b4acf13a8c6a54 correct -6021330/27826#7.cram bd86af24d6dc3adc1194afdda0e5ca51 bd86af24d6dc3adc1194afdda0e5ca51 correct -6022249/28062#16.cram c91275b3e68e6a1fc5711a1215ac87c6 c91275b3e68e6a1fc5711a1215ac87c6 correct -END_CONTENT2 - - $z = new IO::Compress::Bzip2 $p2, AutoClose => 1; - $z->print($content2); - $z->close(); - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - throws_ok { $v->_cached_receipts() } - qr/Mismatching flags for 27772\#17\.cram/, 'mismatching flags - error'; - - $content2 = <<'END_CONTENT2'; -Bucket key WSI_MD5 SBG_MD5 Match? -6012496/27772#17.cram dba4995012539011b4076a14232a91e0 dba4995012539011b4076a14232a91e0 correct -6013647/28032#8.cram 31d9b2c1a0bad8e556cf92a671d89ccd 31d9b2c1a0bad8e556cf92a671d89ccd correct -6016940/27772#19.cram 8be03f3e8bd2e921b81bae34b6def980 8be03f3e8bd2e921b81bae34b6def980 correct -6020632/28011#24.cram 0c7e9fc4aef271c179b4acf13a8c6a54 0c7e9fc4aef271c179b4acf13a8c6a54 correct -6021330/27826#7.cram bd86af24d6dc3adc1194afdda0e5ca51 missing -6022249/28062#16.cram c91275b3e68e6a1fc5711a1215ac87c6 missing -END_CONTENT2 - - $z = new IO::Compress::Bzip2 $p2, AutoClose => 1; - $z->print($content2); - $z->close(); - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - my $expected = { - '27772#17.cram' => {sample => 6012496, flag => 1}, - '27998#20.cram' => {sample => 6005537, flag => 1}, - '27977#12.cram' => {sample => 6007303, flag => 1}, - '28029#3.cram' => {sample => 6010298, flag => 1}, - '28013#18.cram' => {sample => 6011309, flag => 1}, - '28032#8.cram' => {sample => 6013647, flag => 1}, - '27772#19.cram' => {sample => 6016940, flag => 1}, - '28011#24.cram' => {sample => 6020632, flag => 1}, - '27826#7.cram' => {sample => 6021330, flag => 0}, - '28062#16.cram' => {sample => 6022249, flag => 0}, - }; - - my $received; - warning_like { $received = $v->_cached_receipts() } - qr/Duplicate record for 27772\#17\.cram/, 'Duplicate record warning'; - is_deeply ($received, $expected, 'correct cache created'); - - $content2 = <<'END_CONTENT2'; -Bucket key WSI_MD5 SBG_MD5 Match? -6013647/28032#8.cram 31d9b2c1a0bad8e556cf92a671d89ccd 31d9b2c1a0bad8e556cf92a671d89ccd correct -6016940/27772#19.cram 8be03f3e8bd2e921b81bae34b6def980 8be03f3e8bd2e921b81bae34b6def980 correct -6020632/28011#24.cram 0c7e9fc4aef271c179b4acf13a8c6a54 0c7e9fc4aef271c179b4acf13a8c6a54 correct -6021330/27826#7.cram bd86af24d6dc3adc1194afdda0e5ca51 bd86af24d6dc3adc1194afdda0e5ca51 not correct -6022249/28062#16.cram c91275b3e68e6a1fc5711a1215ac87c6 c91275b3e68e6a1fc5711a1215ac87c6 not correct -END_CONTENT2 - - $z = new IO::Compress::Bzip2 $p2, AutoClose => 1; - $z->print($content2); - $z->close(); - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - $received = $v->_cached_receipts(); - is_deeply ($received, $expected, 'correct cache created'); -}; - -subtest 'checking receipts' => sub { - plan tests => 2; - - my $content = <<'END_CONTENT'; -Bucket key WSI_MD5 SBG_MD5 Match? -HG00614_1_9uM/26291#1.cram 31d9b2c1a0bad8e556cf92a671d89ccd 31d9b2c1a0bad8e556cf92a671d89ccd correct -HG00683_1_25uM/26291#2.cram 8be03f3e8bd2e921b81bae34b6def980 missing -END_CONTENT - - my $p = "$receipts_dir/returned_2019-03-05.txt.bz2"; - my $z = new IO::Compress::Bzip2 $p, AutoClose => 1; - $z->print($content); - $z->close(); - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - my $product = $ets[1]->target_product; - ok ($v->_received_by_customer($product), '26291#1.cram received'); - $product = $ets[2]->target_product; - ok (!$v->_received_by_customer($product), '26291#2.cram not received'); - - unlink $p; -}; - -subtest 'product failed mqc' => sub { - plan tests => 9; - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - my @ps = (); - my $p = $ets[10]->target_product; # plex 10, Rejected final - push @ps, $p; - my $failed; - warning_like { $failed = $v->_failed_qc_assessment($p) } qr/failed QC/, - 'warning about failing qc'; - ok ($failed, 'failed mqc with lib qc "Rejected final"'); - - $p = $ets[9]->target_product; # plex 9, Rejected final - push @ps, $p; - warning_like { $failed = $v->_failed_qc_assessment($p) } qr/did not fail QC/, - 'warning about not failing qc'; - ok (!$failed, 'did not fail mqc with lib qc "Accepted final"'); - - $p = $ets[6]->target_product; # plex 6, Undecided final - push @ps, $p; - warning_like { $failed = $v->_failed_qc_assessment($p) } qr/did not fail QC/, - 'warning about not failing qc'; - ok (!$failed, 'did not fail mqc with lib qc "Undecided final"'); - - $p = $ets[2]->target_product; # plex 2, Rejected preliminary - push @ps, $p; - throws_ok { $v->_failed_qc_assessment($p) } qr/not final lib QC outcome/, - 'not final library qc outcome - error'; - - my $lane2 = $qc_schema->resultset('MqcOutcomeEnt')->search({id_run => 26291, position => 2}); - $lane2->update({id_mqc_outcome => 4}); # Rejected final - ok ((4 == scalar grep { $_ } map { trap { $v->_failed_qc_assessment($_) } } @ps), - 'all products now considered as failed mqc'); - $lane2->update({id_mqc_outcome => 2}); # Rejected preliminary - throws_ok { $v->_failed_qc_assessment($ps[0]) } qr/not all final seq QC outcomes/, - 'not all lanes have final seq outcome - error'; -}; - -subtest 's3 fully archived' => sub { - plan tests => 22; - - SKIP: { - skip 'bzcat executable not available', 12 unless which('bzcat'); - my $content = <<'END_CONTENT'; -Bucket key WSI_MD5 SBG_MD5 Match? -HG00614_1_9uM/26291#1.cram 31d9b2c1a0bad8e556cf92a671d89ccd 31d9b2c1a0bad8e556cf92a671d89ccd correct -HG00683_1_25uM/26291#2.cram 8be03f3e8bd2e921b81bae34b6def980 8be03f3e8bd2e921b81bae34b6def980 correct -NA19240_F12_25uM/26291#3.cram 3704e9447532487fcb00e61fe52378e2 3704e9447532487fcb00e61fe52378e2 correct -NA12892_E4_25uM/26291#4.cram 242a93ef2f8d1fc6856e79935e0061cd 242a93ef2f8d1fc6856e79935e0061cd correct -NA12878_N7_25uM/26291#5.cram b1b23810910e74fef8e79109a1c9acb5 b1b23810910e74fef8e79109a1c9acb5 correct -NA19238_E2_25uM/26291#6.cram 3a639e356dace78bd8f9e2dc4283d076 3a639e356dace78bd8f9e2dc4283d076 correct -NA12891_F1_25uM/26291#7.cram d17535538147e3ad8b149f1726f497d7 d17535538147e3ad8b149f1726f497d7 correct -NA19239_C1_25uM/26291#8.cram 1d5189f7f0f9a762bd8c71d7307c7669 1d5189f7f0f9a762bd8c71d7307c7669 correct -HG00614_1_25uM/26291#9.cram 57f40585da201b0b40ebb0dee457abc6 57f40585da201b0b40ebb0dee457abc6 correct -NA19240_F12_25uM/26291#11.cram 81747881edfc68f85e64ab6b20b776d4 81747881edfc68f85e64ab6b20b776d4 correct -NA12892_E4_25uM/26291#12.cram c78cd8149ba10969e8572bf6e3d2dc20 c78cd8149ba10969e8572bf6e3d2dc20 correct -HG00683_1_25uM/26291#10.cram 867cc0e4631e56f0d142bac64adffc5f 867cc0e4631e56f0d142bac64adffc5f correct -END_CONTENT - - my $path = "$receipts_dir/returned_2019-03-05.txt.bz2"; - my $z = new IO::Compress::Bzip2 $path, AutoClose => 1; - $z->print($content); - $z->close(); - - $qc_schema->resultset('MqcOutcomeEnt')->search({id_run => 26291}) - ->update({id_mqc_outcome => 3}); # make all lanes Accepted final - - my $temp = "$config_dir/temp_product_release.yml"; - my $cfile = "$config_dir/product_release.yml"; - move $cfile, $temp; - my $ch = LoadFile($temp); - delete $ch->{study}->[0]->{s3}->{qc_outcome_matters}; - open my $fhc, '>', $cfile or die "Failed to open file $cfile for writing"; - print $fhc (Dump $ch) or die "Failed to write to $cfile"; - close $fhc or warn "Failed to close file handle to $cfile"; - - my $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - ok ($v->fully_archived(), 'qc outcome disregarded, fully archived'); - - move $temp, $cfile; - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - my $hp = LoadFile('t/data/release/config/undef_qc_accept/product_release.yml'); - $hp->{study}->[0]->{s3}->{receipts} = $receipts_dir; - my $pfile = join q[/], $config_dir, 'product_release_undef_qc_accept.yml'; - open my $fhp, '>', $pfile or die "Failed to open file $pfile for writing"; - print $fhp (Dump $hp) or die "Failed to write to $pfile"; - close $fhp or warn "Failed to close file handle to $pfile"; - - my $v2 = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - product_conf_file_path => $pfile, - qc_schema => $qc_schema - ); - - is (@{$v->product_entities} - @{$v->eligible_product_entities}, 2, - 'eligible product entities contain fewer objects'); - throws_ok { $v->fully_archived() } qr/not Final lib QC value/, - 'all qc outcomes should be final'; - - my @compositions = map {$_->target_product->composition} - @{$v->eligible_product_entities}; - $qc_schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition(\@compositions) - ->update({id_mqc_outcome => 3}); # make all libs Accepted final - ok($v->fully_archived(), 'archived - all products acknowledged'); - ok($v2->fully_archived(), 'archived'); - - $qc_schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition([$compositions[0]]) - ->update({id_mqc_outcome => 6}); # make one lib Undecided final - my $archived; - warnings_like { $archived = $v->fully_archived() } - [qr/failed QC assessment/, qr/did not fail QC/, qr/not found/], - 'warning about qc not passed'; - ok(!$archived, - 'no archived - all received, one undecided, not in the cache'); - ok($v2->fully_archived(), 'archived'); - - $qc_schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition([$compositions[0]]) - ->update({id_mqc_outcome => 3}); # make it back Accepted final - - my @lines = split "\n", $content; - pop @lines; # remove record for tag 10; - $z = new IO::Compress::Bzip2 $path, AutoClose => 1; - $z->print(join qq[\n], @lines); - $z->close(); - - my $file = join q[/], $config_dir, 'product_release.yml'; - my $h = LoadFile($file); - delete $h->{study}->[0]->{merge}->{component_cache_dir}; - open my $fh, '>', $file or die "Failed to open file $file for writing"; - print $fh (Dump $h) or die "Failed to write to $file"; - close $fh or warn "Failed to close file handle to $file"; - - $qc_schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition([$compositions[9]]) - ->update({id_mqc_outcome => 4}); # make tag 10 Rejected final - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - - $v2 = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - product_conf_file_path => $pfile, - qc_schema => $qc_schema - ); - - warnings_like { $archived = $v->fully_archived() } - [ qr/No receipt for file 26291\#10\.cram/, - qr/failed QC assessment/, - qr/failed QC/ ], - 'warning about no receipt and failed qc'; - ok($archived, 'archived - one failed mqc, others are acknowledged'); - - warnings_like { $archived = $v2->fully_archived() } - [ qr/No receipt for file 26291\#10\.cram/, - qr/failed QC assessment/ ], - 'warning about no receipt'; - ok($archived, 'archived - one failed mqc, others are acknowledged'); - - my $p = $ets[10]->target_product; # plex 10, Rejected final - # update lib outcome to final undecided - $qc_schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition([$p->composition])->update({id_mqc_outcome => 6}); - - ok (!$v->merge_component_cache_dir($p), 'merge_component_cache_dir is not set'); - warnings_like { $archived = $v->fully_archived() } - [ qr/No receipt for file 26291\#10\.cram/, - qr/failed QC assessment/, - qr/did not fail QC/, - qr/product cache directory not configured/ ], - 'warnings about no receipt, not failing qc, no product cache dir'; - ok (!$archived, - 'not archived - is not acknowledged, undecided, no top-up dir configured'); - - warnings_like { $archived = $v2->fully_archived() } - [ qr/No receipt for file 26291\#10\.cram/ ], - 'warnings about no receipt, not failin qc, no product cache dir'; - ok (!$archived, 'not archived - is not acknowledged, undecided'); - - $file = join q[/], $config_dir, 'product_release.yml'; - $h = LoadFile($file); - $h->{study}->[0]->{merge}->{component_cache_dir} = $cache_dir; - open $fh, '>', $file or die "Failed to open file $file for writing"; - print $fh (Dump $h) or die "Failed to write to $file"; - close $fh or warn "Failed to close file handle to $file"; - - $v = npg_pipeline::validation::s3->new( - product_entities => \@ets, - logger => $logger, - file_extension => 'cram', - conf_path => $config_dir, - qc_schema => $qc_schema - ); - my $product_cache = $v->merge_component_cache_dir($p); - make_path $product_cache or die "failed to create drectory $product_cache"; - ok ($product_cache, 'merge_component_cache_dir is set'); - - $file = join q[/], $product_cache, '26292#10.cram'; - open my $fh1, '>', $file or die "Failed to open file $file for writing"; - print $fh1 'test cram file' or die "Failed to write to $file"; - close $fh1 or warn "Failed to close file handle to $file"; - warnings_like { $archived = $v->fully_archived() } - [ qr/No receipt for file 26291\#10\.cram/, - qr/failed QC assessment/, - qr/did not fail QC/, - qr/cached file $product_cache\/26291\#10\.cram not found/ ], - 'warnings about no receipt, not failing qc, not found in cache dir'; - ok (!$archived, 'not archived - is not acknowledged, undecided, not in top-up'); - - $file = join q[/], $product_cache, '26291#10.cram'; - open my $fh2, '>', $file or die "Failed to open file $file for writing"; - print $fh2 'test cram file' or die "Failed to write to $file"; - close $fh2 or warn "Failed to close file handle to $file"; - - warnings_like { $archived = $v->fully_archived() } - [ qr/No receipt for file 26291\#10\.cram/, - qr/failed QC assessment/, - qr/did not fail QC/, - qr/cached file $product_cache\/26291\#10\.cram found/ ], - 'warnings about no receipt, not failing qc, found in cache dir'; - ok ($archived, 'archived - found in top-up cache'); - } -}; - -1; diff --git a/t/10-validation.t b/t/10-validation.t index 09ca512e..bbc6b044 100644 --- a/t/10-validation.t +++ b/t/10-validation.t @@ -77,7 +77,7 @@ sub _populate_test_runfolder { } subtest 'create object' => sub { - plan tests => 17; + plan tests => 16; my $v = npg_pipeline::validation->new( qc_schema => $qc_schema, @@ -87,8 +87,7 @@ subtest 'create object' => sub { isa_ok ($v, 'npg_pipeline::validation'); for my $flag (qw/ignore_lims ignore_npg_status ignore_time_limit - ignore_autoqc ignore_irods remove_staging_tag - no_s3_archival/) { + ignore_autoqc ignore_irods remove_staging_tag/) { ok (!$v->$flag, "$flag is false by default"); } ok ($v->use_cram, 'cram files are used by default'); @@ -234,7 +233,7 @@ subtest 'lims and staging deletable' => sub { }; subtest 'xarchive validation' => sub { - plan tests => 9; + plan tests => 8; local $ENV{'NPG_CACHED_SAMPLESHEET_FILE'} = 't/data/samplesheet_8747.csv'; @@ -257,12 +256,11 @@ subtest 'xarchive validation' => sub { 'warnings about data absent from archive'); ok (!$deletable, 'not deletable prior to running validation for file archives'); - $v = npg_pipeline::validation->new(%{$ref}, no_s3_archival => 1, ignore_irods => 1); - ok ($v->_s3_deletable(), 'no s3 archival - s3 deletable'); + $v = npg_pipeline::validation->new(%{$ref}, ignore_irods => 1); ok ($v->_irods_seq_deletable(), 'no irods archival - irods deletable'); my $num_products = scalar @{$v->product_entities}; - ok (scalar @{$v->eligible_product_entities} == (2 * $num_products), - 'double number pf products in eligible products'); + ok (scalar @{$v->eligible_product_entities} == $num_products, + 'number pf products in eligible products'); is ($v->_file_archive_deletable(), 1, 'is deletable'); while (scalar @{$v->eligible_product_entities} > ($num_products - 1)) { diff --git a/t/15-product-release.t b/t/15-product-release.t index c0374aa5..cf3901e1 100644 --- a/t/15-product-release.t +++ b/t/15-product-release.t @@ -7,7 +7,7 @@ use File::Path qw[make_path]; use File::Temp; use Log::Log4perl qw[:levels]; use File::Temp qw[tempdir]; -use Test::More tests => 18; +use Test::More tests => 2; use Test::Exception; use Moose::Meta::Class; use t::util; @@ -25,10 +25,9 @@ Log::Log4perl->easy_init({level => $INFO, } # See README in fixtures for a description of the test data. -my $qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); +my $qc = TestDB->new ( + sqlite_utf8_enabled => 1, + verbose => 0)->create_test_db('npg_qc::Schema'); local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . @@ -106,428 +105,3 @@ subtest 'expected_unaligned_files' => sub { diag explain \@observed; }; -subtest '1:1 is_s3_releasable when accept_undef_qc_outcome: undef and seqqc is undef' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->delete;#seqqc is undef - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>3});#libqc is final accepted - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - throws_ok{$archiver->has_qc_for_release($product)} qr/Seq QC is not defined/, 'throws error when accept_undef_qc_outcome is false and seq_qc is undefined for has_qc_for_release'; - throws_ok{$archiver->is_s3_releasable($product)} qr/Seq QC is not defined/, 'throws error when accept_undef_qc_outcome is false and seq_qc is undefined for is_s3_releasable'; - -}; - -#resetting fixture after deletion -$qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); - -subtest '1:2 is_s3_releasable when accept_undef_qc_outcome: undef and seq_qc not final' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>1});#seqqc not final - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>3});#libqc is final accepted - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - throws_ok{$archiver->has_qc_for_release($product)} qr/Product $name, $rpt are not all Final seq QC values/, 'throws error when accept_undef_qc_outcome is false and seq_qc is not final for has_qc_for_release'; - throws_ok{$archiver->is_s3_releasable($product)} qr/Product $name, $rpt are not all Final seq QC values/, 'throws error when accept_undef_qc_outcome is false and seq_qc is not final for is_s3_releasable'; -}; - -subtest '1:3 is_s3_releasable when accept_undef_qc_outcome: undef, seq_qc outcome: final rejected' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>4});#seqqc is final rejected - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>4});#libqc is final rejected - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - is($archiver->has_qc_for_release($product),0,'has_qc_for_release returns 0 when seq_qc outcome is final rejected'); - is($archiver->is_s3_releasable($product),0,'is_s3_releasable returns 0 when qc_outcome_matters is set to true and seq_qc is final rejected'); -}; - -subtest '1:4 has_qc_for_release when accept_undef_qc_outcome: undef, seq_qc outcome: final accepted, lib_qc outcome: undef' => sub { - plan tests => 3; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->delete;#libqc is undef - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - throws_ok{$archiver->has_qc_for_release($product)} qr/lib QC is undefined/, 'throws error when accept_undef_qc_outcome is false and seq_qc is final accepted and lib_qc is undef for has_qc_for_release'; -}; - -#resetting fixture after deletion -$qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); - -subtest '1:5 is_s3_releasable when accept_undef_qc_outcome: undef, seq_qc outcome: final accepted, lib_qc outcome: not final' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>1});#libqc is not final - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - throws_ok{$archiver->has_qc_for_release($product)} qr/Product $name, $rpt is not Final lib QC value/, 'throws error when accept_undef_qc_outcome is false and seq_qc is final accepted and lib_qc is not final for has_qc_for_release'; - throws_ok{$archiver->is_s3_releasable($product)} qr/Product $name, $rpt is not Final lib QC value/, 'throws error when accept_undef_qc_outcome is false and seq_qc is final accepted and lib_qc is not final for is_s3_releasable'; -}; - -subtest '1:6 is_s3_releasable when accept_undef_qc_outcome: undef, seq_qc outcome: final accepted, lib_qc outcome: final undecided' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>6});#libqc is final undecided - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - is($archiver->has_qc_for_release($product),0,'has_qc_for_release returns 0 when seq_qc is final accepted and lib_qc is final undecided'); - is($archiver->is_s3_releasable($product),0,'is_s3_releasable returns 0 when seq_qc is final accepted and lib_qc is final undecided'); -}; - -subtest '1:7 is_s3_releasable when accept_undef_qc_outcome: undef, seq_qc outcome: final accepted, lib_qc outcome: final rejected' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>4});#libqqc is final rejected - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - is($archiver->has_qc_for_release($product),0,'has_qc_for_release returns 0 when seq_qc is final accepted and lib_qc is final rejected'); - is($archiver->is_s3_releasable($product),0,'is_s3_releasable returns 0 when seq_qc is final accepted and lib_qc is final rejected'); -}; - -subtest '1:8 is_s3_releasable when accept_undef_qc_outcome: undef, seq_qc outcome: final accepted, lib_qc outcome: final accepted' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>3});#libqc is final accepted - - local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . - 'Data/Intensities/BAM_basecalls_20180805-013153/' . - 'metadata_cache_26291/samplesheet_no_align_26291.csv'; - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/archive_on", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),undef,'accept_undef_qc_outcome is set to false'); - is($archiver->has_qc_for_release($product),1,'has_qc_for_release returns 1 when seq_qc is final accepted and lib_qc is final accepted'); - is($archiver->is_s3_releasable($product),1,'is_s3_releasable returns 1 when seq_qc is final accepted and lib_qc is final accepted'); -}; - -#accept_undef_qc_outcome is TRUE - -subtest '2:1 is_s3_releasable when accept_undef_qc_outcome: true and seq_qc is undefined' => sub { - plan tests => 4; - ## setting up schema with values - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->delete;# seqqc is undef - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>3});#libqc is final accepted - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - is($archiver->has_qc_for_release($product),1,'returns 1 when accept_undef_qc_outcome is true and seq_qc is undefind for has_qc_for_release'); - is($archiver->is_s3_releasable($product),1,'returns 1 when accept_undef_qc_outcome is true and seq_qc is undefined for is_s3_releasable'); -}; - -#resetting fixture after deletion -$qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); -subtest '2:2 is_s3_releasable when accept_undef_qc_outcome: true and seq_qc not final' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>1});#seq_qc not final - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>3});#libqc is final accepted - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - throws_ok{$archiver->has_qc_for_release($product)} qr/Product $name, $rpt are not all Final seq QC values/, 'throws error when accept_undef_qc_outcome is true and seq_qc is not final for has_qc_for_release'; - throws_ok{$archiver->is_s3_releasable($product)} qr/Product $name, $rpt are not all Final seq QC values/, 'throws error when accept_undef_qc_outcome is true and seq_qc is not final for is_s3_releasable'; -}; - -subtest '2:3 is_s3_releasable when accept_undef_qc_outcome: true, seq_qc outcome: final rejected' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>4});#seqqc is final rejected - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>4});#libqc is final rejected - - local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . - 'Data/Intensities/BAM_basecalls_20180805-013153/' . - 'metadata_cache_26291/samplesheet_no_align_26291.csv'; - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - is($archiver->has_qc_for_release($product),0,'has_qc_for_release returns 0 when seq_qc outcome is final rejected'); - is($archiver->is_s3_releasable($product),0,'is_s3_releasable returns 0 when qc_outcome_matters is set to true and seq_qc is final rejected'); -}; - -subtest '2:4 has_qc_for_release when accept_undef_qc_outcome: true, seq_qc outcome: final accepted, lib_qc outcome: undef' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->delete;#libqc is undef - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - throws_ok{$archiver->has_qc_for_release($product)} qr/lib QC is undefined/, 'throws error when accept_undef_qc_outcome is true and seq_qc is final accepted and lib_qc is undef for has_qc_for_release'; -throws_ok{$archiver->is_s3_releasable($product)} qr/lib QC is undefined/, 'throws error when accept_undef_qc_outcome is true and seq_qc is final accepted and lib_qc is undef for has_qc_for_release'; -}; - -#resetting fixture after deletion -$qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); - -subtest '2:5 is_s3_releasable when accept_undef_qc_outcome: true, seq_qc outcome: final accepted, lib_qc outcome: not final' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>1});#libqc is not final - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - throws_ok{$archiver->has_qc_for_release($product)} qr/Product $name, $rpt is not Final lib QC value/, 'throws error when accept_undef_qc_outcome is true and seq_qc is final accepted and lib_qc is not final for has_qc_for_release'; - throws_ok{$archiver->is_s3_releasable($product)} qr/Product $name, $rpt is not Final lib QC value/, 'throws error when accept_undef_qc_outcome is true and seq_qc is final accepted and lib_qc is not final for is_s3_releasable'; -}; - -# should return 1 -subtest '2:6 is_s3_releasable when accept_undef_qc_outcome: true, seq_qc outcome: final accepted, lib_qc outcome: final undecided' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>6});#libqc is final undecided - - local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . - 'Data/Intensities/BAM_basecalls_20180805-013153/' . - 'metadata_cache_26291/samplesheet_no_align_26291.csv'; - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - is($archiver->has_qc_for_release($product),1,'has_qc_for_release returns 1 when seq_qc is final accepted and lib_qc is final undecided'); - is($archiver->is_s3_releasable($product),1,'is_s3_releasable returns 1 when seq_qc is final accepted and lib_qc is final undecided'); -}; - -subtest '2:7 is_s3_releasable when accept_undef_qc_outcome: true, seq_qc outcome: final accepted, lib_qc outcome: final rejected' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>4});#libqc is final rejected - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - is($archiver->has_qc_for_release($product),0,'has_qc_for_release returns 0 when seq_qc is final accepted and lib_qc is final rejected'); - is($archiver->is_s3_releasable($product),0,'is_s3_releasable returns 0 when seq_qc is final accepted and lib_qc is final rejected'); -}; - -subtest '2:8 is_s3_releasable when accept_undef_qc_outcome: true, seq_qc outcome: final accepted, lib_qc outcome: final accepted' => sub { - plan tests => 4; - my $lane_qc_rs = $qc->resultset('MqcOutcomeEnt'); - $lane_qc_rs->update({id_mqc_outcome=>3});#seqqc is final accepted - my $libqc_rs = $qc->resultset('MqcLibraryOutcomeEnt'); - $libqc_rs->update({id_mqc_outcome=>3});#libqc is final accepted - - my $archiver = $cls->new_object - (conf_path => "t/data/release/config/undef_qc_accept", - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); - - my $product = shift @{$archiver->products->{data_products}}; - my $rpt = $product->rpt_list(); - my $name = $product->file_name_root(); - - is($archiver->qc_outcome_matters($product,'s3'),1,'qc_outcome_matters is set to true'); - is($archiver->accept_undef_qc_outcome($product,'s3'),1,'accept_undef_qc_outcome is set to true'); - is($archiver->has_qc_for_release($product),1,'has_qc_for_release returns 1 when seq_qc is final accepted and lib_qc is final accepted'); - is($archiver->is_s3_releasable($product),1,'is_s3_releasable returns 1 when seq_qc is final accepted and lib_qc is final accepted'); -}; diff --git a/t/20-function-s3_archiver.t b/t/20-function-s3_archiver.t deleted file mode 100644 index 3f1d7ac1..00000000 --- a/t/20-function-s3_archiver.t +++ /dev/null @@ -1,322 +0,0 @@ -use strict; -use warnings; - -use Digest::MD5; -use File::Copy; -use File::Path qw[make_path remove_tree]; -use File::Temp; -use File::Basename; -use Cwd; -use Log::Log4perl qw[:levels]; -use File::Temp qw[tempdir]; -use Test::More tests => 9; -use Test::Exception; -use t::util; - -my $temp_dir = tempdir(CLEANUP => 1); -Log::Log4perl->easy_init({level => $INFO, - layout => '%d %p %m %n', - file => join(q[/], $temp_dir, 'logfile')}); - -{ - package TestDB; - use Moose; - - with 'npg_testing::db'; -} - -# See README in fixtures for a description of the test data. -my $qc = TestDB->new - (sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema', - 't/data/qc_outcomes/fixtures'); - -local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . - 'Data/Intensities/BAM_basecalls_20180805-013153/' . - 'metadata_cache_26291/samplesheet_26291.csv'; - -my $pkg = 'npg_pipeline::function::s3_archiver'; -use_ok($pkg); - -my $runfolder_path = 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX'; -my $timestamp = '20180701-123456'; - -my %init = ( - runfolder_path => $runfolder_path, - id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc, - resource => { - default => { - minimum_cpu => 1, - memory => 2 - } - } -); - -subtest 'local and no_s3_archival flag' => sub { - plan tests => 7; - - my $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/archive_on", - local => 1 - ); - ok($archiver->no_s3_archival, 'no_s3_archival flag is set to true'); - my $ds = $archiver->create; - is(scalar @{$ds}, 1, 'one definition is returned'); - isa_ok($ds->[0], 'npg_pipeline::function::definition'); - is($ds->[0]->excluded, 1, 'function is excluded'); - - $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/archive_on", - no_s3_archival => 1 - ); - ok(!$archiver->local, 'local flag is false'); - $ds = $archiver->create; - is(scalar @{$ds}, 1, 'one definition is returned'); - is($ds->[0]->excluded, 1, 'function is excluded'); -}; - -subtest 'create for a run' => sub { - plan tests => 32; - - my $archiver; - lives_ok { - $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/archive_on", - ); - } 'archiver created ok'; - - dies_ok {$archiver->create} 'preliminary results present - error'; - - my $rs = $qc->resultset('MqcLibraryOutcomeEnt'); - # Make all outcomes either a rejected or undecided final result - while (my $row = $rs->next) { - if (!$row->has_final_outcome) { - my $shift = $row->is_undecided ? 1 : ($row->is_accepted ? 3 : 2); - $row->update({id_mqc_outcome => $row->id_mqc_outcome + $shift}); - } - } - - my @defs = @{$archiver->create}; - my $num_defs_observed = scalar @defs; - my $num_defs_expected = 2; # Only 2 pass manual QC, tag index 3 and 9 - cmp_ok($num_defs_observed, '==', $num_defs_expected, - "create returns $num_defs_expected definitions when archiving"); - - my @archived_rpts; - foreach my $def (@defs) { - push @archived_rpts, - [map { [$_->id_run, $_->position, $_->tag_index] } - $def->composition->components_list]; - } - - is_deeply(\@archived_rpts, - [[[26291, 1, 3], [26291, 2, 3]], - [[26291, 1, 9], [26291, 2, 9]]], - 'Only "26291:1:3;26291:2:3" and "26291:1:9;26291:2:9" archived') - or diag explain \@archived_rpts; - - my $cmd_patt = qr|^gsutil(?: -h Content-MD5:\S{24})? cp $runfolder_path/.*/archive/plex\d+/.* gs://\S+$|; - - foreach my $def (@defs) { - is($def->created_by, $pkg, "created_by is $pkg"); - is($def->identifier, 26291, "identifier is set correctly"); - - my $cmd = $def->command; - my @parts = split / && /, $cmd; # Deconstruct the command - - my $part1 = shift @parts; - my ($env, @rest) = split /;\s/mxs, $part1; - $part1 = join q{ }, @rest; - is('export BOTO_CONFIG=$HOME/.gcp/boto-s3_profile_name', $env, "ENV is $env"); - - foreach my $part ($part1, @parts) { - like($part, $cmd_patt, "command matches"); - } - } -}; - -subtest 'string to add, or not, MD5 to upload command' => sub { - plan tests => 3; - my $file_path = qq($runfolder_path/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex3/26291#3.cram); - my $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/archive_on", - local => 1 - ); - is($archiver->_base64_encoded_md5_gsutil_arg($file_path), q(-h Content-MD5:1B2M2Y8AsgTpgAmY7PhCfg==), 'MD5 header added when md5 available'); - is($archiver->_base64_encoded_md5_gsutil_arg($file_path.q(.crai)), undef, 'MD5 header NOT added when md5 not available'); - dies_ok {$archiver->_base64_encoded_md5_gsutil_arg(q(t/data/file_with_dodgy_md5))} 'dies with malformed md5'; -}; - -subtest 'create for a product' => sub { - plan tests => 5; - - # Using a standard run folder structure. - my $archiver = $pkg->new( - %init, - conf_path => 't/data/release/config/archive_on', - label => 'my_label', - product_rpt_list => '26291:1:3;26291:2:3', - ); - - my @defs = @{$archiver->create}; - is (scalar @defs, 1, 'one definition returned'); - is ($defs[0]->composition->freeze2rpt, '26291:1:3;26291:2:3', 'correct rpt'); - - # Using directory structure similar to top-up cache - - my $dir = File::Temp->newdir()->dirname; - - my $generic_name = $defs[0]->composition->digest; - my $archive = "$dir/archive"; - my $product_archive = join q[/], $archive, $generic_name; - make_path "$product_archive/qc"; - my $target_archive = join q[/], $runfolder_path, 'Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive', 'plex3'; - my @files = glob "$target_archive/*.*"; - my $wd = getcwd(); - foreach my $target (@files) { - my ($name,$path,$suffix) = fileparse($target); - symlink join(q[/],$wd,$target), join(q[/],$product_archive,$name) - or die 'Failed to create a sym link'; - } - @files = glob "$target_archive/qc/*.*"; - foreach my $target (@files) { - my ($name,$path,$suffix) = fileparse($target); - symlink join(q[/],$wd,$target), join(q[/], $product_archive, 'qc', $name) - or die 'Failed to create a sym link'; - } - - $archiver = $pkg->new( - %init, - conf_path => 't/data/release/config/archive_on', - label => 'my_label', - product_rpt_list => '26291:1:3;26291:2:3', - archive_path => $archive, - ); - @defs = @{$archiver->create}; - is (scalar @defs, 1, 'one definition returned'); - is ($defs[0]->composition->freeze2rpt, '26291:1:3;26291:2:3', 'correct rpt'); - - $archiver = $pkg->new( - %init, - conf_path => 't/data/release/config/disregard_qc_outcome', - label => 'my_label', - product_rpt_list => '26291:1:3;26291:2:3', - archive_path => $archive, - qc_schema => undef - ); - @defs = @{$archiver->create}; - is (scalar @defs, 1, - 'no access to QC db, none made since qc outcome does not matter'); - - remove_tree($dir); -}; - -subtest 'configure_date_binning' => sub { - plan tests => 25; - - my $archiver; - lives_ok { - $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/date_binning", - ); - } 'archiver created ok'; - - my $cmd_patt = qr|^gsutil(?: -h Content-MD5:\S{24})? cp $runfolder_path/\S+/archive/plex\d+/\S+ gs://product_bucket/\d{8}/\S+$|; - - my @defs = @{$archiver->create}; - foreach my $def (@defs) { - my $cmd = $def->command; - my @parts = split / && /, $cmd; # Deconstruct the command - - my $part1 = shift @parts; - my ($env, @rest) = split /;\s/mxs, $part1; - $part1 = join q{ }, @rest; - is('export BOTO_CONFIG=$HOME/.gcp/boto-s3_profile_name', $env, "ENV is $env"); - - foreach my $part ($part1, @parts) { - like($part, $cmd_patt, "command matches"); - } - } -}; - -subtest 'no alignments in product' => sub { - local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = - 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . - 'Data/Intensities/BAM_basecalls_20180805-013153/' . - 'metadata_cache_26291/samplesheet_no_align_26291.csv'; - my $archiver; - lives_ok { - $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/archive_on", - ); - } 'archiver created ok'; - - my $cmd_patt = qr|^gsutil(?: -h Content-MD5:\S{24})? cp $runfolder_path/\S+/archive/plex\d+/\S+[.]cram gs://product_bucket/\S+$|; - - my @defs = @{$archiver->create}; - is(scalar @defs, 2, 'two definitions are returned'); - - foreach my $def (@defs) { - my $cmd = $def->command; - my @parts = split / && /, $cmd; # Deconstruct the command - is(scalar @parts, 6, 'one command is present'); - - my $part = shift @parts; - my $expected_env = 'export BOTO_CONFIG=$HOME/.gcp/boto-s3_profile_name'; - my ($env, @rest) = split /;\s/mxs, $part; - is($env, $expected_env, "ENV is $expected_env"); - - $part = join q{ }, @rest; - like($part, $cmd_patt, "command matches"); - } -}; - -subtest 'no_archive_study' => sub { - plan tests => 2; - - my $archiver = $pkg->new( - %init, - conf_path => "t/data/release/config/archive_off" - ); - - my @defs = @{$archiver->create}; - my $num_defs_observed = scalar @defs; - my $num_defs_expected = 1; - cmp_ok($num_defs_observed, '==', $num_defs_expected, - "create returns $num_defs_expected definitions when not archiving") or - diag explain \@defs; - - is($defs[0]->composition, undef, 'definition has no composition') or - diag explain \@defs; -}; - -subtest 'multiple or no study configs' => sub { - plan tests => 2; - - my $archiver = $pkg->new( - %init, - conf_path => 't/data/release/config/multiple_configs', - ); - - throws_ok {$archiver->create} - qr/Multiple configurations for study 5290/, - 'error if multiple study configs are found'; - - $archiver = $pkg->new( - %init, - conf_path => 't/data/release/config/no_config', - ); - - throws_ok {$archiver->create} - qr/No release configuration was defined for study for 26291:1:1;26291:2:1/, - 'error if neither study no default config is found'; -}; diff --git a/t/data/release/config/archive_off/product_release.yml b/t/data/release/config/archive_off/product_release.yml index 9106745d..b89b96aa 100644 --- a/t/data/release/config/archive_off/product_release.yml +++ b/t/data/release/config/archive_off/product_release.yml @@ -1,31 +1,16 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false data_deletion: staging_deletion_delay: 12 study: - study_id: "5290" - s3: - enable: false - url: "gs://product_bucket" - notify: true irods: enable: false - notify: false - study_id: "1000" - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false diff --git a/t/data/release/config/archive_on/product_release.yml b/t/data/release/config/archive_on/product_release.yml index 9ca64527..70b4acfe 100644 --- a/t/data/release/config/archive_on/product_release.yml +++ b/t/data/release/config/archive_on/product_release.yml @@ -1,33 +1,14 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false study: - study_id: "5290" - s3: - enable: true - qc_outcome_matters: true - url: "gs://product_bucket" - profile: s3_profile_name - notify: true irods: enable: false - notify: false - merge: - component_cache_dir: "/tmp/npg_seq_pipeline/cache_merge_component_test/" - study_id: "1000" - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false diff --git a/t/data/release/config/date_binning/product_release.yml b/t/data/release/config/date_binning/product_release.yml deleted file mode 100644 index 9d4ef011..00000000 --- a/t/data/release/config/date_binning/product_release.yml +++ /dev/null @@ -1,23 +0,0 @@ -default: - s3: - enable: true - qc_outcome_matters: true - url: "gs://product_bucket" - date_binning: true - profile: s3_profile_name - notify: false - receipts: "/tmp/receipts/does/not/exist" - irods: - enable: false - notify: false - -study: - - study_id: "1000" - s3: - enable: true - qc_outcome_matters: true - url: null - notify: false - irods: - enable: true - notify: false diff --git a/t/data/release/config/default_s3_archival/product_release.yml b/t/data/release/config/default_s3_archival/product_release.yml deleted file mode 100644 index ce7bdcd3..00000000 --- a/t/data/release/config/default_s3_archival/product_release.yml +++ /dev/null @@ -1,19 +0,0 @@ -default: - s3: - enable: true - url: "gs://product_bucket" - notify: false - receipts: "/tmp/receipts/does/not/exist" - irods: - enable: false - notify: false - -study: - - study_id: "1000" - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false diff --git a/t/data/release/config/disregard_qc_outcome/product_release.yml b/t/data/release/config/disregard_qc_outcome/product_release.yml deleted file mode 100644 index cfde27d3..00000000 --- a/t/data/release/config/disregard_qc_outcome/product_release.yml +++ /dev/null @@ -1,32 +0,0 @@ ---- -default: - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false - -study: - - study_id: "5290" - s3: - enable: true - url: "gs://product_bucket" - profile: s3_profile_name - notify: true - irods: - enable: false - notify: false - merge: - component_cache_dir: "/tmp/npg_seq_pipeline/cache_merge_component_test/" - - - study_id: "1000" - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false - diff --git a/t/data/release/config/empty_default/product_release.yml b/t/data/release/config/empty_default/product_release.yml deleted file mode 100644 index 4bfca927..00000000 --- a/t/data/release/config/empty_default/product_release.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -default: diff --git a/t/data/release/config/multiple_configs/product_release.yml b/t/data/release/config/multiple_configs/product_release.yml deleted file mode 100644 index e6a4118c..00000000 --- a/t/data/release/config/multiple_configs/product_release.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -default: - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false - -study: - - study_id: "5290" - s3: - enable: true - url: "gs://product_bucket" - profile: s3_profile_name - notify: true - irods: - enable: false - notify: false - - - study_id: "1000" - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false - - - study_id: "5290" - s3: - enable: false - notify: false - irods: - enable: true - notify: false diff --git a/t/data/release/config/no_config/product_release.yml b/t/data/release/config/no_config/product_release.yml deleted file mode 100644 index 515930fb..00000000 --- a/t/data/release/config/no_config/product_release.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -study: - - - study_id: "1000" - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false diff --git a/t/data/release/config/notify_off/product_release.yml b/t/data/release/config/notify_off/product_release.yml index b6e10464..67952fa7 100644 --- a/t/data/release/config/notify_off/product_release.yml +++ b/t/data/release/config/notify_off/product_release.yml @@ -1,34 +1,18 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false data_deletion: staging_deletion_delay: 12 study: - study_id: "5290" - s3: - enable: true - qc_outcome_matters: true - url: "gs://product_bucket" - notify: false irods: enable: false - notify: false - study_id: "1000" - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false - study_id: "1713" data_deletion: diff --git a/t/data/release/config/notify_on/product_release.yml b/t/data/release/config/notify_on/product_release.yml index 31fc0866..07aa9d23 100644 --- a/t/data/release/config/notify_on/product_release.yml +++ b/t/data/release/config/notify_on/product_release.yml @@ -1,35 +1,18 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false data_deletion: staging_deletion_delay: 12 study: - study_id: "5290" - s3: - enable: true - qc_outcome_matters: true - url: "gs://product_bucket" - customer_name: test_customer - notify: true irods: enable: false - notify: true - study_id: "1000" - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false - study_id: "1713" data_deletion: diff --git a/t/data/release/config/pp_archival/product_release.yml b/t/data/release/config/pp_archival/product_release.yml index f00c1d4a..196ddbd6 100644 --- a/t/data/release/config/pp_archival/product_release.yml +++ b/t/data/release/config/pp_archival/product_release.yml @@ -1,15 +1,9 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: false - notify: false irods_pp: enable: false - notify: false study: - study_id: "6187" @@ -18,10 +12,8 @@ study: markdup_method: "none" irods: enable: false - notify: false irods_pp: enable: true - notify: false filters: include: - 'ncov2019_artic_nf/v0.(7|8)\b\S+trim\S+/\S+bam' diff --git a/t/data/release/config/pp_archival/product_release_no_array.yml b/t/data/release/config/pp_archival/product_release_no_array.yml index 92d34e5e..8258da0b 100644 --- a/t/data/release/config/pp_archival/product_release_no_array.yml +++ b/t/data/release/config/pp_archival/product_release_no_array.yml @@ -1,15 +1,9 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: false - notify: false irods_pp: enable: false - notify: false study: - study_id: "6187" @@ -18,9 +12,7 @@ study: markdup_method: "none" irods: enable: false - notify: false irods_pp: enable: true - notify: false filters: include: 'ncov2019_artic_nf/v0.(7|8)\b\S+trim\S+/\S+bam' diff --git a/t/data/release/config/pp_archival/product_release_no_filters.yml b/t/data/release/config/pp_archival/product_release_no_filters.yml index 369382b5..a553a1f5 100644 --- a/t/data/release/config/pp_archival/product_release_no_filters.yml +++ b/t/data/release/config/pp_archival/product_release_no_filters.yml @@ -1,15 +1,9 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: false - notify: false irods_pp: enable: false - notify: false study: - study_id: "6187" @@ -18,7 +12,5 @@ study: markdup_method: "none" irods: enable: false - notify: false irods_pp: enable: true - notify: false diff --git a/t/data/release/config/pp_archival/product_release_no_include.yml b/t/data/release/config/pp_archival/product_release_no_include.yml index c9ab6f59..a171d15e 100644 --- a/t/data/release/config/pp_archival/product_release_no_include.yml +++ b/t/data/release/config/pp_archival/product_release_no_include.yml @@ -1,15 +1,9 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: false - notify: false irods_pp: enable: false - notify: false study: - study_id: "6187" @@ -18,10 +12,8 @@ study: markdup_method: "none" irods: enable: false - notify: false irods_pp: enable: true - notify: false filters: exclude: - 'test_file_pollution' diff --git a/t/data/release/config/qc_review/product_release.yml b/t/data/release/config/qc_review/product_release.yml index f0dbf266..b9fdcba6 100644 --- a/t/data/release/config/qc_review/product_release.yml +++ b/t/data/release/config/qc_review/product_release.yml @@ -1,13 +1,7 @@ --- default: - s3: - enable: false - url: null - notify: false irods: enable: true - notify: false - study: - study_id: "1713" robo_qc: diff --git a/t/data/release/config/undef_qc_accept/product_release.yml b/t/data/release/config/undef_qc_accept/product_release.yml deleted file mode 100644 index 6e6b6fd3..00000000 --- a/t/data/release/config/undef_qc_accept/product_release.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -default: - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false - -study: - - study_id: "5290" - s3: - enable: true - qc_outcome_matters: true - accept_undef_qc_outcome: true - url: "gs://product_bucket" - profile: s3_profile_name - notify: true - irods: - enable: false - notify: false - merge: - component_cache_dir: "/tmp/npg_seq_pipeline/cache_merge_component_test/" - - - study_id: "1000" - s3: - enable: false - url: null - notify: false - irods: - enable: true - notify: false - From 580518755aac26b7d58e4dda63183a525ca0d00c Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Fri, 2 Feb 2024 11:07:02 +0000 Subject: [PATCH 06/18] Deleted unused test data --- MANIFEST | 7 ------- t/data/hiseq/samplesheet_45421.csv | 10 ---------- t/data/messaging/npg_message_queue.conf | 6 ------ t/data/miseq/samplesheet_24135_bwa_mem2.csv | 4 ---- .../samplesheet4archival_all_controls.csv | 10 ---------- .../samplesheet4archival_none_controls.csv | 10 ---------- .../samplesheet4archival_none_controls_cons_wthdr.csv | 10 ---------- .../samplesheet4archival_none_controls_diff_study.csv | 10 ---------- ...amplesheet4archival_none_controls_no_suppl_name.csv | 10 ---------- 9 files changed, 77 deletions(-) delete mode 100644 t/data/hiseq/samplesheet_45421.csv delete mode 100644 t/data/messaging/npg_message_queue.conf delete mode 100644 t/data/miseq/samplesheet_24135_bwa_mem2.csv delete mode 100644 t/data/portable_pipelines/samplesheet4archival_all_controls.csv delete mode 100644 t/data/portable_pipelines/samplesheet4archival_none_controls.csv delete mode 100644 t/data/portable_pipelines/samplesheet4archival_none_controls_cons_wthdr.csv delete mode 100644 t/data/portable_pipelines/samplesheet4archival_none_controls_diff_study.csv delete mode 100644 t/data/portable_pipelines/samplesheet4archival_none_controls_no_suppl_name.csv diff --git a/MANIFEST b/MANIFEST index b90f71d1..80a8f6b7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -225,7 +225,6 @@ t/data/hiseq/samplesheet_20268.csv t/data/hiseqx/43416_runParameters.xml t/data/hiseqx/16839_RunInfo.xml t/data/hiseqx/samplesheet_16839.csv -t/data/messaging/npg_message_queue.conf t/data/miseq/16850_RunInfo.xml t/data/miseq/16850_runParameters.xml t/data/miseq/16866_RunInfo.xml @@ -235,7 +234,6 @@ t/data/miseq/samplesheet_16850.csv t/data/miseq/samplesheet_16866.csv t/data/miseq/samplesheet_20990.csv t/data/miseq/samplesheet_24135.csv -t/data/miseq/samplesheet_24135_bwa_mem2.csv t/data/miseq/samplesheet_24135_gbs.csv t/data/miseq/samplesheet_24135_V2.csv t/data/no_reads.cram @@ -1042,11 +1040,6 @@ t/data/novaseqx/20231017_LH00210_0012_B22FCNFLT3/RunParameters.xml t/data/novaseqx/20231017_LH00210_0012_B22FCNFLT3/samplesheet_47995.csv t/data/p4_stage1_analysis/1234_samplesheet.csv t/data/p4_stage1_analysis/TileMetricsOut.bin -t/data/portable_pipelines/samplesheet4archival_all_controls.csv -t/data/portable_pipelines/samplesheet4archival_none_controls.csv -t/data/portable_pipelines/samplesheet4archival_none_controls_cons_wthdr.csv -t/data/portable_pipelines/samplesheet4archival_none_controls_diff_study.csv -t/data/portable_pipelines/samplesheet4archival_none_controls_no_suppl_name.csv t/data/portable_pipelines/ncov2019-artic-nf/cf01166c42a/product_release.yml t/data/portable_pipelines/ncov2019-artic-nf/cf01166c42a/product_release_no_pp.yml t/data/portable_pipelines/ncov2019-artic-nf/cf01166c42a/product_release_no_study.yml diff --git a/t/data/hiseq/samplesheet_45421.csv b/t/data/hiseq/samplesheet_45421.csv deleted file mode 100644 index 91e7948f..00000000 --- a/t/data/hiseq/samplesheet_45421.csv +++ /dev/null @@ -1,10 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Lane,Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,gbs_plex_name,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_control_type,sample_description,sample_donor_id,sample_id,sample_is_control,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index, -1,64072754,SAMPLE01,,TAGCTTGT,ATAGAGGC,,,TAGCTTGT,ATAGAGGC,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk,,0,0,64504473,0,64072754,,9606,S10481,,,standard,,,from:300 to:400,,NA,Homo sapiens,0,,MSH2E2_2_R3_D14,SAMPLE01,8319648,0,SAMPLE01,,Homo_sapiens (GRCh38_15),MSH2E2_2_R3_D14,888,,0,0,0,Saturation Genome Editing of MSH2. This study aims to functionally characterize saturating-levels of mutation at the MSH2 locus. We will target the Coding Sequence (CDS) and splice-site containing intron of the transcript%3A ENST00000233146.7.%0D%0A%0D%0ACRISPR-Cas9 and variant harbouring dsDNA repair templates will be co-transfected into HAP1 cells (Lig4-%26 clonal Cas9 expressing%2C sorted for 1n ploidy) to edit populations of cells. Targeted regions will then be sampled with gDNA extracted from cells at day 0%2C 3 %26 14 after transfection. Amplicons are then generated for each of these time points in triplicate. Amplicons are composed of edited MSH2 locus.%0D%0AOligonucleotide libraries were generated using the software package VaLiAnT (https%3A%2F%2Fgithub.com%2Fcancerit%2FVaLiAnT) and synthesized by Twist Bioscience. Libraries contain SNVs%2C in-frame deletions%2C an alanine and stop-codon scan%2C 1 base-pair deletions and tandem deletions in exon flanking intron. Clinical and population-observed mutations were also incorporated into edited regions (or %27targetons%27) by including accessions in ClinVar release%3A 20210619 and gnomAD release%3A v3.1. Libraries can be accessed here%3A https%3A%2F%2Fgitlab.internal.sanger.ac.uk%2Fteam113_sge%2Fteam113_sge_libraries%2FMSH2.%0D%0A%0D%0AAfter gDNA and PCR sampling (to enrich for the edited locus). Amplicons will be processed to add Illumina primary adapters and indexes and pooled. Sequencing will be performed on Illumina platforms. HISeq2500 and 500 SE reads (dual indexed pools) will be standard. The amplicons are roughly 245-300bp in length. Library sizes are roughly 1000 variants for each amplicon. We will aim for 500x coverage%2C which equates to roughly 500%2C000 reads allocated per library. Plasmid libraries will also be sequenced as part of this project. %0D%0A%0D%0AFastq files will be processed through a pipeline to obtain read-counts for variants with subsequent down-stream analyses performed to calculate the depletion kinetics of the variants within target regions.,6931,Saturation Genome Editing (SGE) on MSH2,Homo_sapiens (GRCh38_full_analysis_set_plus_decoy_hla),0,Saturation Genome Editing (SGE) on MSH2,1, -1,64072741,SAMPLE02,,GGCTACAG,ATAGAGGC,,,GGCTACAG,ATAGAGGC,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk,,0,0,64504473,0,64072741,,9606,S10481,,,standard,,,from:300 to:400,,NA,Homo sapiens,0,,MSH2E2_1_R2_D0,SAMPLE02,8319635,0,SAMPLE02,,Homo_sapiens (GRCh38_15),MSH2E2_1_R2_D0,888,,0,0,0,Saturation Genome Editing of MSH2. This study aims to functionally characterize saturating-levels of mutation at the MSH2 locus. We will target the Coding Sequence (CDS) and splice-site containing intron of the transcript%3A ENST00000233146.7.%0D%0A%0D%0ACRISPR-Cas9 and variant harbouring dsDNA repair templates will be co-transfected into HAP1 cells (Lig4-%26 clonal Cas9 expressing%2C sorted for 1n ploidy) to edit populations of cells. Targeted regions will then be sampled with gDNA extracted from cells at day 0%2C 3 %26 14 after transfection. Amplicons are then generated for each of these time points in triplicate. Amplicons are composed of edited MSH2 locus.%0D%0AOligonucleotide libraries were generated using the software package VaLiAnT (https%3A%2F%2Fgithub.com%2Fcancerit%2FVaLiAnT) and synthesized by Twist Bioscience. Libraries contain SNVs%2C in-frame deletions%2C an alanine and stop-codon scan%2C 1 base-pair deletions and tandem deletions in exon flanking intron. Clinical and population-observed mutations were also incorporated into edited regions (or %27targetons%27) by including accessions in ClinVar release%3A 20210619 and gnomAD release%3A v3.1. Libraries can be accessed here%3A https%3A%2F%2Fgitlab.internal.sanger.ac.uk%2Fteam113_sge%2Fteam113_sge_libraries%2FMSH2.%0D%0A%0D%0AAfter gDNA and PCR sampling (to enrich for the edited locus). Amplicons will be processed to add Illumina primary adapters and indexes and pooled. Sequencing will be performed on Illumina platforms. HISeq2500 and 500 SE reads (dual indexed pools) will be standard. The amplicons are roughly 245-300bp in length. Library sizes are roughly 1000 variants for each amplicon. We will aim for 500x coverage%2C which equates to roughly 500%2C000 reads allocated per library. Plasmid libraries will also be sequenced as part of this project. %0D%0A%0D%0AFastq files will be processed through a pipeline to obtain read-counts for variants with subsequent down-stream analyses performed to calculate the depletion kinetics of the variants within target regions.,6931,Saturation Genome Editing (SGE) on MSH2,Homo_sapiens (GRCh38_full_analysis_set_plus_decoy_hla),0,Saturation Genome Editing (SGE) on MSH2,2, -1,64072742,SAMPLE03,,CTTGTACT,ATAGAGGC,,,CTTGTACT,ATAGAGGC,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk,,0,0,64504473,0,64072742,,9606,S10481,,,standard,,,from:300 to:400,,NA,Homo sapiens,0,,MSH2E2_1_R1_D3,SAMPLE03,8319636,0,SAMPLE03,,Homo_sapiens (GRCh38_15),MSH2E2_1_R1_D3,888,,0,0,0,Saturation Genome Editing of MSH2. This study aims to functionally characterize saturating-levels of mutation at the MSH2 locus. We will target the Coding Sequence (CDS) and splice-site containing intron of the transcript%3A ENST00000233146.7.%0D%0A%0D%0ACRISPR-Cas9 and variant harbouring dsDNA repair templates will be co-transfected into HAP1 cells (Lig4-%26 clonal Cas9 expressing%2C sorted for 1n ploidy) to edit populations of cells. Targeted regions will then be sampled with gDNA extracted from cells at day 0%2C 3 %26 14 after transfection. Amplicons are then generated for each of these time points in triplicate. Amplicons are composed of edited MSH2 locus.%0D%0AOligonucleotide libraries were generated using the software package VaLiAnT (https%3A%2F%2Fgithub.com%2Fcancerit%2FVaLiAnT) and synthesized by Twist Bioscience. Libraries contain SNVs%2C in-frame deletions%2C an alanine and stop-codon scan%2C 1 base-pair deletions and tandem deletions in exon flanking intron. Clinical and population-observed mutations were also incorporated into edited regions (or %27targetons%27) by including accessions in ClinVar release%3A 20210619 and gnomAD release%3A v3.1. Libraries can be accessed here%3A https%3A%2F%2Fgitlab.internal.sanger.ac.uk%2Fteam113_sge%2Fteam113_sge_libraries%2FMSH2.%0D%0A%0D%0AAfter gDNA and PCR sampling (to enrich for the edited locus). Amplicons will be processed to add Illumina primary adapters and indexes and pooled. Sequencing will be performed on Illumina platforms. HISeq2500 and 500 SE reads (dual indexed pools) will be standard. The amplicons are roughly 245-300bp in length. Library sizes are roughly 1000 variants for each amplicon. We will aim for 500x coverage%2C which equates to roughly 500%2C000 reads allocated per library. Plasmid libraries will also be sequenced as part of this project. %0D%0A%0D%0AFastq files will be processed through a pipeline to obtain read-counts for variants with subsequent down-stream analyses performed to calculate the depletion kinetics of the variants within target regions.,6931,Saturation Genome Editing (SGE) on MSH2,Homo_sapiens (GRCh38_full_analysis_set_plus_decoy_hla),0,Saturation Genome Editing (SGE) on MSH2,3, -1,27409532,phiX_for_spiked_buffers,,TGTGCAGC,ACTGATGT,,,TGTGCAGC,ACTGATGT,,,,,,1,0,64504473,0,27409532,,10847,,,,standard,,,,,,,0,,,,1255141,,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888, -2,64072754,SAMPLE01,,TAGCTTGT,ATAGAGGC,,,TAGCTTGT,ATAGAGGC,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk,,0,0,64504474,0,64072754,,9606,S10481,,,standard,,,from:300 to:400,,NA,Homo sapiens,0,,MSH2E2_2_R3_D14,SAMPLE01,8319648,0,SAMPLE01,,Homo_sapiens (GRCh38_15),MSH2E2_2_R3_D14,888,,0,0,0,Saturation Genome Editing of MSH2. This study aims to functionally characterize saturating-levels of mutation at the MSH2 locus. We will target the Coding Sequence (CDS) and splice-site containing intron of the transcript%3A ENST00000233146.7.%0D%0A%0D%0ACRISPR-Cas9 and variant harbouring dsDNA repair templates will be co-transfected into HAP1 cells (Lig4-%26 clonal Cas9 expressing%2C sorted for 1n ploidy) to edit populations of cells. Targeted regions will then be sampled with gDNA extracted from cells at day 0%2C 3 %26 14 after transfection. Amplicons are then generated for each of these time points in triplicate. Amplicons are composed of edited MSH2 locus.%0D%0AOligonucleotide libraries were generated using the software package VaLiAnT (https%3A%2F%2Fgithub.com%2Fcancerit%2FVaLiAnT) and synthesized by Twist Bioscience. Libraries contain SNVs%2C in-frame deletions%2C an alanine and stop-codon scan%2C 1 base-pair deletions and tandem deletions in exon flanking intron. Clinical and population-observed mutations were also incorporated into edited regions (or %27targetons%27) by including accessions in ClinVar release%3A 20210619 and gnomAD release%3A v3.1. Libraries can be accessed here%3A https%3A%2F%2Fgitlab.internal.sanger.ac.uk%2Fteam113_sge%2Fteam113_sge_libraries%2FMSH2.%0D%0A%0D%0AAfter gDNA and PCR sampling (to enrich for the edited locus). Amplicons will be processed to add Illumina primary adapters and indexes and pooled. Sequencing will be performed on Illumina platforms. HISeq2500 and 500 SE reads (dual indexed pools) will be standard. The amplicons are roughly 245-300bp in length. Library sizes are roughly 1000 variants for each amplicon. We will aim for 500x coverage%2C which equates to roughly 500%2C000 reads allocated per library. Plasmid libraries will also be sequenced as part of this project. %0D%0A%0D%0AFastq files will be processed through a pipeline to obtain read-counts for variants with subsequent down-stream analyses performed to calculate the depletion kinetics of the variants within target regions.,6931,Saturation Genome Editing (SGE) on MSH2,Homo_sapiens (GRCh38_full_analysis_set_plus_decoy_hla),0,Saturation Genome Editing (SGE) on MSH2,1, -2,64072741,SAMPLE02,,GGCTACAG,ATAGAGGC,,,GGCTACAG,ATAGAGGC,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk,,0,0,64504474,0,64072741,,9606,S10481,,,standard,,,from:300 to:400,,NA,Homo sapiens,0,,MSH2E2_1_R2_D0,SAMPLE02,8319635,0,SAMPLE02,,Homo_sapiens (GRCh38_15),MSH2E2_1_R2_D0,888,,0,0,0,Saturation Genome Editing of MSH2. This study aims to functionally characterize saturating-levels of mutation at the MSH2 locus. We will target the Coding Sequence (CDS) and splice-site containing intron of the transcript%3A ENST00000233146.7.%0D%0A%0D%0ACRISPR-Cas9 and variant harbouring dsDNA repair templates will be co-transfected into HAP1 cells (Lig4-%26 clonal Cas9 expressing%2C sorted for 1n ploidy) to edit populations of cells. Targeted regions will then be sampled with gDNA extracted from cells at day 0%2C 3 %26 14 after transfection. Amplicons are then generated for each of these time points in triplicate. Amplicons are composed of edited MSH2 locus.%0D%0AOligonucleotide libraries were generated using the software package VaLiAnT (https%3A%2F%2Fgithub.com%2Fcancerit%2FVaLiAnT) and synthesized by Twist Bioscience. Libraries contain SNVs%2C in-frame deletions%2C an alanine and stop-codon scan%2C 1 base-pair deletions and tandem deletions in exon flanking intron. Clinical and population-observed mutations were also incorporated into edited regions (or %27targetons%27) by including accessions in ClinVar release%3A 20210619 and gnomAD release%3A v3.1. Libraries can be accessed here%3A https%3A%2F%2Fgitlab.internal.sanger.ac.uk%2Fteam113_sge%2Fteam113_sge_libraries%2FMSH2.%0D%0A%0D%0AAfter gDNA and PCR sampling (to enrich for the edited locus). Amplicons will be processed to add Illumina primary adapters and indexes and pooled. Sequencing will be performed on Illumina platforms. HISeq2500 and 500 SE reads (dual indexed pools) will be standard. The amplicons are roughly 245-300bp in length. Library sizes are roughly 1000 variants for each amplicon. We will aim for 500x coverage%2C which equates to roughly 500%2C000 reads allocated per library. Plasmid libraries will also be sequenced as part of this project. %0D%0A%0D%0AFastq files will be processed through a pipeline to obtain read-counts for variants with subsequent down-stream analyses performed to calculate the depletion kinetics of the variants within target regions.,6931,Saturation Genome Editing (SGE) on MSH2,Homo_sapiens (GRCh38_full_analysis_set_plus_decoy_hla),0,Saturation Genome Editing (SGE) on MSH2,2, -2,64072742,SAMPLE03,,CTTGTACT,ATAGAGGC,,,CTTGTACT,ATAGAGGC,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk xxx.sanger.ac.uk xxx.sanger.ac.uk,xxx.sanger.ac.uk,,0,0,64504474,0,64072742,,9606,S10481,,,standard,,,from:300 to:400,,NA,Homo sapiens,0,,MSH2E2_1_R1_D3,SAMPLE03,8319636,0,SAMPLE03,,Homo_sapiens (GRCh38_15),MSH2E2_1_R1_D3,888,,0,0,0,Saturation Genome Editing of MSH2. This study aims to functionally characterize saturating-levels of mutation at the MSH2 locus. We will target the Coding Sequence (CDS) and splice-site containing intron of the transcript%3A ENST00000233146.7.%0D%0A%0D%0ACRISPR-Cas9 and variant harbouring dsDNA repair templates will be co-transfected into HAP1 cells (Lig4-%26 clonal Cas9 expressing%2C sorted for 1n ploidy) to edit populations of cells. Targeted regions will then be sampled with gDNA extracted from cells at day 0%2C 3 %26 14 after transfection. Amplicons are then generated for each of these time points in triplicate. Amplicons are composed of edited MSH2 locus.%0D%0AOligonucleotide libraries were generated using the software package VaLiAnT (https%3A%2F%2Fgithub.com%2Fcancerit%2FVaLiAnT) and synthesized by Twist Bioscience. Libraries contain SNVs%2C in-frame deletions%2C an alanine and stop-codon scan%2C 1 base-pair deletions and tandem deletions in exon flanking intron. Clinical and population-observed mutations were also incorporated into edited regions (or %27targetons%27) by including accessions in ClinVar release%3A 20210619 and gnomAD release%3A v3.1. Libraries can be accessed here%3A https%3A%2F%2Fgitlab.internal.sanger.ac.uk%2Fteam113_sge%2Fteam113_sge_libraries%2FMSH2.%0D%0A%0D%0AAfter gDNA and PCR sampling (to enrich for the edited locus). Amplicons will be processed to add Illumina primary adapters and indexes and pooled. Sequencing will be performed on Illumina platforms. HISeq2500 and 500 SE reads (dual indexed pools) will be standard. The amplicons are roughly 245-300bp in length. Library sizes are roughly 1000 variants for each amplicon. We will aim for 500x coverage%2C which equates to roughly 500%2C000 reads allocated per library. Plasmid libraries will also be sequenced as part of this project. %0D%0A%0D%0AFastq files will be processed through a pipeline to obtain read-counts for variants with subsequent down-stream analyses performed to calculate the depletion kinetics of the variants within target regions.,6931,Saturation Genome Editing (SGE) on MSH2,Homo_sapiens (GRCh38_full_analysis_set_plus_decoy_hla),0,Saturation Genome Editing (SGE) on MSH2,3, -2,27409532,phiX_for_spiked_buffers,,TGTGCAGC,ACTGATGT,,,TGTGCAGC,ACTGATGT,,,,,,1,0,64504474,0,27409532,,10847,,,,standard,,,,,,,0,,,,1255141,,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888, diff --git a/t/data/messaging/npg_message_queue.conf b/t/data/messaging/npg_message_queue.conf deleted file mode 100644 index e3d1ec04..00000000 --- a/t/data/messaging/npg_message_queue.conf +++ /dev/null @@ -1,6 +0,0 @@ -host=localhost -port=5672 -user=npg -password=test -vhost=/ -exchange="" diff --git a/t/data/miseq/samplesheet_24135_bwa_mem2.csv b/t/data/miseq/samplesheet_24135_bwa_mem2.csv deleted file mode 100644 index 688edcba..00000000 --- a/t/data/miseq/samplesheet_24135_bwa_mem2.csv +++ /dev/null @@ -1,4 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_description,sample_donor_id,sample_id,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index,gbs_plex_name, -20314922,mxPCR7155682,,ATCACGTT,AGGCGAAG,,GbS standard,ATCACGTT,AGGCGAAG,blah@sanger.ac.uk blah2@sanger.ac.uk,blah@sanger.ac.uk,blah2@sanger.ac.uk,blah2@sanger.ac.uk,0,0,20315681,0,20314922,,,S0910,,,standard,,,from:100 to:1000,,,,0,,mxPCR7155682,3373451,mxPCR7155682,,,HAPMAP5265538,,EGAS00001002541,1,0,0,This data is part of a pre-publication release. For information on the proper use of pre-publication data shared by the Wellcome Trust Sanger Institute (including details of any publication moratoria)%2C please see http%3A%2F%2Fwww.sanger.ac.uk%2Fdatasharing%2F%0D%0A,4825,Multiplex PCR R%26D for Agena%2FFluidigm replacement,Homo_sapiens (GRCh38_15),0,Flexible multiplex PCR for genotyping-by-sequencing,1,Hs_MajorQC, -20314923,mxPCR7155683,,CGATGTTT,AGGCGAAG [bwa_mem2],,GnT MDA,CGATGTTT,AGGCGAAG,blah@sanger.ac.uk blah2@sanger.ac.uk,blah@sanger.ac.uk,blah2@sanger.ac.uk,blah2@sanger.ac.uk,0,0,20315681,0,20314923,,,S0910,,,standard,,,from:100 to:1000,,,,0,,mxPCR7155683,3373452,mxPCR7155683,,,HAPMAP5265539,,EGAS00001002541,1,0,0,This data is part of a pre-publication release. For information on the proper use of pre-publication data shared by the Wellcome Trust Sanger Institute (including details of any publication moratoria)%2C please see http%3A%2F%2Fwww.sanger.ac.uk%2Fdatasharing%2F%0D%0A,4825,Multiplex PCR R%26D for Agena%2FFluidigm replacement,Homo_sapiens (GRCh38_15) [bwa_mem2],0,Flexible multiplex PCR for genotyping-by-sequencing,2,Hs_MajorQC, diff --git a/t/data/portable_pipelines/samplesheet4archival_all_controls.csv b/t/data/portable_pipelines/samplesheet4archival_all_controls.csv deleted file mode 100644 index b442347b..00000000 --- a/t/data/portable_pipelines/samplesheet4archival_all_controls.csv +++ /dev/null @@ -1,10 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Lane,Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,gbs_plex_name,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_description,sample_donor_id,sample_id,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index,sample_is_control,sample_control_type, -1,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),A1,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,1,, -1,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),B1,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,1,, -1,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),C1,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,1,, -1,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),A1,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,1,, -2,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),B1,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,1,, -2,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),C1,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,1,, diff --git a/t/data/portable_pipelines/samplesheet4archival_none_controls.csv b/t/data/portable_pipelines/samplesheet4archival_none_controls.csv deleted file mode 100644 index 730c7f0d..00000000 --- a/t/data/portable_pipelines/samplesheet4archival_none_controls.csv +++ /dev/null @@ -1,10 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Lane,Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,gbs_plex_name,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_description,sample_donor_id,sample_id,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index,sample_is_control,sample_control_type, -1,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -1,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -1,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, -1,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -2,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -2,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, diff --git a/t/data/portable_pipelines/samplesheet4archival_none_controls_cons_wthdr.csv b/t/data/portable_pipelines/samplesheet4archival_none_controls_cons_wthdr.csv deleted file mode 100644 index e31e15d8..00000000 --- a/t/data/portable_pipelines/samplesheet4archival_none_controls_cons_wthdr.csv +++ /dev/null @@ -1,10 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Lane,Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,gbs_plex_name,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_description,sample_donor_id,sample_id,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index,sample_is_control,sample_control_type, -1,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,1,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -1,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -1,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, -1,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -2,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -2,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, diff --git a/t/data/portable_pipelines/samplesheet4archival_none_controls_diff_study.csv b/t/data/portable_pipelines/samplesheet4archival_none_controls_diff_study.csv deleted file mode 100644 index 8b887b33..00000000 --- a/t/data/portable_pipelines/samplesheet4archival_none_controls_diff_study.csv +++ /dev/null @@ -1,10 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Lane,Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,gbs_plex_name,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_description,sample_donor_id,sample_id,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index,sample_is_control,sample_control_type, -1,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3070,Team51_Development,,0,Team51_Development,1,0,, -1,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3070,Team51_Development,,0,Team51_Development,2,0,, -1,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3070,Team51_Development,,0,Team51_Development,3,0,, -1,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -2,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -2,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, diff --git a/t/data/portable_pipelines/samplesheet4archival_none_controls_no_suppl_name.csv b/t/data/portable_pipelines/samplesheet4archival_none_controls_no_suppl_name.csv deleted file mode 100644 index fcb3f425..00000000 --- a/t/data/portable_pipelines/samplesheet4archival_none_controls_no_suppl_name.csv +++ /dev/null @@ -1,10 +0,0 @@ -[Data],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Lane,Sample_ID,Sample_Name,GenomeFolder,Index,Index2,bait_name,default_library_type,default_tag_sequence,default_tagtwo_sequence,email_addresses,email_addresses_of_followers,email_addresses_of_managers,email_addresses_of_owners,gbs_plex_name,is_control,is_pool,lane_id,lane_priority,library_name,organism,organism_taxon_id,project_cost_code,project_id,project_name,purpose,qc_state,request_id,required_insert_size_range,sample_accession_number,sample_cohort,sample_common_name,sample_consent_withdrawn,sample_description,sample_donor_id,sample_id,sample_name,sample_public_name,sample_reference_genome,sample_supplier_name,spiked_phix_tag_index,study_accession_number,study_alignments_in_bam,study_contains_nonconsented_human,study_contains_nonconsented_xahuman,study_description,study_id,study_name,study_reference_genome,study_separate_y_chromosome_data,study_title,tag_index,sample_is_control,sample_control_type, -1,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -1,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -1,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, -1,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,21210572,phiX_for_spiked_buffers,,ACAACGCAATC,,,,ACAACGCAATC,,,,,,,1,0,22706627,0,21210572,,10847,,,,standard,,,,,,,0,,,1255141,phiX_for_spiked_buffers,,PhiX (Sanger-SNPs),,888,,1,0,0,None,198,Illumina Controls, ,0,,888,0,, -2,29622116,8818236,,GGGATCCT,CCATCCAA,,Standard,GGGATCCT,CCATCCAA,,,,,nCoV-2019,0,0,29622179,0,29622116,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818236,4424218,8818236,,SARS-CoV-2 (MN908947.3),AAMB-M4567,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,1,0,, -2,29622117,8818237,,GATACTCC,ACACCCAG,,Standard,GATACTCC,ACACCCAG,,,,,nCoV-2019/V2,0,0,29622179,0,29622117,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818237,4424219,8818237,,SARS-CoV-2 (MN908947.3),BIRMZ4378,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,2,0,, -2,29622118,8818238,,GCCAAGCA,CTCTCCTC,,Standard,GCCAAGCA,CTCTCCTC,,,,,nCoV-2019/V3,0,0,29622179,0,29622118,,,S10068,,,standard,,,from:50 to:600,,,,0,,8818238,4424220,8818238,,SARS-CoV-2 (MN908947.3),BRIS-K5678,,,1,0,0,Development of sequencing and library prep protocols using Human DNA from Promega,3073,Team51_Development,,0,Team51_Development,3,0,, From ea8db8be175f2b41f9ec09130eac37f9e3ffe643 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Fri, 2 Feb 2024 17:25:16 +0000 Subject: [PATCH 07/18] Removed pipeline dependency on npg_qc::Schema At the monent neither the analysis nor the archival pipeline runner (but not jobs) needs access to the QC database. The 'qc_schema' accessor attribute is removed from npg_pipeline::base. Methods returning QC database objects removed from npg_pipeline::product; this functionality is no longer required. Unused QC database fixtures are deleted. --- MANIFEST | 8 - lib/npg_pipeline/base.pm | 16 -- lib/npg_pipeline/product.pm | 110 ------------ lib/npg_pipeline/validation.pm | 8 +- t/15-product-release.t | 11 +- .../fixtures/000-mqc_library_outcome_dict.yml | 32 ---- .../fixtures/000-mqc_outcome_dict.yml | 27 --- .../fixtures/000-uqc_outcome_dict.yml | 16 -- .../fixtures/200-seq_component.yml | 158 ------------------ .../300-seq_component_composition.yml | 106 ------------ .../fixtures/300-seq_composition.yml | 44 ----- .../fixtures/400-mqc_library_outcome_ent.yml | 121 -------------- .../fixtures/400-mqc_outcome_ent.yml | 20 --- t/data/qc_outcomes/fixtures/README | 18 -- 14 files changed, 7 insertions(+), 688 deletions(-) delete mode 100644 t/data/qc_outcomes/fixtures/000-mqc_library_outcome_dict.yml delete mode 100644 t/data/qc_outcomes/fixtures/000-mqc_outcome_dict.yml delete mode 100755 t/data/qc_outcomes/fixtures/000-uqc_outcome_dict.yml delete mode 100644 t/data/qc_outcomes/fixtures/200-seq_component.yml delete mode 100644 t/data/qc_outcomes/fixtures/300-seq_component_composition.yml delete mode 100644 t/data/qc_outcomes/fixtures/300-seq_composition.yml delete mode 100644 t/data/qc_outcomes/fixtures/400-mqc_library_outcome_ent.yml delete mode 100644 t/data/qc_outcomes/fixtures/400-mqc_outcome_ent.yml delete mode 100644 t/data/qc_outcomes/fixtures/README diff --git a/MANIFEST b/MANIFEST index 80a8f6b7..f95cf38e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1057,14 +1057,6 @@ t/data/qc/references/Homo_sapiens/1000Genomes_hs37d5/all/fasta/hs37d5.fa t/data/qc/references/PhiX/default/all/fasta/PhiX.fasta t/data/qc/samplesheet_14043.csv t/data/qc/samplesheet_14353.csv -t/data/qc_outcomes/fixtures/000-mqc_library_outcome_dict.yml -t/data/qc_outcomes/fixtures/000-mqc_outcome_dict.yml -t/data/qc_outcomes/fixtures/000-uqc_outcome_dict.yml -t/data/qc_outcomes/fixtures/200-seq_component.yml -t/data/qc_outcomes/fixtures/300-seq_component_composition.yml -t/data/qc_outcomes/fixtures/300-seq_composition.yml -t/data/qc_outcomes/fixtures/400-mqc_library_outcome_ent.yml -t/data/qc_outcomes/fixtures/README t/data/release/config/archive_off/product_release.yml t/data/release/config/archive_on/product_release.yml t/data/release/config/bqsr_off/product_release.yml diff --git a/lib/npg_pipeline/base.pm b/lib/npg_pipeline/base.pm index 0fe98efb..c1490e26 100644 --- a/lib/npg_pipeline/base.pm +++ b/lib/npg_pipeline/base.pm @@ -60,22 +60,6 @@ within npg_pipeline package =head2 npg_tracking_schema -=head2 qc_schema - -An attribute caching a connection to a QC database. -The attribute is allowed to be undefined and is implicitly undefined -since no default or build method is provided. This is done in order -to prevent the automatic connection to a database in child classes. - -=cut - -has 'qc_schema' => ( - metaclass => 'NoGetopt', - isa => 'Maybe[npg_qc::Schema]', - is => 'ro', - required => 0, -); - =head2 flowcell_id =head2 tracking_run diff --git a/lib/npg_pipeline/product.pm b/lib/npg_pipeline/product.pm index 91663f9c..06cab424 100644 --- a/lib/npg_pipeline/product.pm +++ b/lib/npg_pipeline/product.pm @@ -598,116 +598,6 @@ sub chunk_as_product { return __PACKAGE__->new($ref); } - -=head2 final_seqqc_objs - - Returns a list of DBIx row objects representing a sequencing QC outcomes - for component lanes of this product. If not all lanes have a final outcome, - an empty list is returned. - - npg_qc::Schema object argument is required. - - use List::MoreUtils qw/all any/; - my @seq_qc_objs = $p->final_seqqc_objs($schema); - my $passed = @seq_qc_objs && (all { $_->is_accepted } @seq_qc_objs); - my $failed = !@seq_qc_objs || (any { $_->is_rejected } @seq_qc_objs); -=cut - -sub final_seqqc_objs { - my ($self, $schema) = @_; - - $schema or croak 'qc schema argument is required'; - - my @lp = $self->lanes_as_products; - my @seqqc = grep { $_->has_final_outcome } - $schema->resultset('MqcOutcomeEnt') - ->search_via_composition([map{$_->composition}@lp])->all; - if (@lp != @seqqc) { - return; - } - - return @seqqc; -} - -=head2 seqqc_objs - - Returns a list of DBIx row objects representing a sequencing QC outcomes - for component lanes of this product, even if not all outcomes are final. - - npg_qc::Schema object argument is required. - - use List::MoreUtils qw/all any/; - my @seq_qc_objs = $p->seqqc_objs($schema); - #these may or may not be final outcomes - my $passed = @seq_qc_objs && (all { $_->is_accepted } @seq_qc_objs); - my $failed = !@seq_qc_objs || (any { $_->is_rejected } @seq_qc_objs); - -=cut - -sub seqqc_objs { - my ($self, $schema) = @_; - - $schema or croak 'qc schema argument is required'; - - my @lp = $self->lanes_as_products; - my @seqqc = $schema->resultset('MqcOutcomeEnt') - ->search_via_composition([map{$_->composition}@lp])->all; - if (@lp != @seqqc) { - return; - } - return @seqqc; -} - -=head2 final_libqc_obj - - Returns a DBIx row object representing a final library QC outcome. - Returns an undefined value if the final library QC outcome is - not available for this product. - - npg_qc::Schema object argument is required. - - my $lib_qc_obj = $p->final_libqc_obj($schema); - print $lib_qc_obj->is_accepted; - -=cut - -sub final_libqc_obj { - my ($self, $schema) = @_; - - $schema or croak 'qc schema argument is required'; - - my $libqc = $schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition([$self->composition])->next; - if ($libqc && $libqc->has_final_outcome) { - return $libqc; - } - - return; -} - -=head2 libqc_obj - - Returns a DBIx row object representing the library QC outcome. - Returns an undefined value if the library QC outcome is - not available for this product. - - npg_qc::Schema object argument is required. - - my $lib_qc_obj = $p->libqc_obj($schema); - -=cut - -sub libqc_obj { - my ($self, $schema) = @_; - - $schema or croak 'qc schema argument is required'; - - return $schema->resultset('MqcLibraryOutcomeEnt') - ->search_via_composition([$self->composition])->next; -} - - - __PACKAGE__->meta->make_immutable; 1; diff --git a/lib/npg_pipeline/validation.pm b/lib/npg_pipeline/validation.pm index 3296d9f8..1e106ac2 100644 --- a/lib/npg_pipeline/validation.pm +++ b/lib/npg_pipeline/validation.pm @@ -403,9 +403,11 @@ a database connection. =cut -has '+qc_schema' => ( - lazy => 1, - builder => '_build_qc_schema', +has 'qc_schema' => ( + isa => 'npg_qc::Schema', + is => 'ro', + required => 0, + lazy_build => 1, ); sub _build_qc_schema { return npg_qc::Schema->connect(); diff --git a/t/15-product-release.t b/t/15-product-release.t index cf3901e1..08db9308 100644 --- a/t/15-product-release.t +++ b/t/15-product-release.t @@ -24,11 +24,6 @@ Log::Log4perl->easy_init({level => $INFO, with 'npg_testing::db'; } -# See README in fixtures for a description of the test data. -my $qc = TestDB->new ( - sqlite_utf8_enabled => 1, - verbose => 0)->create_test_db('npg_qc::Schema'); - local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX/' . 'Data/Intensities/BAM_basecalls_20180805-013153/' . @@ -49,8 +44,7 @@ subtest 'expected_files' => sub { (conf_path => "t/data/release/config/archive_on", runfolder_path => $runfolder_path, id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); + timestamp => $timestamp); my $product = shift @{$archiver->products->{data_products}}; @@ -85,8 +79,7 @@ subtest 'expected_unaligned_files' => sub { (conf_path => "t/data/release/config/archive_on", runfolder_path => $runfolder_path, id_run => 26291, - timestamp => $timestamp, - qc_schema => $qc); + timestamp => $timestamp); my $product = shift @{$archiver->products->{data_products}}; diff --git a/t/data/qc_outcomes/fixtures/000-mqc_library_outcome_dict.yml b/t/data/qc_outcomes/fixtures/000-mqc_library_outcome_dict.yml deleted file mode 100644 index de310d9f..00000000 --- a/t/data/qc_outcomes/fixtures/000-mqc_library_outcome_dict.yml +++ /dev/null @@ -1,32 +0,0 @@ ---- -- id_mqc_library_outcome : 1 - short_desc : 'Accepted preliminary' - long_desc : 'Library is preliminary accepted.' - iscurrent : 1 - isvisible : 1 -- id_mqc_library_outcome : 2 - short_desc : 'Rejected preliminary' - long_desc : 'Library is preliminary rejected.' - iscurrent : 1 - isvisible : 1 -- id_mqc_library_outcome : 3 - short_desc : 'Accepted final' - long_desc : 'Library has been accepted as a final decision.' - iscurrent : 1 - isvisible : 1 -- id_mqc_library_outcome : 4 - short_desc : 'Rejected final' - long_desc : 'Library has been rejected as a final decision.' - iscurrent : 1 - isvisible : 1 -- id_mqc_library_outcome : 5 - short_desc : 'Undecided' - long_desc : 'Library has no current outcome.' - iscurrent : 1 - isvisible : 1 -- id_mqc_library_outcome : 6 - short_desc : 'Undecided final' - long_desc : 'Library has no outcome as final decision.' - iscurrent : 1 - isvisible : 1 - diff --git a/t/data/qc_outcomes/fixtures/000-mqc_outcome_dict.yml b/t/data/qc_outcomes/fixtures/000-mqc_outcome_dict.yml deleted file mode 100644 index 65481123..00000000 --- a/t/data/qc_outcomes/fixtures/000-mqc_outcome_dict.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -- id_mqc_outcome : 1 - short_desc : 'Accepted preliminary' - long_desc : 'Lane is preliminary accepted.' - iscurrent : 1 - isvisible : 1 -- id_mqc_outcome : 2 - short_desc : 'Rejected preliminary' - long_desc : 'Lane is preliminary rejected.' - iscurrent : 1 - isvisible : 1 -- id_mqc_outcome : 3 - short_desc : 'Accepted final' - long_desc : 'Lane has been accepted as a final decision.' - iscurrent : 1 - isvisible : 1 -- id_mqc_outcome : 4 - short_desc : 'Rejected final' - long_desc : 'Lane has been rejected as a final decision.' - iscurrent : 1 - isvisible : 1 -- id_mqc_outcome : 5 - short_desc : 'Undecided' - long_desc : 'Lane has no current outcome.' - iscurrent : 1 - isvisible : 1 - diff --git a/t/data/qc_outcomes/fixtures/000-uqc_outcome_dict.yml b/t/data/qc_outcomes/fixtures/000-uqc_outcome_dict.yml deleted file mode 100755 index 320ec47e..00000000 --- a/t/data/qc_outcomes/fixtures/000-uqc_outcome_dict.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -- id_uqc_outcome : 1 - short_desc : 'Accepted' - long_desc : 'End user would like to utilise the product' - iscurrent : 1 - isvisible : 1 -- id_uqc_outcome : 2 - short_desc : 'Rejected' - long_desc : 'End user will not utilise the product' - iscurrent : 1 - isvisible : 1 -- id_uqc_outcome : 3 - short_desc : 'Undecided' - long_desc : 'No decision, follow mqc outcome when determining utility' - iscurrent : 1 - isvisible : 1 \ No newline at end of file diff --git a/t/data/qc_outcomes/fixtures/200-seq_component.yml b/t/data/qc_outcomes/fixtures/200-seq_component.yml deleted file mode 100644 index f73ea514..00000000 --- a/t/data/qc_outcomes/fixtures/200-seq_component.yml +++ /dev/null @@ -1,158 +0,0 @@ ---- -- digest: 64013f487492f493d06c360266c75179fca9e5e3bd9cdf4715656c05e484d04a - id_run: 26291 - id_seq_component: 1 - position: 1 - subset: ~ - tag_index: 10 -- digest: 1575e3fa8cfc5b0684045f1b2a132076e9ac088f630c90790fbe36f7e0589d00 - id_run: 26291 - id_seq_component: 2 - position: 2 - subset: ~ - tag_index: 10 -- digest: f1c6a2b1a081645eceec70070e0900ed11e4ef7527cdbe5311738629d759e97b - id_run: 26291 - id_seq_component: 3 - position: 1 - subset: ~ - tag_index: 4 -- digest: 247284cbb9248db81a44b4ea1dba9e6abff3137f99c2f4a138555b120f5eaf8c - id_run: 26291 - id_seq_component: 4 - position: 2 - subset: ~ - tag_index: 4 -- digest: cdf72931d7b0ccce78922cec587b0bfa1c6ba0bad8c7ecb217d48af7c0e08a19 - id_run: 26291 - id_seq_component: 5 - position: 1 - subset: ~ - tag_index: 7 -- digest: ac2b116498fe0f7085a75f6f2f4bdb8e5ffadf7068d724fb08771cd6302b24e3 - id_run: 26291 - id_seq_component: 6 - position: 2 - subset: ~ - tag_index: 7 -- digest: a8ee737489b8ae763c3e53056ca2638da44859177584ba2ba7abf73168c55f5e - id_run: 26291 - id_seq_component: 7 - position: 1 - subset: ~ - tag_index: 8 -- digest: b4178cdaf8d6f7d5c1c1179a524e1489ca89a45eea7aad99c96e9706a5fc8ec8 - id_run: 26291 - id_seq_component: 8 - position: 2 - subset: ~ - tag_index: 8 -- digest: c957145416114cd41df343db734e2de29921fb6aac1c4494ac8ab738d69a714a - id_run: 26291 - id_seq_component: 9 - position: 1 - subset: ~ - tag_index: 1 -- digest: 78d0a76c780c449ac12645d642e7f98888a895f400f4a879fe7f28455d6a602e - id_run: 26291 - id_seq_component: 10 - position: 2 - subset: ~ - tag_index: 1 -- digest: 5b6320cc7f823853bb4e4373bd99156957e0162fd56c594160678237f148b08e - id_run: 26291 - id_seq_component: 11 - position: 1 - subset: ~ - tag_index: 9 -- digest: 4b9361de5a2e4f739a3a5f29c5c85a6d1765ba92f6516c36997a2f385e1cc4d8 - id_run: 26291 - id_seq_component: 12 - position: 2 - subset: ~ - tag_index: 9 -- digest: 8dd53961be4c48398a33239805839bbcfef01198f46d5f1d847c52da2483f852 - id_run: 26291 - id_seq_component: 13 - position: 1 - subset: ~ - tag_index: 12 -- digest: 9099df4b8546270b01d1fe62288bd142ac7f0121995fcd84a13700ad29735496 - id_run: 26291 - id_seq_component: 14 - position: 2 - subset: ~ - tag_index: 12 -- digest: 2172da71cf35ae59316f93b1f8e45b28e7f2f1a53c641d956ba8be5611623ea5 - id_run: 26291 - id_seq_component: 15 - position: 1 - subset: ~ - tag_index: 11 -- digest: bf51062197cb45b27beaa5901d2c2f7ab5ecf9370e1955873c4a4f07bcef1dc9 - id_run: 26291 - id_seq_component: 16 - position: 2 - subset: ~ - tag_index: 11 -- digest: a142d0df20a8362a241e571ed480b741a192a5f70108ee3af41cf1d701365b06 - id_run: 26291 - id_seq_component: 17 - position: 1 - subset: ~ - tag_index: 6 -- digest: f05db0e533f9072826078aa3ee34e60c7638a77c58135427a7cf54ec8d8fdaeb - id_run: 26291 - id_seq_component: 18 - position: 2 - subset: ~ - tag_index: 6 -- digest: b62e703d047c360a5830bd46d7f48439efb25e6852302fd21d56778c26a35b76 - id_run: 26291 - id_seq_component: 19 - position: 1 - subset: ~ - tag_index: 2 -- digest: 4e18a830a0756c837343aae86871259481523173486c6e94a5cf0f0ac3b16561 - id_run: 26291 - id_seq_component: 20 - position: 2 - subset: ~ - tag_index: 2 -- digest: ad5ec898f6e5407f5a80ec68c0967acf20a5e4809d21cd29b5b2d39c0f731534 - id_run: 26291 - id_seq_component: 21 - position: 1 - subset: ~ - tag_index: 5 -- digest: 7458fe6b0b88f8fefd75f21862bed23e7b342caf2d51a726a324a228613c677f - id_run: 26291 - id_seq_component: 22 - position: 2 - subset: ~ - tag_index: 5 -- digest: f4013ca42106e02a488361206d845005a21c0917d7b7dbcb6a878f7322194c2a - id_run: 26291 - id_seq_component: 23 - position: 1 - subset: ~ - tag_index: 3 -- digest: 28f8a790af34647bc75d61b07e2506b84612dfd58ada09da2edc5bb6eead8873 - id_run: 26291 - id_seq_component: 24 - position: 2 - subset: ~ - tag_index: 3 -- digest: cd87cabb80ce5105c7924a3bc56a383afb7b72afda6b5867856373403b0913a2 - id_run: 26291 - id_seq_component: 25 - position: 1 - subset: ~ - tag_index: ~ -- digest: 98af9d7a81091699a06cfd97624f0049c87fca8229c8133fda245caeff0a194c - id_run: 26291 - id_seq_component: 26 - position: 2 - subset: ~ - tag_index: ~ - diff --git a/t/data/qc_outcomes/fixtures/300-seq_component_composition.yml b/t/data/qc_outcomes/fixtures/300-seq_component_composition.yml deleted file mode 100644 index bb1a9004..00000000 --- a/t/data/qc_outcomes/fixtures/300-seq_component_composition.yml +++ /dev/null @@ -1,106 +0,0 @@ ---- -- id_seq_comcom: 1 - id_seq_component: 1 - id_seq_composition: 1 - size: 2 -- id_seq_comcom: 2 - id_seq_component: 2 - id_seq_composition: 1 - size: 2 -- id_seq_comcom: 3 - id_seq_component: 3 - id_seq_composition: 2 - size: 2 -- id_seq_comcom: 4 - id_seq_component: 4 - id_seq_composition: 2 - size: 2 -- id_seq_comcom: 5 - id_seq_component: 5 - id_seq_composition: 3 - size: 2 -- id_seq_comcom: 6 - id_seq_component: 6 - id_seq_composition: 3 - size: 2 -- id_seq_comcom: 7 - id_seq_component: 7 - id_seq_composition: 4 - size: 2 -- id_seq_comcom: 8 - id_seq_component: 8 - id_seq_composition: 4 - size: 2 -- id_seq_comcom: 9 - id_seq_component: 9 - id_seq_composition: 5 - size: 2 -- id_seq_comcom: 10 - id_seq_component: 10 - id_seq_composition: 5 - size: 2 -- id_seq_comcom: 11 - id_seq_component: 11 - id_seq_composition: 6 - size: 2 -- id_seq_comcom: 12 - id_seq_component: 12 - id_seq_composition: 6 - size: 2 -- id_seq_comcom: 13 - id_seq_component: 13 - id_seq_composition: 7 - size: 2 -- id_seq_comcom: 14 - id_seq_component: 14 - id_seq_composition: 7 - size: 2 -- id_seq_comcom: 15 - id_seq_component: 15 - id_seq_composition: 8 - size: 2 -- id_seq_comcom: 16 - id_seq_component: 16 - id_seq_composition: 8 - size: 2 -- id_seq_comcom: 17 - id_seq_component: 17 - id_seq_composition: 9 - size: 2 -- id_seq_comcom: 18 - id_seq_component: 18 - id_seq_composition: 9 - size: 2 -- id_seq_comcom: 19 - id_seq_component: 19 - id_seq_composition: 10 - size: 2 -- id_seq_comcom: 20 - id_seq_component: 20 - id_seq_composition: 10 - size: 2 -- id_seq_comcom: 21 - id_seq_component: 21 - id_seq_composition: 11 - size: 2 -- id_seq_comcom: 22 - id_seq_component: 22 - id_seq_composition: 11 - size: 2 -- id_seq_comcom: 23 - id_seq_component: 23 - id_seq_composition: 12 - size: 2 -- id_seq_comcom: 24 - id_seq_component: 24 - id_seq_composition: 12 - size: 2 -- id_seq_comcom: 25 - id_seq_component: 25 - id_seq_composition: 13 - size: 1 -- id_seq_comcom: 26 - id_seq_component: 26 - id_seq_composition: 14 - size: 1 - diff --git a/t/data/qc_outcomes/fixtures/300-seq_composition.yml b/t/data/qc_outcomes/fixtures/300-seq_composition.yml deleted file mode 100644 index 81d1f183..00000000 --- a/t/data/qc_outcomes/fixtures/300-seq_composition.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- -- digest: d00e47ab46e2b4e5cbf1d7d67a5a0f4f3f5ca6c14c8c9994fa7b1cb5b83505c2 - id_seq_composition: 1 - size: 2 -- digest: 40ec8ffb930b2e661e5a496a263dcf09bb096cd85508f9bac1f5e32298bb3381 - id_seq_composition: 2 - size: 2 -- digest: 477c2257c18c6895320f532f347b51133e4126dded129c070488988ca65fa4ea - id_seq_composition: 3 - size: 2 -- digest: af6877094c0031f61ba6847a5d3f14d891c00a40ca660cb95571d4e2df102cca - id_seq_composition: 4 - size: 2 -- digest: b65be328691835deeff44c4025fadecd9af6512c10044754dd2161d8a7c85000 - id_seq_composition: 5 - size: 2 -- digest: b5a2c4b928e74dedf08adb31b558849ab927bb4ad60636554414d4bcc2d924ea - id_seq_composition: 6 - size: 2 -- digest: 333ecb63f21d80de0c2affc0458e168f79f77ee9cf26771b655e17220e46cc50 - id_seq_composition: 7 - size: 2 -- digest: 446d78a664d9939cd3e603a133e43f22b99b3b35e2ec893c5f9b6e0d1c00a1a7 - id_seq_composition: 8 - size: 2 -- digest: 654571abbf002fe3db014b1886bc676d54325816c3464e855ed3fe234e4ab15c - id_seq_composition: 9 - size: 2 -- digest: e7acb7b9924267e06abcaf2f0ceb76e9c9e0692908d04d4edfac4a8dc35843c0 - id_seq_composition: 10 - size: 2 -- digest: a3649dc48ec3511ad99817086e84ceb05df5d5749c45e597517c2b3e3cebd0e8 - id_seq_composition: 11 - size: 2 -- digest: 05858d03dadcd624f4c33c8766828f89fd44a3cc67582aa68a8dc257e95bd519 - id_seq_composition: 12 - size: 2 -- digest: ec20309571a4ee83d19cbec42a4837e33a3361881d781acce2bc9b88d3a4b763 - id_seq_composition: 13 - size: 1 -- digest: f14be2eeb5fd199883138473f915cdf9bd2b66bda5592e122a4b4b9e5e3110ad - id_seq_composition: 14 - size: 1 - diff --git a/t/data/qc_outcomes/fixtures/400-mqc_library_outcome_ent.yml b/t/data/qc_outcomes/fixtures/400-mqc_library_outcome_ent.yml deleted file mode 100644 index a1651e89..00000000 --- a/t/data/qc_outcomes/fixtures/400-mqc_library_outcome_ent.yml +++ /dev/null @@ -1,121 +0,0 @@ ---- -- id_mqc_library_outcome_ent: 1 - id_mqc_outcome: 4 - id_run: ~ - id_seq_composition: 1 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 2 - id_mqc_outcome: 4 - id_run: ~ - id_seq_composition: 2 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 3 - id_mqc_outcome: 1 - id_run: ~ - id_seq_composition: 3 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 4 - id_mqc_outcome: 2 - id_run: ~ - id_seq_composition: 4 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 5 - id_mqc_outcome: 1 - id_run: ~ - id_seq_composition: 5 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 6 - id_mqc_outcome: 3 - id_run: ~ - id_seq_composition: 6 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 7 - id_mqc_outcome: 6 - id_run: ~ - id_seq_composition: 7 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 8 - id_mqc_outcome: 5 - id_run: ~ - id_seq_composition: 8 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 9 - id_mqc_outcome: 6 - id_run: ~ - id_seq_composition: 9 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 10 - id_mqc_outcome: 2 - id_run: ~ - id_seq_composition: 10 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 11 - id_mqc_outcome: 5 - id_run: ~ - id_seq_composition: 11 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 -- id_mqc_library_outcome_ent: 12 - id_mqc_outcome: 3 - id_run: ~ - id_seq_composition: 12 - last_modified: 2018-08-14 12:06:28 - modified_by: 'user' - position: ~ - reported: ~ - tag_index: ~ - username: u1 diff --git a/t/data/qc_outcomes/fixtures/400-mqc_outcome_ent.yml b/t/data/qc_outcomes/fixtures/400-mqc_outcome_ent.yml deleted file mode 100644 index c4588de0..00000000 --- a/t/data/qc_outcomes/fixtures/400-mqc_outcome_ent.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -- id_mqc_outcome: 3 - id_mqc_outcome_ent: 1 - id_run: 26291 - id_seq_composition: 13 - last_modified: 2019-03-18 15:54:32 - modified_by: ~ - position: 1 - reported: ~ - username: ~ -- id_mqc_outcome: 3 - id_mqc_outcome_ent: 2 - id_run: 26291 - id_seq_composition: 14 - last_modified: 2019-03-18 15:54:32 - modified_by: ~ - position: 2 - reported: ~ - username: ~ - diff --git a/t/data/qc_outcomes/fixtures/README b/t/data/qc_outcomes/fixtures/README deleted file mode 100644 index 3f8af79b..00000000 --- a/t/data/qc_outcomes/fixtures/README +++ /dev/null @@ -1,18 +0,0 @@ -Run 26291 has the following library manual QC results: - -# 26291:1:1;26291:2:1 => 1 # 1: Accepted preliminary -# 26291:1:2;26291:2:2 => 2 # 2: Rejected preliminary -# 26291:1:3;26291:2:3 => 3 # 3: Accepted final -# 26291:1:4;26291:2:4 => 4 # 4: Rejected final -# 26291:1:5;26291:2:5 => 5 # 5: Undecided -# 26291:1:6;26291:2:6 => 6 # 6: Undecided final -# 26291:1:7;26291:2:7 => 1 -# 26291:1:8;26291:2:8 => 2 -# 26291:1:9;26291:2:9 => 3 # 3: Accepted final -# 26291:1:10;26291:2:10 => 4 # 4: Rejected final -# 26291:1:11;26291:2:11 => 5 -# 26291:1:12;26291:2:12 => 6 - -These results are used to test that pipeline jobs take the -correct action when presented with data with a range of -library QC outcomes. From 263d82803c37e2e77aed3d33a1f0f22029ac6cda Mon Sep 17 00:00:00 2001 From: jmtcsngr Date: Tue, 6 Feb 2024 16:18:39 +0000 Subject: [PATCH 08/18] update docs after deletion of validation::s3 --- bin/npg_receipt4run_is_deletable | 3 --- 1 file changed, 3 deletions(-) diff --git a/bin/npg_receipt4run_is_deletable b/bin/npg_receipt4run_is_deletable index d0ff8c4a..a24b271a 100755 --- a/bin/npg_receipt4run_is_deletable +++ b/bin/npg_receipt4run_is_deletable @@ -127,9 +127,6 @@ Uses data from ml warehouse to generate a list of externally acknowledged products. The list is written to a compressed file. The path of the new file is as given by the --receipt_path plus the .bz2 extension. -This file will be used by the npg_run_is_deletable -script, see npg_pipeline::validation::s3. - =head1 DESCRIPTION npg_receipt4run_is_deletable --help From e25e0be5882e1099a5b5bbc40a930523ec770e60 Mon Sep 17 00:00:00 2001 From: jmtcsngr Date: Tue, 6 Feb 2024 16:19:15 +0000 Subject: [PATCH 09/18] update loggers after deletion of validation::s3 --- bin/npg_run_is_deletable | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/npg_run_is_deletable b/bin/npg_run_is_deletable index 6ed1450a..396990e5 100755 --- a/bin/npg_run_is_deletable +++ b/bin/npg_run_is_deletable @@ -19,7 +19,6 @@ my $their_log_level = $verbose ? 'DEBUG' : 'WARN'; ##no critic (ValuesAndExpressions::ProhibitImplicitNewlines) my $log4perl_config = qq( log4perl.logger = $my_log_level, A1 - log4perl.category.npg_pipeline.validation.s3 = $their_log_level, A1 log4perl.category.npg_pipeline.validation.irods = $their_log_level, A1 log4perl.category.npg_pipeline.validation.autoqc = $their_log_level, A1 log4perl.logger.WTSI.NPG.iRODS = OFF, A1 From 326b40d18ba9534ffbf7ce0da5452c2e743c21ba Mon Sep 17 00:00:00 2001 From: jmtcsngr Date: Tue, 6 Feb 2024 17:03:13 +0000 Subject: [PATCH 10/18] update product release docs after removing s3 --- lib/npg_pipeline/product/release.pm | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/npg_pipeline/product/release.pm b/lib/npg_pipeline/product/release.pm index 56f3f6ce..e240921b 100644 --- a/lib/npg_pipeline/product/release.pm +++ b/lib/npg_pipeline/product/release.pm @@ -106,7 +106,6 @@ sub is_release_data { Arg [2] : Str, type of release Example : $obj->is_for_release($product, 'irods'); - $obj->is_for_release($product, 's3'); Description: Return true if the product is to be released via the mechanism defined by the second argument. @@ -376,10 +375,6 @@ product release. The configuration file gives per-study settings and a default to be used for any study without a specific configuration. - S3: - enable: S3 release enabled if true. - url: The S3 bucket URL to send to. - irods: enable: iRODS release enabled if true. @@ -387,24 +382,15 @@ e.g. --- default: - s3: - enable: false - url: null irods: enable: true study: - study_id: "5290" - s3: - enable: true - url: "s3://product_bucket" irods: enable: false - study_id: "1000" - s3: - enable: false - url: null irods: enable: true From bb370b9924a1e658335e97b99d357bc123d93d3a Mon Sep 17 00:00:00 2001 From: jmtcsngr Date: Wed, 7 Feb 2024 10:22:20 +0000 Subject: [PATCH 11/18] check for receipts deprecated at deletion we don't need to check for receipts when validating for deletion the script is not necessary from now on. --- MANIFEST | 1 - bin/npg_receipt4run_is_deletable | 198 ------------------------------- 2 files changed, 199 deletions(-) delete mode 100755 bin/npg_receipt4run_is_deletable diff --git a/MANIFEST b/MANIFEST index 80a8f6b7..e5027ee9 100644 --- a/MANIFEST +++ b/MANIFEST @@ -9,7 +9,6 @@ bin/npg_pipeline_post_qc_review bin/npg_pipeline_preexec_references bin/npg_pipeline_script_must_be_unique_runner bin/npg_pipeline_seqchksum_comparator -bin/npg_receipt4run_is_deletable bin/npg_run_is_deletable Build.PL Changes diff --git a/bin/npg_receipt4run_is_deletable b/bin/npg_receipt4run_is_deletable deleted file mode 100755 index a24b271a..00000000 --- a/bin/npg_receipt4run_is_deletable +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use FindBin qw($Bin $Script); -use lib ( -d "$Bin/../lib/perl5" ? "$Bin/../lib/perl5" : "$Bin/../lib" ); -use Log::Log4perl qw{:levels}; -use Getopt::Long; -use Readonly; -use File::Temp qw(tempdir); -use DateTime; -use Pod::Usage; -use File::Slurp; -use Carp; -use File::Copy; - -use WTSI::DNAP::Warehouse::Schema; - -our $VERSION = '0'; - -Readonly::Scalar my $STATUS_SUCCESS => 'SUCCESS'; -Readonly::Scalar my $STATUS_PASS => 'PASS'; -Readonly::Scalar my $RECEIPT_DELIM => qq[\t]; - -my $help; -my $file_path; - -GetOptions ( - 'help' => \$help, - 'receipt_path=s' => \$file_path, - ); -if ($help) { pod2usage(0); } - - -my $layout = '%d %-5p %c - %m%n'; -Log::Log4perl->easy_init({layout => $layout, - level => $INFO, - utf8 => 1}); -my $logger = Log::Log4perl->get_logger(); - -$file_path or - ($logger->error('--receipt_path argument is required') and exit 1); -$logger->info("Receipt file to use $file_path"); - -my $schema = WTSI::DNAP::Warehouse::Schema->connect(); - -my $rs = $schema->resultset('IseqExternalProductMetric')->search( - {manifest_upload_status => $STATUS_SUCCESS, - format_validation => $STATUS_PASS}, - {column => qw(supplier_sample_name file_name md5_staging)} -); - -my $count = $rs->count; -if ($count == 0) { - $logger->info('No receipts available, exiting'); - exit 0; -} else { - $logger->info("Receipts for $count products are available"); -} - -my @lines = (); -push @lines, join $RECEIPT_DELIM, ('Bucket key', 'WSI_MD5', 'SBG_MD5', 'Match?'); -while (my $row = $rs->next()) { - push @lines, join $RECEIPT_DELIM, - (join q[/], $row->supplier_sample_name, $row->file_name), - $row->md5_staging, - $row->md5_staging, - 'correct'; -} -@lines = map { $_ . qq[\n] } @lines; - -my $tdir = tempdir( CLEANUP => 1 ); -my $filename = "$tdir/receipt"; -$logger->info("Writing to temp file $filename"); -write_file($filename, @lines); -0 == system "bzip2 $filename" or croak "Failed to compress $filename"; -$filename .= '.bz2'; - -my $new_path; -my $compressed_file_path = $file_path . '.bz2'; -if (-e $compressed_file_path) { - if (not -f $compressed_file_path) { - croak "$compressed_file_path exists and is not a file"; - } - $new_path = join q[.], - $file_path, DateTime->now()->strftime(q[%Y%m%d-%T]), 'bz2'; - move($compressed_file_path, $new_path) or croak - "Failed to move $compressed_file_path to $new_path"; -} -move($filename, $compressed_file_path) or croak - "Failed to move $filename to $compressed_file_path"; -$new_path && $logger->info("Moved existing $compressed_file_path to $new_path"); -$logger->info("Created new $compressed_file_path"); - -exit 0; - -__END__ - -=head1 NAME - -npg_receipt4run_is_deletable - -=head1 USAGE - -npg_receipt4run_is_deletable --help - -npg_receipt4run_is_deletable --receipt_path - -=head1 REQUIRED ARGUMENTS - ---receipt_path file path of the receipt - -=head1 OPTIONS - ---help ---receipt_path - -=head1 EXIT STATUS - -0 - -=head1 CONFIGURATION - -=head1 SYNOPSIS - -Uses data from ml warehouse to generate a list of externally -acknowledged products. The list is written to a compressed file. The path -of the new file is as given by the --receipt_path plus the .bz2 extension. - -=head1 DESCRIPTION - -npg_receipt4run_is_deletable --help -npg_receipt4run_is_deletable --file_path - -=head1 SUBROUTINES/METHODS - -=head1 DIAGNOSTICS - -=head1 CONFIGURATION AND ENVIRONMENT - -=head1 DEPENDENCIES - -=over - -=item strict - -=item warnings - -=item lib - -=item FindBin - -=item Log::Log4perl - -=item Getopt::Long - -=item Readonly - -=item File::Temp - -=item DateTime - -=item Pod::Usage - -=item File::Slurp - -=item Carp - -=item File::Copy - -=item WTSI::DNAP::Warehouse::Schema - -=back - -=head1 INCOMPATIBILITIES - -=head1 BUGS AND LIMITATIONS - -=head1 AUTHOR - -Marina Gourtovaia - -=head1 LICENSE AND COPYRIGHT - -Copyright (C) 2019 Genome Research Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . From 2a109f7dfbcec8678c5fdd7201234249e89f5cea Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Fri, 5 Jan 2024 18:25:25 +0000 Subject: [PATCH 12/18] Use one aggregation method for merges. Use st::api::lims->aggregate_libraries() method for both 'merge_lanes' and 'merge_by_library' pipeline options. --- MANIFEST | 114 +++++++----------- lib/npg_pipeline/base.pm | 97 +++++++++------ t/10-base.t | 3 +- t/10-runfolder_scaffold.t | 24 ++-- t/15-product-release.t | 12 +- .../no_cal/archive/README | 6 + .../plex0/.npg_cache_10000/26291_1#0_1.fastq} | 0 .../plex0/.npg_cache_10000/26291_1#0_2.fastq} | 0 .../26291#0.bai => lane1/plex0/26291_1#0.bai} | 0 .../26291#0.bam => lane1/plex0/26291_1#0.bam} | 0 .../plex0/26291_1#0.bam.md5} | 0 .../plex0/26291_1#0.bam_stats} | 0 .../plex0/26291_1#0.cram} | 0 .../plex0/26291_1#0.cram.crai} | 0 .../plex0/26291_1#0.cram.md5} | 0 .../plex0/26291_1#0.flagstat} | 0 .../plex0/26291_1#0.orig.seqchksum} | 0 .../plex0/26291_1#0.seqchksum} | 0 .../26291_1#0.sha512primesums512.seqchksum} | 0 .../plex0/26291_1#0.spatial_filter.stats} | 0 .../plex0/26291_1#0_F0x900.stats} | 0 .../plex0/26291_1#0_F0xB00.stats} | 0 .../plex0/26291_1#0_phix.bai} | 0 .../plex0/26291_1#0_phix.bam} | 0 .../plex0/26291_1#0_phix.bam.md5} | 0 .../plex0/26291_1#0_phix.bam_stats} | 0 .../plex0/26291_1#0_phix.cram} | 0 .../plex0/26291_1#0_phix.cram.crai} | 0 .../plex0/26291_1#0_phix.cram.md5} | 0 .../plex0/26291_1#0_phix.flagstat} | 0 .../26291_1#0_phix.markdups_metrics.txt} | 0 .../plex0/26291_1#0_phix.seqchksum} | 0 ...291_1#0_phix.sha512primesums512.seqchksum} | 0 .../plex0/26291_1#0_phix_F0x900.stats} | 0 .../plex0/26291_1#0_phix_F0xB00.stats} | 0 .../26291_1#0.alignment_filter_metrics.json} | 0 .../plex0/qc/26291_1#0.bam_flagstats.json} | 0 .../plex0/qc/26291_1#0.gc_fraction.json} | 0 .../plex0/qc/26291_1#0.insert_size.json} | 0 .../plex0/qc/26291_1#0.qX_yield.json} | 0 .../plex0/qc/26291_1#0.ref_match.json} | 0 .../plex0/qc/26291_1#0.sequence_error.json} | 0 .../plex0/qc/26291_1#0.sequence_summary.json} | 0 .../qc/26291_1#0_F0x900.samtools_stats.json} | 0 .../qc/26291_1#0_F0xB00.samtools_stats.json} | 0 .../qc/26291_1#0_phix.bam_flagstats.json} | 0 .../qc/26291_1#0_phix.sequence_summary.json} | 0 ...26291_1#0_phix_F0x900.samtools_stats.json} | 0 ...26291_1#0_phix_F0xB00.samtools_stats.json} | 0 .../.npg_cache_10000/26291#888_1.fastq | 0 .../.npg_cache_10000/26291#888_2.fastq | 0 .../no_cal/archive/plex888/26291#888.bai | 0 .../no_cal/archive/plex888/26291#888.bam | 0 .../no_cal/archive/plex888/26291#888.bam.md5 | 1 - .../archive/plex888/26291#888.bam_stats | 0 .../no_cal/archive/plex888/26291#888.cram | 0 .../archive/plex888/26291#888.cram.crai | 0 .../no_cal/archive/plex888/26291#888.cram.md5 | 1 - .../no_cal/archive/plex888/26291#888.flagstat | 0 .../plex888/26291#888.markdups_metrics.txt | 0 .../archive/plex888/26291#888.orig.seqchksum | 0 .../archive/plex888/26291#888.seqchksum | 0 .../26291#888.sha512primesums512.seqchksum | 0 .../plex888/26291#888.spatial_filter.stats | 0 .../archive/plex888/26291#888_F0x900.stats | 0 .../archive/plex888/26291#888_F0xB00.stats | 0 .../archive/plex888/qc/26291#888.adapter.json | 0 .../plex888/qc/26291#888.bam_flagstats.json | 0 .../plex888/qc/26291#888.gc_fraction.json | 0 .../plex888/qc/26291#888.insert_size.json | 0 .../plex888/qc/26291#888.qX_yield.json | 0 .../plex888/qc/26291#888.ref_match.json | 0 .../plex888/qc/26291#888.sequence_error.json | 0 .../qc/26291#888.sequence_summary.json | 0 .../qc/26291#888_F0x900.samtools_stats.json | 0 .../qc/26291#888_F0xB00.samtools_stats.json | 0 76 files changed, 135 insertions(+), 123 deletions(-) create mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/README rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/.npg_cache_10000/26291#0_1.fastq => lane1/plex0/.npg_cache_10000/26291_1#0_1.fastq} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/.npg_cache_10000/26291#0_2.fastq => lane1/plex0/.npg_cache_10000/26291_1#0_2.fastq} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.bai => lane1/plex0/26291_1#0.bai} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.bam => lane1/plex0/26291_1#0.bam} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.bam.md5 => lane1/plex0/26291_1#0.bam.md5} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.bam_stats => lane1/plex0/26291_1#0.bam_stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.cram => lane1/plex0/26291_1#0.cram} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.cram.crai => lane1/plex0/26291_1#0.cram.crai} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.cram.md5 => lane1/plex0/26291_1#0.cram.md5} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.flagstat => lane1/plex0/26291_1#0.flagstat} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.orig.seqchksum => lane1/plex0/26291_1#0.orig.seqchksum} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.seqchksum => lane1/plex0/26291_1#0.seqchksum} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.sha512primesums512.seqchksum => lane1/plex0/26291_1#0.sha512primesums512.seqchksum} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0.spatial_filter.stats => lane1/plex0/26291_1#0.spatial_filter.stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_F0x900.stats => lane1/plex0/26291_1#0_F0x900.stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_F0xB00.stats => lane1/plex0/26291_1#0_F0xB00.stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.bai => lane1/plex0/26291_1#0_phix.bai} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.bam => lane1/plex0/26291_1#0_phix.bam} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.bam.md5 => lane1/plex0/26291_1#0_phix.bam.md5} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.bam_stats => lane1/plex0/26291_1#0_phix.bam_stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.cram => lane1/plex0/26291_1#0_phix.cram} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.cram.crai => lane1/plex0/26291_1#0_phix.cram.crai} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.cram.md5 => lane1/plex0/26291_1#0_phix.cram.md5} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.flagstat => lane1/plex0/26291_1#0_phix.flagstat} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.markdups_metrics.txt => lane1/plex0/26291_1#0_phix.markdups_metrics.txt} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.seqchksum => lane1/plex0/26291_1#0_phix.seqchksum} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix.sha512primesums512.seqchksum => lane1/plex0/26291_1#0_phix.sha512primesums512.seqchksum} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix_F0x900.stats => lane1/plex0/26291_1#0_phix_F0x900.stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/26291#0_phix_F0xB00.stats => lane1/plex0/26291_1#0_phix_F0xB00.stats} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.alignment_filter_metrics.json => lane1/plex0/qc/26291_1#0.alignment_filter_metrics.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.bam_flagstats.json => lane1/plex0/qc/26291_1#0.bam_flagstats.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.gc_fraction.json => lane1/plex0/qc/26291_1#0.gc_fraction.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.insert_size.json => lane1/plex0/qc/26291_1#0.insert_size.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.qX_yield.json => lane1/plex0/qc/26291_1#0.qX_yield.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.ref_match.json => lane1/plex0/qc/26291_1#0.ref_match.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.sequence_error.json => lane1/plex0/qc/26291_1#0.sequence_error.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0.sequence_summary.json => lane1/plex0/qc/26291_1#0.sequence_summary.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0_F0x900.samtools_stats.json => lane1/plex0/qc/26291_1#0_F0x900.samtools_stats.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0_F0xB00.samtools_stats.json => lane1/plex0/qc/26291_1#0_F0xB00.samtools_stats.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0_phix.bam_flagstats.json => lane1/plex0/qc/26291_1#0_phix.bam_flagstats.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0_phix.sequence_summary.json => lane1/plex0/qc/26291_1#0_phix.sequence_summary.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0_phix_F0x900.samtools_stats.json => lane1/plex0/qc/26291_1#0_phix_F0x900.samtools_stats.json} (100%) rename t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/{plex0/qc/26291#0_phix_F0xB00.samtools_stats.json => lane1/plex0/qc/26291_1#0_phix_F0xB00.samtools_stats.json} (100%) delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_1.fastq delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_2.fastq delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bai delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam.md5 delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam_stats delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.crai delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.md5 delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.flagstat delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.markdups_metrics.txt delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.orig.seqchksum delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.seqchksum delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.sha512primesums512.seqchksum delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.spatial_filter.stats delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0x900.stats delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0xB00.stats delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.adapter.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.bam_flagstats.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.gc_fraction.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.insert_size.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.qX_yield.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.ref_match.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_error.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_summary.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0x900.samtools_stats.json delete mode 100644 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0xB00.samtools_stats.json diff --git a/MANIFEST b/MANIFEST index e5027ee9..0606f6ba 100644 --- a/MANIFEST +++ b/MANIFEST @@ -286,6 +286,7 @@ t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_2018 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/26291_2#9.bam t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/26291_2.spatial_filter t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/26291_2.stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/README t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/26291.alllanes.seqchksum t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/26291.allprods.seqchksum t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/.npg_cache_10000/26291_1_1.fastq @@ -318,49 +319,49 @@ t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_2018 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane2/qc/26291_2.tag_metrics.json t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane2/qc/26291_2.upstream_tags.json t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane2/tileviz.html -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/.npg_cache_10000/26291#0_1.fastq -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/.npg_cache_10000/26291#0_2.fastq -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bai -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam.md5 -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam_stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram.crai -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram.md5 -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.flagstat -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.orig.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.sha512primesums512.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.spatial_filter.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_F0x900.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_F0xB00.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bai -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam.md5 -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam_stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram.crai -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram.md5 -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.flagstat -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.markdups_metrics.txt -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.sha512primesums512.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix_F0x900.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix_F0xB00.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.alignment_filter_metrics.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.bam_flagstats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.gc_fraction.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.insert_size.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.qX_yield.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.ref_match.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.sequence_error.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.sequence_summary.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_F0x900.samtools_stats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_F0xB00.samtools_stats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix.bam_flagstats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix.sequence_summary.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix_F0x900.samtools_stats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix_F0xB00.samtools_stats.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/.npg_cache_10000/26291_1#0_1.fastq +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/.npg_cache_10000/26291_1#0_2.fastq +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bai +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam.md5 +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam_stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram.crai +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram.md5 +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.flagstat +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.orig.seqchksum +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.seqchksum +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.sha512primesums512.seqchksum +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.spatial_filter.stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_F0x900.stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_F0xB00.stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bai +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam.md5 +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam_stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram.crai +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram.md5 +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.flagstat +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.markdups_metrics.txt +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.seqchksum +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.sha512primesums512.seqchksum +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix_F0x900.stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix_F0xB00.stats +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.alignment_filter_metrics.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.bam_flagstats.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.gc_fraction.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.insert_size.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.qX_yield.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.ref_match.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.sequence_error.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.sequence_summary.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_F0x900.samtools_stats.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_F0xB00.samtools_stats.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix.bam_flagstats.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix.sequence_summary.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix_F0x900.samtools_stats.json +t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix_F0xB00.samtools_stats.json t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex1/.npg_cache_10000/26291#1_1.fastq t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex1/.npg_cache_10000/26291#1_2.fastq t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex1/26291#1.bai @@ -935,33 +936,6 @@ t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_2018 t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex8/qc/26291#8_phix.sequence_summary.json t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex8/qc/26291#8_phix_F0x900.samtools_stats.json t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex8/qc/26291#8_phix_F0xB00.samtools_stats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_1.fastq -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_2.fastq -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bai -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam.md5 -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam_stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.crai -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.md5 -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.flagstat -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.markdups_metrics.txt -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.orig.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.sha512primesums512.seqchksum -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.spatial_filter.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0x900.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0xB00.stats -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.adapter.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.bam_flagstats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.gc_fraction.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.insert_size.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.qX_yield.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.ref_match.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_error.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_summary.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0x900.samtools_stats.json -t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0xB00.samtools_stats.json t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex9/.npg_cache_10000/26291#9_1.fastq t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex9/.npg_cache_10000/26291#9_2.fastq t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex9/26291#9.bai diff --git a/lib/npg_pipeline/base.pm b/lib/npg_pipeline/base.pm index 0fe98efb..a4c28161 100644 --- a/lib/npg_pipeline/base.pm +++ b/lib/npg_pipeline/base.pm @@ -5,7 +5,7 @@ use namespace::autoclean; use MooseX::Getopt::Meta::Attribute::Trait::NoGetopt; use POSIX qw(strftime); use Math::Random::Secure qw{irand}; -use List::MoreUtils qw{any}; +use List::MoreUtils qw{any uniq}; use File::Basename; use Readonly; @@ -358,49 +358,51 @@ sub _build_products { if ($self->has_product_rpt_list) { @data_lims = ($self->lims); } else { - my @positions = $self->positions; - @lane_lims = map { $self->lims4lane($_) } @positions; + @lane_lims = map { $self->lims4lane($_) } $self->positions; - if ($self->merge_lanes) { - @data_lims = $self->lims->aggregate_xlanes(@positions); - } else { + my %tag0_lims = (); + if ($self->is_indexed) { + %tag0_lims = map { $_->position => $_->create_tag_zero_object() } + grep { $_->is_pool } @lane_lims; + } + + if ($self->merge_lanes || $self->merge_by_library) { + + my $all_lims = $self->lims->aggregate_libraries(\@lane_lims); + @data_lims = @{$all_lims->{'singles'}}; # Might be empty. - my %tag0_lims = (); - if ($self->is_indexed) { - %tag0_lims = map { $_->position => $_->create_tag_zero_object() } - grep { $_->is_pool } @lane_lims; + # merge_lanes option implies a merge across all lanes. + if ($self->merge_lanes && (@lane_lims > 1)) { + $self->_check_lane_merge_is_viable( + \@lane_lims, $all_lims->{'singles'}, $all_lims->{'merges'}); } - if ($self->merge_by_library) { - my $all_lims = $self->lims->aggregate_libraries(\@lane_lims); - @data_lims = @{$all_lims->{'singles'}}; # Might be empty. - # Tag zero LIMS objects for all lanes, merged or unmerged. - push @data_lims, map { $tag0_lims{$_} } (sort keys %tag0_lims); - - if ( @{$all_lims->{'merges'}} ) { - # If the libraries are merged across a subset of lanes under analysis, - # the 'selected_lanes' flag needs to be flipped to true. - if (!$self->_selected_lanes) { - my $rpt_list = $all_lims->{'merges'}->[0]->rpt_list;; - my $num_components = - npg_tracking::glossary::composition::factory::rpt_list - ->new(rpt_list => $rpt_list) - ->create_composition()->num_components(); - if ($num_components != scalar @lane_lims) { - $self->_set_selected_lanes(1); - } + # Tag zero LIMS objects for all pooled lanes, merged or unmerged. + push @data_lims, map { $tag0_lims{$_} } (sort keys %tag0_lims); + + if ( @{$all_lims->{'merges'}} ) { + # If the libraries are merged across a subset of lanes under analysis, + # the 'selected_lanes' flag needs to be flipped to true. + if (!$self->_selected_lanes) { + my $rpt_list = $all_lims->{'merges'}->[0]->rpt_list;; + my $num_components = + npg_tracking::glossary::composition::factory::rpt_list + ->new(rpt_list => $rpt_list) + ->create_composition()->num_components(); + if ($num_components != scalar @lane_lims) { + $self->_set_selected_lanes(1); } - push @data_lims, @{$all_lims->{'merges'}}; } + push @data_lims, @{$all_lims->{'merges'}}; + } - } else { - # To keep backward-compatible order of pipeline invocations, add - # tag zero LIMS object at the end of other objects for the lane. - @data_lims = map { - exists $tag0_lims{$_->position} ? + } else { + # To keep backward-compatible order of pipeline invocations, add + # tag zero LIMS object at the end of other objects for the lane. + @data_lims = map { + exists $tag0_lims{$_->position} ? ($_->children, $tag0_lims{$_->position}) : $_ - } @lane_lims; - } + } @lane_lims; } } @@ -442,6 +444,29 @@ sub _lims_object2product { ); } +sub _check_lane_merge_is_viable { + my ($self, $lane_lims, $singles, $merges) = @_; + + my @num_plexes = uniq + map { scalar @{$_} } + map { [grep { !$_->is_control } @{$_}] } + map { [$_->children()] } @{$lane_lims}; + + my $m = 'merge_lane option is not viable: '; + if (@num_plexes > 1) { + $self->logcroak($m . 'different number of samples in lanes'); + } + if (any { !$_->is_control } @{$singles}) { + $self->logcroak($m . 'unmerged samples are present after aggregation'); + } + if (@{$merges} != $num_plexes[0]) { + $self->logcroak($m . 'number of merged samples after aggregation ' . + 'differs from the number of samples in a lane'); + } + + return 1; +} + __PACKAGE__->meta->make_immutable; 1; diff --git a/t/10-base.t b/t/10-base.t index ab83edcc..ec648467 100644 --- a/t/10-base.t +++ b/t/10-base.t @@ -96,13 +96,14 @@ subtest 'products - merging (or not) lanes' => sub { local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = 't/data/products/samplesheet_novaseq4lanes.csv'; cp 't/data/run_params/runParameters.novaseq.xml', "$rf_path/runParameters.xml"; + cp 't/data/novaseq/210111_A00513_0447_AHJ55JDSXY/RunInfo.xml', "$rf_path/RunInfo.xml"; $b = npg_pipeline::base->new(runfolder_path => $rf_path, id_run => 999); ok ($b->merge_lanes, 'merge_lanes flag is set'); lives_ok {$products = $b->products} 'products hash created for NovaSeq run'; ok (exists $products->{'lanes'}, 'products lanes key exists'); is (scalar @{$products->{'lanes'}}, 4, 'four lane product'); ok (exists $products->{'data_products'}, 'products data_products key exists'); - is (scalar @{$products->{'data_products'}}, 23, '23 data products'); + is (scalar @{$products->{'data_products'}}, 29, '29 data products'); local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = 't/data/products/samplesheet_rapidrun_nopool.csv'; cp 't/data/run_params/runParameters.hiseq.rr.xml', "$rf_path/runParameters.xml"; diff --git a/t/10-runfolder_scaffold.t b/t/10-runfolder_scaffold.t index 47c6c141..880d1abf 100644 --- a/t/10-runfolder_scaffold.t +++ b/t/10-runfolder_scaffold.t @@ -67,12 +67,13 @@ subtest 'top level scaffold' => sub { }; subtest 'product level scaffold, NovaSeq all lanes' => sub { - plan tests => 99; + plan tests => 101; my $util = t::util->new(); my $rfh = $util->create_runfolder(); my $rf_path = $rfh->{'runfolder_path'}; - fcopy 't/data/run_params/runParameters.novaseq.xml', "$rf_path/runParameters.xml"; + fcopy 't/data/run_params/runParameters.novaseq.xml', "$rf_path/runParameters.xml"; + fcopy 't/data/novaseq/210111_A00513_0447_AHJ55JDSXY/RunInfo.xml', "$rf_path/RunInfo.xml"; local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = 't/data/products/samplesheet_novaseq4lanes.csv'; my $rfs = Moose::Meta::Class->create_anon_class( @@ -95,6 +96,8 @@ subtest 'product level scaffold, NovaSeq all lanes' => sub { push @dirs, (map {join q[/], $_, 'qc'} @original); push @dirs, (map {join q[/], $_, 'tileviz_'.$_} @original); push @dirs, (map {join q[/], $_, '.npg_cache_10000'} @original); + push @dirs, (map {join q[/], $_, 'plex0/qc'} @original); + push @dirs, (map {join q[/], $_, 'plex888/qc'} @original); map { ok (-d $_, "$_ created") } map {join q[/], $apath, $_} @dirs; for my $lane (@original) { @@ -106,7 +109,7 @@ subtest 'product level scaffold, NovaSeq all lanes' => sub { like ($content, qr/No tileviz data available for this lane/, 'info exists'); } - @original = map {'plex' . $_} (0 .. 21, 888); + @original = map {'plex' . $_} (1 .. 21); @dirs = @original; push @dirs, (map {join q[/], $_, 'qc'} @original); push @dirs, (map {join q[/], $_, '.npg_cache_10000'} @original); @@ -115,16 +118,17 @@ subtest 'product level scaffold, NovaSeq all lanes' => sub { my $tileviz_index = join q[/], $apath, 'tileviz', 'index.html'; ok (-e $tileviz_index, 'tileviz index created'); my @lines = read_file($tileviz_index); - is (scalar @lines, 7, 'tileviz index contains sevel lines'); + is (scalar @lines, 7, 'tileviz index contains seven lines'); }; subtest 'product level scaffold, NovaSeq selected lanes' => sub { - plan tests => 175; + plan tests => 165; my $util = t::util->new(); my $rfh = $util->create_runfolder(); my $rf_path = $rfh->{'runfolder_path'}; - fcopy 't/data/run_params/runParameters.novaseq.xml', "$rf_path/runParameters.xml"; + fcopy 't/data/run_params/runParameters.novaseq.xml', "$rf_path/runParameters.xml"; + fcopy 't/data/novaseq/210111_A00513_0447_AHJ55JDSXY/RunInfo.xml', "$rf_path/RunInfo.xml"; local $ENV{NPG_CACHED_SAMPLESHEET_FILE} = 't/data/products/samplesheet_novaseq4lanes.csv'; my $rfs = Moose::Meta::Class->create_anon_class( @@ -149,12 +153,14 @@ subtest 'product level scaffold, NovaSeq selected lanes' => sub { push @dirs, (map {join q[/], $_, 'qc'} @original); push @dirs, (map {join q[/], $_, 'tileviz_'.$_} @original); push @dirs, (map {join q[/], $_, '.npg_cache_10000'} @original); + push @dirs, (map {join q[/], $_, 'plex0/qc'} @original); + push @dirs, (map {join q[/], $_, 'plex888/qc'} @original); map { ok (-d $_, "$_ created") } map {join q[/], $apath, $_} @dirs; @dirs = qw/lane1 lane4/; map { ok (!-e $_, "$_ not created") } map {join q[/], $apath, $_} @dirs; - @original = map {'lane2-3/plex' . $_} (0 .. 21, 888); + @original = map {'lane2-3/plex' . $_} (1 .. 21); @dirs = @original; push @dirs, (map {join q[/], $_, 'qc'} @original); push @dirs, (map {join q[/], $_, '.npg_cache_10000'} @original); @@ -172,7 +178,7 @@ subtest 'product level scaffold, NovaSeq selected lanes' => sub { "link for lane $l file is not created"); } - for my $t ( (0 .. 21, 888) ) { + for my $t ( (1 .. 21) ) { my $name = "999_2-3#${t}.cram"; my $file = "$napath/lane2-3/plex${t}/stage1/$name"; ok ((-l $file), "link for plex $t is created"); @@ -252,4 +258,4 @@ subtest 'product level scaffold, library merge for NovaSeqX' => sub { } }; -1; \ No newline at end of file +1; diff --git a/t/15-product-release.t b/t/15-product-release.t index cf3901e1..aef2e7f6 100644 --- a/t/15-product-release.t +++ b/t/15-product-release.t @@ -43,7 +43,7 @@ my $runfolder_path = 't/data/novaseq/180709_A00538_0010_BH3FCMDRXX'; my $timestamp = '20180701-123456'; subtest 'expected_files' => sub { - plan tests => 1; + plan tests => 2; my $archiver = $cls->new_object (conf_path => "t/data/release/config/archive_on", @@ -52,10 +52,11 @@ subtest 'expected_files' => sub { timestamp => $timestamp, qc_schema => $qc); - my $product = shift @{$archiver->products->{data_products}}; - my $path = "$runfolder_path/Data/Intensities/" . 'BAM_basecalls_20180805-013153/no_cal/archive/plex1'; + my $product = $archiver->products->{data_products}->[4]; + is ($product->rpt_list, '26291:1:1;26291:2:1', 'correct product'); + my @expected = sort map { "$path/$_" } ('26291#1_F0x900.stats', '26291#1_F0xB00.stats', @@ -88,8 +89,7 @@ subtest 'expected_unaligned_files' => sub { timestamp => $timestamp, qc_schema => $qc); - my $product = shift @{$archiver->products->{data_products}}; - + my $product = $archiver->products->{data_products}->[4]; my $path = "$runfolder_path/Data/Intensities/" . 'BAM_basecalls_20180805-013153/no_cal/archive/plex1'; my @expected = sort map { "$path/$_" } @@ -105,3 +105,5 @@ subtest 'expected_unaligned_files' => sub { diag explain \@observed; }; +1; + diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/README b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/README new file mode 100644 index 00000000..b673710b --- /dev/null +++ b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/README @@ -0,0 +1,6 @@ +5 January 2024 + +Both lane1 and lane2 directories are expected to contain +subdirectories plex0 and plex888 with all relevant files +and subdirectories. Only lane1/plex0 directory is present +in this testrunfolder as a representative example. diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/.npg_cache_10000/26291#0_1.fastq b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/.npg_cache_10000/26291_1#0_1.fastq similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/.npg_cache_10000/26291#0_1.fastq rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/.npg_cache_10000/26291_1#0_1.fastq diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/.npg_cache_10000/26291#0_2.fastq b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/.npg_cache_10000/26291_1#0_2.fastq similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/.npg_cache_10000/26291#0_2.fastq rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/.npg_cache_10000/26291_1#0_2.fastq diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bai b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bai similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bai rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bai diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam.md5 b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam.md5 similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam.md5 rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam.md5 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam_stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam_stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.bam_stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.bam_stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram.crai b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram.crai similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram.crai rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram.crai diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram.md5 b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram.md5 similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.cram.md5 rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.cram.md5 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.flagstat b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.flagstat similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.flagstat rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.flagstat diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.orig.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.orig.seqchksum similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.orig.seqchksum rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.orig.seqchksum diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.seqchksum similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.seqchksum rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.seqchksum diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.sha512primesums512.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.sha512primesums512.seqchksum similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.sha512primesums512.seqchksum rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.sha512primesums512.seqchksum diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.spatial_filter.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.spatial_filter.stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0.spatial_filter.stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0.spatial_filter.stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_F0x900.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_F0x900.stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_F0x900.stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_F0x900.stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_F0xB00.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_F0xB00.stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_F0xB00.stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_F0xB00.stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bai b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bai similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bai rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bai diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam.md5 b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam.md5 similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam.md5 rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam.md5 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam_stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam_stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.bam_stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.bam_stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram.crai b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram.crai similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram.crai rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram.crai diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram.md5 b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram.md5 similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.cram.md5 rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.cram.md5 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.flagstat b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.flagstat similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.flagstat rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.flagstat diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.markdups_metrics.txt b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.markdups_metrics.txt similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.markdups_metrics.txt rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.markdups_metrics.txt diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.seqchksum similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.seqchksum rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.seqchksum diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.sha512primesums512.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.sha512primesums512.seqchksum similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix.sha512primesums512.seqchksum rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix.sha512primesums512.seqchksum diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix_F0x900.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix_F0x900.stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix_F0x900.stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix_F0x900.stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix_F0xB00.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix_F0xB00.stats similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/26291#0_phix_F0xB00.stats rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/26291_1#0_phix_F0xB00.stats diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.alignment_filter_metrics.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.alignment_filter_metrics.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.alignment_filter_metrics.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.alignment_filter_metrics.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.bam_flagstats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.bam_flagstats.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.bam_flagstats.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.bam_flagstats.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.gc_fraction.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.gc_fraction.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.gc_fraction.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.gc_fraction.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.insert_size.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.insert_size.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.insert_size.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.insert_size.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.qX_yield.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.qX_yield.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.qX_yield.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.qX_yield.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.ref_match.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.ref_match.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.ref_match.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.ref_match.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.sequence_error.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.sequence_error.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.sequence_error.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.sequence_error.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.sequence_summary.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.sequence_summary.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0.sequence_summary.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0.sequence_summary.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_F0x900.samtools_stats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_F0x900.samtools_stats.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_F0x900.samtools_stats.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_F0x900.samtools_stats.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_F0xB00.samtools_stats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_F0xB00.samtools_stats.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_F0xB00.samtools_stats.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_F0xB00.samtools_stats.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix.bam_flagstats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix.bam_flagstats.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix.bam_flagstats.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix.bam_flagstats.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix.sequence_summary.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix.sequence_summary.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix.sequence_summary.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix.sequence_summary.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix_F0x900.samtools_stats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix_F0x900.samtools_stats.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix_F0x900.samtools_stats.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix_F0x900.samtools_stats.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix_F0xB00.samtools_stats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix_F0xB00.samtools_stats.json similarity index 100% rename from t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex0/qc/26291#0_phix_F0xB00.samtools_stats.json rename to t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/lane1/plex0/qc/26291_1#0_phix_F0xB00.samtools_stats.json diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_1.fastq b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_1.fastq deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_2.fastq b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/.npg_cache_10000/26291#888_2.fastq deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bai b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bai deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam.md5 b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam.md5 deleted file mode 100644 index df9edc40..00000000 --- a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam.md5 +++ /dev/null @@ -1 +0,0 @@ -d41d8cd98f00b204e9800998ecf8427e diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam_stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.bam_stats deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.crai b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.crai deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.md5 b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.md5 deleted file mode 100644 index df9edc40..00000000 --- a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.cram.md5 +++ /dev/null @@ -1 +0,0 @@ -d41d8cd98f00b204e9800998ecf8427e diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.flagstat b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.flagstat deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.markdups_metrics.txt b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.markdups_metrics.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.orig.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.orig.seqchksum deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.seqchksum deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.sha512primesums512.seqchksum b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.sha512primesums512.seqchksum deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.spatial_filter.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888.spatial_filter.stats deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0x900.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0x900.stats deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0xB00.stats b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/26291#888_F0xB00.stats deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.adapter.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.adapter.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.bam_flagstats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.bam_flagstats.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.gc_fraction.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.gc_fraction.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.insert_size.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.insert_size.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.qX_yield.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.qX_yield.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.ref_match.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.ref_match.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_error.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_error.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_summary.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888.sequence_summary.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0x900.samtools_stats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0x900.samtools_stats.json deleted file mode 100644 index e69de29b..00000000 diff --git a/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0xB00.samtools_stats.json b/t/data/novaseq/180709_A00538_0010_BH3FCMDRXX/Data/Intensities/BAM_basecalls_20180805-013153/no_cal/archive/plex888/qc/26291#888_F0xB00.samtools_stats.json deleted file mode 100644 index e69de29b..00000000 From fd5477972db94197737c673726ba989fb5e5c736 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Tue, 9 Jan 2024 18:32:29 +0000 Subject: [PATCH 13/18] Described the change --- Changes | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Changes b/Changes index 28b2b586..f587b727 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,16 @@ LIST OF CHANGES --------------- + - Use st::api::lims->aggregate_libraries() method for both 'merge_lanes' and + 'merge_by_library' pipeline options. This is a breaking change as far as + archival and deletion of NovaSeq Standard workflow data is concerned. + Key change for lane merging for this data will be that tag 0 and tag 888 will + not be merged across the lanes. + The NovaSeq Standard workflow, where there is only one input port, is + different to the more general merging across lanes where the (claimed) same + library has been sequenced. But this is not a valid reason to maintain separate + code. + release 67.1.1 - Fixed correct pp collection root for MiSeq From a0168dec68344bc995f44f69a224ce5c1c971652 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Wed, 7 Feb 2024 17:00:31 +0000 Subject: [PATCH 14/18] Updated archival pipeline graph image --- .../function_list_post_qc_review.json.png | Bin 64600 -> 39548 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/config_files/function_list_post_qc_review.json.png b/data/config_files/function_list_post_qc_review.json.png index 93a302b0a03a30842234462b34be0157d0655699..b81487d83e0b82ae8b93841aa2a9d02b8367980d 100644 GIT binary patch literal 39548 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 NDQf(kb^gY~{|{h<+fe`j literal 64600 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 A+yDRo From a82a96066b43300193bbabb7691658bfbfe5bcd2 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Wed, 7 Feb 2024 17:05:25 +0000 Subject: [PATCH 15/18] Deleted a graph for unused short Heron pipeline. Most likely this pipeline was used for testing. --- .../config_files/function_list_heron_amd.json | 164 ------------------ 1 file changed, 164 deletions(-) delete mode 100644 data/config_files/function_list_heron_amd.json diff --git a/data/config_files/function_list_heron_amd.json b/data/config_files/function_list_heron_amd.json deleted file mode 100644 index 0b2d3c98..00000000 --- a/data/config_files/function_list_heron_amd.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "graph": { - "edges": [ - { - "relation": "dependsOn", - "source": "pipeline_start", - "target": "p4_stage1_analysis" - }, - { - "relation": "dependsOn", - "source": "p4_stage1_analysis", - "target": "stage2pp" - }, - { - "relation": "dependsOn", - "source": "stage2pp", - "target": "archive_pp_data_to_irods" - }, - { - "relation": "dependsOn", - "source": "stage2pp", - "target": "qc_generic_artic" - }, - { - "relation": "dependsOn", - "source": "archive_pp_data_to_irods", - "target": "remove_intermediate_data" - }, - { - "relation": "dependsOn", - "source": "qc_generic_artic", - "target": "remove_intermediate_data" - }, - { - "relation": "dependsOn", - "source": "remove_intermediate_data", - "target": "run_analysis_complete" - }, - { - "relation": "dependsOn", - "source": "run_analysis_complete", - "target": "pipeline_end" - } - ], - "nodes": [ - { - "id": "pipeline_start", - "label": "pipeline_start", - "metadata": { - "description": "A token job, which always succeeds; the start node of the both functions and jobs directed graphs.", - "resources": { - "default": { - "queue": "small", - "minimum_cpu": 0 - } - } - } - }, - { - "id": "p4_stage1_analysis", - "label": "p4_stage1_analysis", - "metadata": { - "description": "Primary analysis of the data (bcl/cbcl files) coming from the Illumina instrument producing unaligned CRAM files for individual samples", - "resources": { - "default": { - "minimum_cpu": 8, - "memory": 20, - "fs_slots_num": 4, - "queue": "p4stage1" - } - } - } - }, - { - "id": "stage2pp", - "label": "stage2pp", - "metadata": { - "description": "Creates file system scaffold and job definitions for external pipelines, which use the output of the primary analysis as their input.", - "resources": { - "default": {}, - "ncov2019-artic-nf": { - "minimum_cpu": 4, - "memory": 5 - } - } - } - }, - { - "id": "qc_generic_artic", - "label": "qc_generic_artic", - "metadata": { - "description": "A QC check that ingests the QC summary of ncov2019 artic external pipeline in combination with results of some other QC checks run by the main pipeline", - "resources": { - "default": { - "minimum_cpu": 4, - "memory": 5, - "fs_slots_num": 1, - "apply_array_cpu_limit": 1 - } - } - } - }, - { - "id": "run_analysis_complete", - "label": "run_analysis_complete", - "metadata": { - "description": "Writes a serialized representation of the 'analysis complete' run status to the file system", - "resources": { - "default": { - "queue": "small", - "minimum_cpu": 0 - } - } - } - }, - { - "id": "archive_pp_data_to_irods", - "label": "archive_pp_data_to_irods", - "metadata": { - "description": "Archival of the output of external pipelines to the iRODS repository", - "resources": { - "default": { - "reserve_irods_slots": 1 - } - } - } - }, - { - "id": "remove_intermediate_data", - "label": "remove_intermediate_data", - "metadata": { - "description": "Remove intermediate analysis data", - "resources": { - "default": { - "queue": "small" - } - } - } - }, - { - "id": "pipeline_end", - "label": "pipeline_end", - "metadata": { - "description": "A token job, which always succeeds; the end node of the both functions and jobs directed graphs.", - "resources": { - "default": { - "queue": "small", - "minimum_cpu": 0 - } - } - } - } - ], - "metadata": { - "description": "A directed graph of functions for reanalysis of -Heron runs to produce an additional consensus file", - "default_resources": { - "minimum_cpu": 1, - "memory": 2, - "array_cpu_limit": 64 - } - } - } -} From c0e09b7a0187a64c6877444568f13595589f1b90 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Fri, 9 Feb 2024 10:57:52 +0000 Subject: [PATCH 16/18] Created a log of changes for release 68.0.0 --- Changes | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Changes b/Changes index f587b727..e9c1866f 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,7 @@ LIST OF CHANGES --------------- +release 68.0.0 - Use st::api::lims->aggregate_libraries() method for both 'merge_lanes' and 'merge_by_library' pipeline options. This is a breaking change as far as archival and deletion of NovaSeq Standard workflow data is concerned. @@ -10,6 +11,22 @@ LIST OF CHANGES different to the more general merging across lanes where the (claimed) same library has been sequenced. But this is not a valid reason to maintain separate code. + - Deletable shadow folders are detected, but not considered as deletable + for now. They are flagged in the log of the 'npg_run_is_deletable' script. + - Removed all code that was used for the UKB project and the upload of Heron + project data to CLIMB. Updated the archival pipeline function graph and its + graphical representation. + - Removed 'cache_merge_component' and 'archive_to_s3' pipeline functions. + - Removed all functions for retrieving the QC state of the product + from 'npg_pipeline::product'. + - Dropped npg_pipeline::base dependency on QC database ('qc_schema' + attribute for 'npg_qc::Schema'). Removed test fixtures for the QC database. + - Deleted 'npg_receipt4run_is_deletable' script. + - Dropped checks for files upload to the third-party cloud locations when + deciding whether the run folder is deletable. + - Updated examples in POD in 'npg_pipeline::product::release'. + - Excluded redundant settings from 'product_release.yml' files used in + unit tests. release 67.1.1 - Fixed correct pp collection root for MiSeq From ba410aa73c5464708b34a89f1a7ee280457d8e32 Mon Sep 17 00:00:00 2001 From: Marina Gourtovaia Date: Wed, 21 Feb 2024 13:45:10 +0000 Subject: [PATCH 17/18] Drop build dependency on npg_tracking::illumina::run::folder::validation --- Build.PL | 1 - 1 file changed, 1 deletion(-) diff --git a/Build.PL b/Build.PL index ca72e34b..af188c45 100755 --- a/Build.PL +++ b/Build.PL @@ -86,7 +86,6 @@ my $builder = $class->new( 'npg_tracking::glossary::rpt' => 0, 'npg_tracking::glossary::composition::factory::rpt_list' => 0, 'npg_tracking::illumina::runfolder' => 0, - 'npg_tracking::illumina::run::folder::validation' => 0, 'npg_tracking::Schema' => 0, 'npg_tracking::util::types' => 0, 'npg_tracking::util::abs_path' => 0, From c1da8b86ab0729339cd1ee4e9a99d176ee360f48 Mon Sep 17 00:00:00 2001 From: jmtcsngr Date: Wed, 21 Feb 2024 14:20:57 +0000 Subject: [PATCH 18/18] prep release 68.0.0 --- Changes | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Changes b/Changes index e9c1866f..3b7c6bb5 100644 --- a/Changes +++ b/Changes @@ -3,14 +3,14 @@ LIST OF CHANGES release 68.0.0 - Use st::api::lims->aggregate_libraries() method for both 'merge_lanes' and - 'merge_by_library' pipeline options. This is a breaking change as far as - archival and deletion of NovaSeq Standard workflow data is concerned. - Key change for lane merging for this data will be that tag 0 and tag 888 will - not be merged across the lanes. - The NovaSeq Standard workflow, where there is only one input port, is - different to the more general merging across lanes where the (claimed) same - library has been sequenced. But this is not a valid reason to maintain separate - code. + 'merge_by_library' pipeline options. This is a breaking change as far as + archival and deletion of NovaSeq Standard workflow data is concerned. + Key change for lane merging for this data will be that tag 0 and tag 888 will + not be merged across the lanes. + The NovaSeq Standard workflow, where there is only one input port, is + different to the more general merging across lanes where the (claimed) same + library has been sequenced. But this is not a valid reason to maintain separate + code. - Deletable shadow folders are detected, but not considered as deletable for now. They are flagged in the log of the 'npg_run_is_deletable' script. - Removed all code that was used for the UKB project and the upload of Heron