diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000000..163f777c441 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,62 @@ +name: Coverage + +on: [push, pull_request] + +jobs: + test: + name: Run coverage tests + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + part: [ 1, 2, 3 ] + + env: + PERL5LIB: local-coverage/lib/perl5 + HARNESS_PERL_SWITCHES: "-MDevel::Cover=+ignore,local/lib/perl5,commonlib,perllib/Catalyst/[^A],perllib/Email,Test.pm,^t" + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + + - uses: niden/actions-memcached@v7 + + - name: Setup cache (carton) + uses: actions/cache@v2 + with: + path: local + key: ${{ runner.os }}-carton-${{ hashFiles('cpanfile.snapshot') }} + + - name: Setup cache (coverage) + uses: actions/cache@v2 + with: + path: local-coverage + key: ${{ runner.os }}-coverage + + - name: Install packages + run: | + sudo apt install -y gettext language-pack-en language-pack-de language-pack-sv libimage-magick-perl + vendor/bin/carton install --deployment + commonlib/bin/gettext-makemo FixMyStreet + bin/cpanm --quiet --notest -l local-coverage Devel::Cover::Report::Codecov JSON::MaybeXS + + - name: Run tests (with coverage, part 1) + if: matrix.part == 1 + run: script/test --jobs 3 $(find t/app/controller -name "[a-q]*.t") + + - name: Run tests (with coverage, part 2) + if: matrix.part == 2 + run: script/test --jobs 3 $(find t/app/controller -name "[r-z]*.t") + + - name: Run tests (with coverage, part 3) + if: matrix.part == 3 + run: script/test --jobs 3 $(find t -name "*.t" ! -path "t/app/controller*") + + - name: Generate coverage report + if: success() + run: local-coverage/bin/cover --report codecov + env: + PERL5LIB: 'local-coverage/lib/perl5:perllib' + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml new file mode 100644 index 00000000000..557ebd52987 --- /dev/null +++ b/.github/workflows/cypress.yml @@ -0,0 +1,46 @@ +name: Cypress + +on: [push, pull_request] + +jobs: + test: + name: Run Cypress tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + + - name: Setup node + uses: actions/setup-node@v1 + with: + node-version: 8.x + + - name: Setup cache (carton) + uses: actions/cache@v2 + with: + path: local + key: ${{ runner.os }}-carton-${{ hashFiles('cpanfile.snapshot') }} + + - name: Setup cache (cypress) + uses: actions/cache@v2 + with: + path: | + ~/.npm + node_modules + key: ${{ runner.os }}-node-8-cypress-3.8.3 + + - name: Install packages + run: | + sudo apt install -y gettext + npm install cypress@3.8.3 + vendor/bin/carton install --deployment + commonlib/bin/gettext-makemo FixMyStreet + echo "$(npm bin)" >> $GITHUB_PATH + + - name: Run Cypress tests + run: | + bin/browser-tests run ${CYPRESS_RECORD_KEY:+--record} + env: + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml new file mode 100644 index 00000000000..c3becce85ce --- /dev/null +++ b/.github/workflows/default.yml @@ -0,0 +1,49 @@ +name: CI + +on: [push, pull_request] + +jobs: + test: + name: Test on perl ${{ matrix.perl_version }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + # stretch, buster, focal/bullseye, xenial, trusty + # bionic 5.26 is ubuntu-latest, in coverage run + perl_version: [ 5.24.4, 5.28.3, 5.30.3, 5.22.4, 5.18.4 ] + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + + - name: Setup cache (carton) + uses: actions/cache@v2 + with: + path: local + key: ${{ runner.os }}-perl-${{ matrix.perl_version }}-carton-${{ hashFiles('cpanfile.snapshot') }} + + - name: Setup cache (perl) + id: cache-perl + uses: actions/cache@v2 + with: + path: ~/perl5 + key: ${{ runner.os }}-perl-${{ matrix.perl_version }} + + - name: Install correct perl + if: steps.cache-perl.outputs.cache-hit != 'true' + run: | + wget -qO - https://install.perlbrew.pl | bash + ~/perl5/perlbrew/bin/perlbrew install --notest ${{ matrix.perl_version }} + ~/perl5/perlbrew/bin/perlbrew clean + + - name: Add packages + run: | + sudo apt install -y gettext language-pack-en language-pack-de language-pack-sv libimage-magick-perl + ~/perl5/perlbrew/bin/perlbrew exec vendor/bin/carton install --deployment + commonlib/bin/gettext-makemo FixMyStreet + + - name: Run tests + run: ~/perl5/perlbrew/bin/perlbrew exec script/test --jobs 3 t diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ca5eaee6c7e..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,69 +0,0 @@ -dist: trusty - -notifications: - email: false - irc: - channels: - - "irc.freenode.net#fixmystreet" - use_notice: true - skip_join: true - slack: - secure: "yY05S8ecxMv5GwexGQV/9sqUwxn1j0LF8KyG0VnoMPqJXOaGmkAe60I695CC7/P0AaNC2oWfqMZcEcdXZNa8l7kWluxyRktt6cP+VDPmIKJqcsasoDPDTLlZQTNy8i+EwxzRWDUUMFjLet6lqZYEbBPeCSufmQyyjknhGiSPGsQ=" - webhooks: - urls: - secure: "x6M1u9SFv2oQpo28wDSpURV0Rnk+jTA5VCXIjlo0ccbEV1IOp36KSJT3A2lSbf2BDlwGlKcbgtMP9dk83So2dhvPow7ogemouW+Rx1olYJgzoTR3v5cZt9pn7g6y0O1M+AkDIzabzT90oRD4//YVY5OS16ZjePcBWwp9yHEEQ7I=" - -# Put the versions in the matrix below so that we're ordered better -language: perl - -cache: - directories: - - ~/.npm - - node_modules - -matrix: - include: - - perl: "5.24" # stretch - - perl: "5.26" # bionic - env: "COVERAGE_PART=1" # Running the tests with coverage is much slower, so split the test run in two - - perl: "5.26" - env: "COVERAGE_PART=2" - - perl: "5.22" - env: "CYPRESS=1" # Run headless browser tests - - perl: "5.22" # xenial - - perl: "5.18" # trusty - - perl: "5.20" # jessie - - perl: "5.28" # buster - -env: - global: - - "S3_BUCKET=fixmystreet-bundle-cache" - - "CYPRESS=0" - - "COVERAGE_PART=0" - - secure: "llgWNfR/8pH0HjYpg+xhVxuqTaLC0GGUugfuINiUap7JxzjCZ2rlryxCXA4BCM8GUHa9wlYKhrKCSx+DM3EHRE0cLei7LNxAK1JSXLj3NihFQhqnq64tjDwGCSA4l7mlqErA7DK4Dpmh+hBp5f680akITAInM92CbwQZxLDYaCU=" - - secure: "qW+WCgAF68itADxcbcq+nCnKx3vf3GX73HMfjfbkFFUsYmIR+ZaJ9yQMnGJwxIpCHTWLAeqyx4KO8N8T3GmNdKYzIMZemOzp4ED29YC31QOQeq1CwNp2hD5sq/o47d2BzXWwMYNvNXfxz1K6r2c6EMPUtu8X3B8ExZq1RzSFdXs=" - -sudo: false - -addons: - apt: - packages: - - gettext - - language-pack-de - - language-pack-sv - -install: - - .travis/install - - 'if [ "$COVERAGE_PART" != "0" ]; then cpanm --quiet --notest Devel::Cover::Report::Codecov; fi' - - 'if [ "$CYPRESS" = "1" ]; then npm install cypress@3.8.3; fi' -before_script: - - commonlib/bin/gettext-makemo FixMyStreet - - 'if [ "$COVERAGE_PART" != "0" ]; then export HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,local/lib/perl5,commonlib,perllib/Catalyst/[^A],perllib/Email,Test.pm,^t"; fi' -script: - - 'if [ "$CYPRESS" = "0" ] && [ "$COVERAGE_PART" = "0" ]; then script/test --jobs 3 t; fi' - - 'if [ "$COVERAGE_PART" = "1" ]; then script/test --jobs 3 `find t/app/controller -name "*.t"`; fi' - - 'if [ "$COVERAGE_PART" = "2" ]; then script/test --jobs 3 `find t -name "*.t" ! -path "t/app/controller*"`; fi' - - 'if [ "$CYPRESS" = "1" ]; then PATH=$(npm bin):$PATH bin/browser-tests run ${CYPRESS_RECORD_KEY:+--record}; fi' -after_success: - - .travis/after_script - - 'if [ "$COVERAGE_PART" != "0" ]; then cover --report codecov; fi' diff --git a/.travis/after_script b/.travis/after_script deleted file mode 100755 index 2a8b2268d9e..00000000000 --- a/.travis/after_script +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python - -import os -import site -import sys -import tarfile -from utils import get_bundle_filename - -wanted_filename = get_bundle_filename() - -if os.path.exists(wanted_filename) and os.path.getsize(wanted_filename): - print "File was downloaded, no need to upload" - sys.exit() - -site.addsitedir(site.getusersitepackages()) -os.system('pip install --user boto') - -import boto -from boto.s3.key import Key - -print "Creating archive..." -tfile = tarfile.open(wanted_filename, 'w:gz') -tfile.add('local') -tfile.close() - -print "Uploading archive to S3..." -conn = boto.connect_s3() -bucket = conn.get_bucket('fixmystreet-bundle-cache') -key = Key(bucket) -key.key = wanted_filename -key.set_contents_from_filename(wanted_filename) - -print "Completed" diff --git a/.travis/install b/.travis/install deleted file mode 100755 index c9d0aef7865..00000000000 --- a/.travis/install +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import tarfile -import urllib -from utils import get_bundle_filename - -wanted_filename = get_bundle_filename() - -url = 'https://fixmystreet-bundle-cache.s3.amazonaws.com/%s' % wanted_filename -try: - urllib.urlretrieve(url, wanted_filename) - if tarfile.is_tarfile(wanted_filename): - tfile = tarfile.open(wanted_filename) - tfile.extractall() - print "Cached copy found and extracted" - sys.exit(0) - else: - os.remove(wanted_filename) -except IOError: - os.remove(wanted_filename) - -print "No cached copy found, running carton install..." -ret = os.system('vendor/bin/carton install --deployment') -if ret: - os.system('cat ~/.cpanm/build.log') - -sys.exit(ret) diff --git a/.travis/utils.py b/.travis/utils.py deleted file mode 100755 index f56b7d9d442..00000000000 --- a/.travis/utils.py +++ /dev/null @@ -1,22 +0,0 @@ -import hashlib -import os - - -def get_bundle_filename(): - root = os.path.join(os.path.dirname(__file__), '..') - with open(os.path.join(root, 'cpanfile.snapshot')) as cpanfile: - hash = hashlib.md5(cpanfile.read()).hexdigest() - - try: - version = os.environ['TRAVIS_PERL_VERSION'] - except KeyError: - # Not running on Travis, assume default Travis version - version = '5.14' - - if version == '5.14': - version = '' - else: - version = '-%s' % version - - filename = 'fixmystreet-local-%s%s.tgz' % (hash, version) - return filename diff --git a/perllib/Devel/Cover/Report/Codecov/Service/GitHub.pm b/perllib/Devel/Cover/Report/Codecov/Service/GitHub.pm new file mode 100644 index 00000000000..a5d5e7fb708 --- /dev/null +++ b/perllib/Devel/Cover/Report/Codecov/Service/GitHub.pm @@ -0,0 +1,33 @@ +package Devel::Cover::Report::Codecov::Service::GitHub; +use strict; +use warnings; +use utf8; + +sub detect { + return $ENV{GITHUB_ACTIONS}; +} + +sub configuration { + (my $branch = $ENV{GITHUB_REF}) =~ s{^refs/heads/}{}; + + my $conf = { + service => 'github-actions', + commit => $ENV{GITHUB_SHA}, + slug => $ENV{GITHUB_REPOSITORY}, + build => $ENV{GITHUB_RUN_ID}, + build_url => "https://github.com/$ENV{GITHUB_REPOSITORY}/actions/runs/$ENV{GITHUB_RUN_ID}", + branch => $branch, + }; + + if ($ENV{GITHUB_HEAD_REF}) { + (my $pr = $ENV{GITHUB_REF}) =~ s{^refs/pull/}{}; + $pr =~ s{/merge$}{}; + $conf->{pr} = $pr; + $conf->{branch} = $ENV{GITHUB_HEAD_REF}; + } + + return $conf; +} + +1; +__END__ diff --git a/perllib/FixMyStreet/App/Controller/Admin/Reports.pm b/perllib/FixMyStreet/App/Controller/Admin/Reports.pm index e3a4256325f..20801e0cfd9 100644 --- a/perllib/FixMyStreet/App/Controller/Admin/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Admin/Reports.pm @@ -4,6 +4,7 @@ use namespace::autoclean; BEGIN { extends 'Catalyst::Controller'; } +use utf8; use List::MoreUtils 'uniq'; use FixMyStreet::SMS; use Utils; diff --git a/perllib/FixMyStreet/App/Model/PhotoSet.pm b/perllib/FixMyStreet/App/Model/PhotoSet.pm index 76a287e71c5..85e45785643 100644 --- a/perllib/FixMyStreet/App/Model/PhotoSet.pm +++ b/perllib/FixMyStreet/App/Model/PhotoSet.pm @@ -8,6 +8,7 @@ use Scalar::Util 'openhandle', 'blessed'; use Image::Size; use IPC::Cmd qw(can_run); use IPC::Open3; +use Try::Tiny; use FixMyStreet; use FixMyStreet::ImageMagick; @@ -149,7 +150,9 @@ has ids => ( # Arrayref of $fileid tuples (always, so post upload/raw data proc } # we have an image we can use - save it to storage - $photo_blob = FixMyStreet::ImageMagick->new(blob => $photo_blob)->shrink('2048x2048')->as_blob; + $photo_blob = try { + FixMyStreet::ImageMagick->new(blob => $photo_blob)->shrink('2048x2048')->as_blob; + } catch { $photo_blob }; return $self->storage->store_photo($photo_blob); } @@ -201,18 +204,20 @@ sub get_image_data { } my $im = FixMyStreet::ImageMagick->new(blob => $image->{data}); - my $photo; - if ( $size eq 'tn' ) { - $photo = $im->shrink('x100'); - } elsif ( $size eq 'fp' ) { - $photo = $im->crop; - } elsif ( $size eq 'og' ) { - $photo = $im->crop('1200x630'); - } elsif ( $size eq 'full' ) { - $photo = $im - } else { - $photo = $im->shrink($args{default} || '250x250'); - } + my $photo = try { + if ( $size eq 'tn' ) { + $im->shrink('x100'); + } elsif ( $size eq 'fp' ) { + $im->crop; + } elsif ( $size eq 'og' ) { + $im->crop('1200x630'); + } elsif ( $size eq 'full' ) { + $im + } else { + $im->shrink($args{default} || '250x250'); + } + }; + return unless $photo; return { data => $photo->as_blob, diff --git a/perllib/FixMyStreet/ImageMagick.pm b/perllib/FixMyStreet/ImageMagick.pm index d9f64380120..ec99fd87765 100644 --- a/perllib/FixMyStreet/ImageMagick.pm +++ b/perllib/FixMyStreet/ImageMagick.pm @@ -64,7 +64,7 @@ sub shrink { my ($self, $size) = @_; return $self unless $self->image; my $err = $self->image->Scale(geometry => "$size>"); - throw Error::Simple("resize failed: $err") if "$err"; + die "resize failed: $err" if "$err"; $self->_set_width_and_height(); return $self->strip; } @@ -76,9 +76,9 @@ sub crop { $size //= '90x60'; return $self unless $self->image; my $err = $self->image->Resize( geometry => "$size^" ); - throw Error::Simple("resize failed: $err") if "$err"; + die "resize failed: $err" if "$err"; $err = $self->image->Extent( geometry => $size, gravity => 'Center' ); - throw Error::Simple("resize failed: $err") if "$err"; + die "resize failed: $err" if "$err"; $self->_set_width_and_height(); return $self->strip; }