AWS-Lambda-Quick

 view release on metacpan or  search on metacpan

CONTRIBUTING.md  view on Meta::CPAN

# CONTRIBUTING

Thank you for considering contributing to this distribution. This file
contains instructions that will help you work with the source code.

Please note that if you have any questions or difficulties, you can reach the
maintainer(s) through the bug queue described later in this document
(preferred), or by emailing the releaser directly. You are not required to
follow any of the steps in this document to submit a patch or bug report;
these are recommendations, intended to help you (and help us help you faster).


The distribution is managed with
[Dist::Zilla](https://metacpan.org/release/Dist-Zilla).

However, you can still compile and test the code with the `Makefile.PL` or
`Build.PL` in the repository:

    perl Makefile.PL

CONTRIBUTING.md  view on Meta::CPAN

    $ dzil test
    $ dzil test --release
    $ dzil xtest
    $ dzil listdeps --json
    $ dzil build --notgz

You can learn more about Dist::Zilla at http://dzil.org/.

The code for this distribution is [hosted at GitHub](https://github.com/2shortplanks/aws-lambda-quick).

You can submit code changes by forking the repository, pushing your code
changes to your clone, and then submitting a pull request. Detailed
instructions for doing that is available here:

https://help.github.com/articles/creating-a-pull-request

If you have found a bug, but do not have an accompanying patch to fix it, you
can submit an issue report [via the web](https://github.com/2shortplanks/aws-lambda-quick/issues)
.
This is a good place to send your questions about the usage of this distribution.


## Tidyall

This distribution uses
[Code::TidyAll](https://metacpan.org/release/Code-TidyAll) to enforce a
uniform coding style. This is tested as part of the author testing suite. You
can install and run tidyall by running the following commands:

CONTRIBUTING.md  view on Meta::CPAN

    $ tidyall -a

Please run this before committing your changes and address any issues it
brings up.

## Contributor Names

If you send a patch or pull request, your name and email address will be
included in the documentation as a contributor (using the attribution on the
commit or patch), unless you specifically request for it not to be. If you
wish to be listed under a different name or address, you should submit a pull
request to the .mailmap file to contain the correct mapping.
[Check here](https://github.com/git/git/blob/master/Documentation/mailmap.txt)
for more information on git's .mailmap files.

This file was generated via Dist::Zilla::Plugin::GenerateFile::FromShareDir 0.014 from a
template file originating in Dist-Zilla-PluginBundle-MAXMIND-0.83.

LICENSE  view on Meta::CPAN

    received the program in object code or executable form alone.)

Source code for a work means the preferred form of the work for making
modifications to it.  For an executable file, complete source code means
all the source code for all modules it contains; but, as a special
exception, it need not include source code for modules which are standard
libraries that accompany the operating system on which the executable
file runs, or for standard header files or definitions files that
accompany that operating system.

  4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License.  However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.

  5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions.  You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.

  7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of the license which applies to it and "any

LICENSE  view on Meta::CPAN

may not charge a fee for this Package itself. However, you may distribute this
Package in aggregate with other (possibly commercial) programs as part of a
larger (possibly commercial) software distribution provided that you do not
advertise this Package as a product of your own.

6. The scripts and library files supplied as input to or produced as output
from the programs of this Package do not automatically fall under the copyright
of this Package, but belong to whomever generated them, and may be sold
commercially, and may be aggregated with this Package.

7. C or perl subroutines supplied by you and linked into this Package shall not
be considered part of this Package.

8. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.

9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

The End

README.md  view on Meta::CPAN


    #!/usr/bin/perl

    use strict;
    use warnings;

    use AWS::Lambda::Quick (
        name => 'hello-world',
    );

    sub handler {
        my $data = shift;
        my $name = $data->{queryStringParameters}{who} // "World";
        return {
            statusCode => 200,
            headers => {
                'Content-Type' => 'text/plain',
            },
            body => "Hello, $name",
        };
    }

README.md  view on Meta::CPAN

handler function:

    use AWS::Lambda::Quick (
        name => 'random-lottery-numbers',
    );

And then execute it locally.  Rather than running as normal your script
will instead upload itself to AWS as a Lambda function (modifying
itself so that it no longer has a dependency on AWS::Lambda::Quick) and
handle all the other steps needed to make itself web accessible.
Running the script locally subsequent times will update the code and
AWS settings.

## What This Actually Does

You probably don't care about this, but this is actually what's
going on when the script uploads itself.  This is subject to change
in later versions of this utility as better ways to do things
become available (for example AWS has a HTTP API that is currently in
beta that could make some of this easier!).

By default, unless you specify extra parameters when you import
AWS::Lambda::Quick, AWS will be configured as described below

### Create A New Role For Use With AWS::Lambda::Quick

Execution creates a new role called `perl-aws-lambda-quick` that can

README.md  view on Meta::CPAN


    use strict;
    use warnings;

    use JSON::PP;

    use AWS::Lambda::Quick (
        name => 'echo',
    );

    sub handler {
        my $data = shift;
        return {
            statusCode => 200,
            headers => {
                'Content-Type' => 'application/json',
            },
            body => encode_json($data),
        };
    }

cpanfile  view on Meta::CPAN

requires "AWS::CLIWrapper" => "0";
requires "Archive::Zip" => "0";
requires "File::Temp" => "0";
requires "JSON::PP" => "0";
requires "Mo" => "0";
requires "Path::Tiny" => "0";
requires "autodie" => "0";
requires "strict" => "0";
requires "warnings" => "0";

on 'test' => sub {
  requires "Exporter" => "0";
  requires "ExtUtils::MakeMaker" => "0";
  requires "File::Spec" => "0";
  requires "FindBin" => "0";
  requires "HTTP::Tiny" => "0";
  requires "Test2::V0" => "0";
  requires "Test::More" => "1.302015";
  requires "Test::TempDir::Tiny" => "0";
  requires "base" => "0";
  requires "lib" => "0";
};

on 'test' => sub {
  recommends "CPAN::Meta" => "2.120900";
};

on 'configure' => sub {
  requires "ExtUtils::MakeMaker" => "0";
};

on 'develop' => sub {
  requires "Code::TidyAll::Plugin::Test::Vars" => "0.02";
  requires "File::Spec" => "0";
  requires "IO::Handle" => "0";
  requires "IPC::Open3" => "0";
  requires "Parallel::ForkManager" => "1.19";
  requires "Perl::Critic" => "1.126";
  requires "Perl::Tidy" => "20160302";
  requires "Pod::Wordlist" => "0";
  requires "Test::CPAN::Changes" => "0.19";
  requires "Test::CPAN::Meta::JSON" => "0.16";

lib/AWS/Lambda/Quick.pm  view on Meta::CPAN

package AWS::Lambda::Quick;

use strict;
use warnings;
use autodie;

our $VERSION = '1.0002';

use AWS::Lambda::Quick::Processor ();

sub import {
    shift;

    # where's the source code of the script calling us?
    my ( undef, $file, undef ) = caller;

    # process the whole thing
    my $proc = AWS::Lambda::Quick::Processor->new(
        src_filename => $file,
        @_,
    );

lib/AWS/Lambda/Quick.pm  view on Meta::CPAN


    #!/usr/bin/perl

    use strict;
    use warnings;

    use AWS::Lambda::Quick (
        name => 'hello-world',
    );

    sub handler {
        my $data = shift;
        my $name = $data->{queryStringParameters}{who} // "World";
        return {
            statusCode => 200,
            headers => {
                'Content-Type' => 'text/plain',
            },
            body => "Hello, $name",
        };
    }

lib/AWS/Lambda/Quick.pm  view on Meta::CPAN

handler function:

    use AWS::Lambda::Quick (
        name => 'random-lottery-numbers',
    );

And then execute it locally.  Rather than running as normal your script
will instead upload itself to AWS as a Lambda function (modifying
itself so that it no longer has a dependency on AWS::Lambda::Quick) and
handle all the other steps needed to make itself web accessible.
Running the script locally subsequent times will update the code and
AWS settings.

=head2 What This Actually Does

You probably don't care about this, but this is actually what's
going on when the script uploads itself.  This is subject to change
in later versions of this utility as better ways to do things
become available (for example AWS has a HTTP API that is currently in
beta that could make some of this easier!).

By default, unless you specify extra parameters when you import
AWS::Lambda::Quick, AWS will be configured as described below

=head3 Create A New Role For Use With AWS::Lambda::Quick

Execution creates a new role called C<perl-aws-lambda-quick> that can

lib/AWS/Lambda/Quick.pm  view on Meta::CPAN


    use strict;
    use warnings;

    use JSON::PP;

    use AWS::Lambda::Quick (
        name => 'echo',
    );

    sub handler {
        my $data = shift;
        return {
            statusCode => 200,
            headers => {
                'Content-Type' => 'application/json',
            },
            body => encode_json($data),
        };
    }

lib/AWS/Lambda/Quick/CreateZip.pm  view on Meta::CPAN

our $VERSION = '1.0002';

use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use Path::Tiny qw( path );

has src_filename => required => 1;
has zip_filename => required => 1;

has extra_files => default => [];

has _src_path => sub { path( shift->src_filename ) };
has _src_dir  => sub { shift->_src_path->parent };
has _zip_class  => default => 'Archive::Zip';
has _zip        => sub { shift->_zip_class->new };
has _script_src => sub { shift->_src_path->slurp_raw };

# this is the same src as in script src but the first occurance of
# "use AWS::Lambda::Quick" is prepended with
# "$INC{'AWS/Lambda/Quick.pm'}=1" to prevent it actually being loaded
# from disk.  Note this happens on just one line to avoid screwing
# with line numebrs that could mess with error messages
has _converted_src => sub {
    my $self = shift;
    my $src  = $self->_script_src;
    $src =~ s{(?=use AWS::Lambda::Quick(?:\s|[;(]))}
             {BEGIN{\$INC{'AWS/Lambda/Quick.pm'}=1} };
    return $src;
};

### methods for interfacing with Archive::Zip
### no code outside this section should directly interact with the
### zip file

sub _add_string {
    my $self     = shift;
    my $string   = shift;
    my $filename = shift;

    my $zip           = $self->_zip;
    my $string_member = $zip->addString( $string, $filename );
    $string_member->desiredCompressionMethod(COMPRESSION_DEFLATED);
    return ();
}

sub _add_path {
    my $self = shift;
    my $path = path(shift);

    if ( $path->is_absolute ) {
        die "Cannot add absolute path! $path";
    }
    my $abs_path = path( $self->_src_dir, $path );

    # silently ignore files that don't exist.  This allows you
    # to say put extra_files => [qw( lib )] in your file and not

lib/AWS/Lambda/Quick/CreateZip.pm  view on Meta::CPAN

    return () unless -d $abs_path;
    my $iter = $abs_path->iterator;
    while ( my $next = $iter->() ) {
        my $child = $path->child( $next->basename );
        $self->_add_path($child);
    }

    return ();
}

sub _write_zip {
    my $self = shift;
    unless ( $self->_zip->writeToFileNamed( $self->zip_filename->stringify )
        == AZ_OK ) {
        die 'write error';
    }
    return ();
}

### logic for building the zip file contents ###

sub _build_zip {
    my $self = shift;
    $self->_add_string( $self->_converted_src, 'handler.pl' );
    $self->_add_path($_) for @{ $self->extra_files };
    return ();
}

sub create_zip {
    my $self = shift;
    $self->_build_zip;
    $self->_write_zip;
    return ();
}

1;

__END__

lib/AWS/Lambda/Quick/Processor.pm  view on Meta::CPAN

has src_filename => required => 1;

has 'description';
has 'extra_files';
has 'extra_layers';
has 'memory_size';
has 'region';
has 'stage_name';
has 'timeout';

has _tempdir => sub {
    return tempdir( CLEANUP => 1 );
};
has zip_filename => sub {
    return path( shift->_tempdir, 'handler.zip' );
};

sub selfkv {
    my $self = shift;
    my @computed_args;
    for my $key (@_) {
        my $val = $self->$key;
        push @computed_args, $key => $val if defined $val;
    }
    return @computed_args;
}

sub process {
    my $self = shift;

    AWS::Lambda::Quick::CreateZip->new(
        $self->selfkv(
            qw(
                extra_files
                src_filename
                zip_filename
                )
        ),

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN


has extra_layers => default => [];
has region       => default => 'us-east-1';
has memory_size  => default => 128;           # this is the AWS default
has timeout      => default => 3;             # this is the AWS default
has description => default => 'A Perl AWS::Lambda::Quick Lambda function.';
has stage_name  => default => 'quick';

### lambda function computed attributes

has aws => sub {
    my $self = shift;

    return AWS::CLIWrapper->new(
        region => $self->region,
    );
};

has zip_file_blob => sub { 'fileb://' . shift->zip_filename };

# should we create the function from scratch or just update it?
# by default we interogate the api to see if it exists already
has update_type => sub {
    my $self = shift;
    my $aws  = $self->aws;

    my $result = $aws->lambda(
        'get-function',
        {
            'function-name' => $self->name,
        }
    );

    return $result ? 'update-function' : 'create-function';
};

### role attributes

has role      => default => 'perl-aws-lambda-quick';
has _role_arn => sub {
    my $self = shift;

    # if whatever we were passed in role was an actual ARN then we
    # can just use that without any further lookups
    if ( $self->role
        =~ /^arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role\/?[a-zA-Z_0-9+=,.@\-_\/]+$/
    ) {
        $self->debug('using passed role arn');
        return $self->role;
    }

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

            'role-name' => $self->role,
        }
    );
    $self->debug('permissions attached to role');
    return $result->{Role}{Arn};
};

### rest api attributes

has rest_api    => default => 'perl-aws-lambda-quick';
has rest_api_id => sub {
    my $self = shift;

    # search existing apis
    $self->debug('searching for existing rest api');
    my $result = $self->aws_do(
        'apigateway',
        'get-rest-apis',
    );
    for ( @{ $result->{items} } ) {
        next unless $_->{name} eq $self->rest_api;

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

        {
            name => $self->rest_api,
            description =>
                'Created by AWS::Lambda::Quick. See https://metacpan.org/pod/AWS::Lambda::Quick for more info.',
        },
    );
    $self->debug('created new rest api');
    return $result->{id};
};

has resource_id => sub {
    my $self = shift;

    # TODO: We shold probably make this configurable, right?
    my $path = '/' . $self->name;

    # search existing resources
    $self->debug('searching of existing resource');
    my $result = $self->aws_do(
        'apigateway',
        'get-resources',

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

        {
            'rest-api-id' => $self->rest_api_id,
            'parent-id'   => $parent_id,
            'path-part'   => $self->name,
        },
    );
    $self->debug('created new resource');
    return $result->{id};
};

has greedy_resource_id => sub {
    my $self = shift;

    my $path = '/' . $self->name . '/{proxy+}';

    # search existing resources
    $self->debug('searching of existing greedy resource');
    my $result = $self->aws_do(
        'apigateway',
        'get-resources',
        {

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

            'parent-id'   => $self->resource_id,
            'path-part'   => '{proxy+}',
        },
    );
    $self->debug('created new greedy resource');
    return $result->{id};
};

### methods

sub upload {
    my $self = shift;

    my $function_arn = $self->_upload_function;

    for my $resource_id ( $self->resource_id, $self->greedy_resource_id ) {
        $self->_create_method($resource_id);
        $self->_create_method_response($resource_id);
        $self->_create_integration( $function_arn, $resource_id );
        $self->_create_integration_response($resource_id);
    }
    $self->_stage;

    return ();
}

sub api_url {
    my $self = shift;

    return
          'https://'
        . $self->rest_api_id
        . '.execute-api.'
        . $self->region
        . '.amazonaws.com/'
        . $self->stage_name . '/'
        . $self->name;
}

sub _stage {
    my $self = shift;

    $self->aws_do(
        'apigateway',
        'create-deployment',
        {
            'rest-api-id' => $self->rest_api_id,
            'stage-name'  => $self->stage_name,
        }
    );
}

sub _create_method {
    my $self        = shift;
    my $resource_id = shift;

    my @identifiers = (
        'rest-api-id' => $self->rest_api_id,
        'resource-id' => $resource_id,
        'http-method' => 'ANY',
    );

    $self->debug('checking for existing method');

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

        {
            @identifiers,
            'authorization-type' => 'NONE',
        },
    );
    $self->debug('new method put');

    return ();
}

sub _create_method_response {
    my $self        = shift;
    my $resource_id = shift;

    my $identifiers = {
        'rest-api-id' => $self->rest_api_id,
        'resource-id' => $resource_id,
        'http-method' => 'ANY',
        'status-code' => 200,
    };

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

    $self->aws_do(
        'apigateway',
        'put-method-response',
        $identifiers,
    );
    $self->debug('new method response put');

    return ();
}

sub _create_integration {
    my $self         = shift;
    my $function_arn = shift;
    my $resource_id  = shift;

    my $identifiers = {
        'rest-api-id' => $self->rest_api_id,
        'resource-id' => $resource_id,
        'http-method' => 'ANY',
    };

    # according the the documentation at https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-integration.html
    # the uri has the form arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}
    # "lambda:path/2015-03-31/functions" is the {subdomain.service|service}:path|action for lambda functions
    my $uri
        = "arn:aws:apigateway:@{[ $self->region ]}:lambda:path/2015-03-31/functions/$function_arn/invocations";

    $self->debug('checking for existing integration');

    # get the current method response
    my $result = $self->aws->apigateway(
        'get-integration', $identifiers,
    );
    if ($result) {

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

            'integration-http-method' => 'POST',
            'credential'              => $self->_role_arn,
            uri                       => $uri,
        }
    );
    $self->debug('new integration put');

    return ();
}

sub _create_integration_response {
    my $self        = shift;
    my $resource_id = shift;

    my $identifiers = {
        'rest-api-id' => $self->rest_api_id,
        'resource-id' => $resource_id,
        'http-method' => 'ANY',
        'status-code' => 200,
    };

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

        {
            %{$identifiers},
            'selection-pattern' => q{},
        }
    );
    $self->debug('new integration put');

    return ();
}

sub _upload_function {
    my $self = shift;

    my $update_type = $self->update_type;
    my $region      = $self->region;

    # compute the arn based on the list in the AWS::Lambda 0.0.11
    # documentation
    my $v      = $region eq 'me-south-1' ? 3 : 5;
    my $layers = [
        "arn:aws:lambda:$region:445285296882:layer:perl-5-30-runtime:$v",

lib/AWS/Lambda/Quick/Upload.pm  view on Meta::CPAN

            'layers'        => $layers,
            'timeout'       => $self->timeout,
            'memory-size'   => $self->memory_size,
        }
    );
    $self->debug('function congifuration updated');
    return $result->{FunctionArn};
}

# just like $self->aws->$method but throws exception on error
sub aws_do {
    my $self   = shift;
    my $method = shift;

    my $aws    = $self->aws;
    my $result = $aws->$method(@_);

    return $result if defined $result;

    # uh oh, something went wrong, throw exception

    ## no critic (ProhibitPackageVars)
    my $code    = $AWS::CLIWrapper::Error->{Code};
    my $message = $AWS::CLIWrapper::Error->{Message};

    die "AWS CLI failure when calling $method $_[0] '$code': $message";
}

sub encode_json($) {
    return JSON::PP->new->ascii->canonical(1)->allow_nonref(1)->encode(shift);
}

sub debug {
    my $self = shift;
    return unless $ENV{AWS_LAMBDA_QUICK_DEBUG};
    for (@_) {
        print STDERR "$_\n" or die "Can't write to fh: $!";
    }
    return ();
}

sub just_update_function_code {
    my $self = shift;

    $self->aws_do(
        'lambda',
        'update-function-code',
        {
            'function-name' => $self->name,
            'zip-file'      => $self->zip_file_blob,
        },
    );

perlcriticrc  view on Meta::CPAN

[-RegularExpressions::RequireLineBoundaryMatching]

# by concensus in standup 2015-05-12 we decided to allow return undef
# this is mainly so bar can be written to return undef so that
# foo( bar => bar(), bazz => baz() ) won't cause problems
[-Subroutines::ProhibitExplicitReturnUndef]

# This incorrectly thinks signatures are prototypes.
[-Subroutines::ProhibitSubroutinePrototypes]

# http://stackoverflow.com/questions/2275317/why-does-perlcritic-dislike-using-shift-to-populate-subroutine-variables
[-Subroutines::RequireArgUnpacking]

[-Subroutines::RequireFinalReturn]

# "use v5.14" is more readable than "use 5.014"
[-ValuesAndExpressions::ProhibitVersionStrings]

t/00-report-prereqs.t  view on Meta::CPAN


# hide optional CPAN::Meta modules from prereq scanner
# and check if they are available
my $cpan_meta = "CPAN::Meta";
my $cpan_meta_pre = "CPAN::Meta::Prereqs";
my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic

# Verify requirements?
my $DO_VERIFY_PREREQS = 1;

sub _max {
    my $max = shift;
    $max = ( $_ > $max ) ? $_ : $max for @_;
    return $max;
}

sub _merge_prereqs {
    my ($collector, $prereqs) = @_;

    # CPAN::Meta::Prereqs object
    if (ref $collector eq $cpan_meta_pre) {
        return $collector->with_merged_prereqs(
            CPAN::Meta::Prereqs->new( $prereqs )
        );
    }

    # Raw hashrefs

t/02zip.t  view on Meta::CPAN

is( $z->contents('handler.pl'), <<'PERL', 'hander.pl was stored ok' );
BEGIN{$INC{'AWS/Lambda/Quick.pm'}=1} use AWS::Lambda::Quick (
    name => 'whatever',
    extra_files => 'lib',
);

use lib qw(lib);
use Greeting;
use JSON::PP qw( encode_json );

sub handler {
    my $data = shift;

    return {
        statusCode => 200,
        headers => {
            'Content-Type' => 'text/plain',
        },
        body => Greeting->greeting( $data->{queryStringParameters}{who} ),
    };
}
1;
PERL

is( $z->contents('lib/Greeting.pm'), <<'PERL', 'Greeting.pm was stored ok' );
package Greeting;
sub greeting {
    my $class = shift;
    my $name  = shift;

    return "Hello, $name";
}
1;
PERL

done_testing;

t/lib/TestHelper/CreateTestFiles.pm  view on Meta::CPAN


use strict;
use warnings;

use Test::TempDir::Tiny qw( tempdir );
use Path::Tiny qw( path );

use base qw(Exporter);
our @EXPORT_OK = qw( populated_tempdir );

sub populated_tempdir {

    # make a clean temp dir
    my $tempdir = path( tempdir() );
    $tempdir->remove_tree if -e $tempdir;
    $tempdir->mkpath;

    # create the temp files
    my $dir = path( $tempdir, 'src' );
    $dir->mkpath;

t/lib/TestHelper/CreateTestFiles.pm  view on Meta::CPAN

    path( $dir, 'handler.pl' )->spew(<<'PERL');
use AWS::Lambda::Quick (
    name => 'whatever',
    extra_files => 'lib',
);

use lib qw(lib);
use Greeting;
use JSON::PP qw( encode_json );

sub handler {
    my $data = shift;

    return {
        statusCode => 200,
        headers => {
            'Content-Type' => 'text/plain',
        },
        body => Greeting->greeting( $data->{queryStringParameters}{who} ),
    };
}
1;
PERL

    # an example library
    path( $dir, 'lib' )->mkpath;
    path( $dir, 'lib', 'Greeting.pm' )->spew(<<'PERL');
package Greeting;
sub greeting {
    my $class = shift;
    my $name  = shift;

    return "Hello, $name";
}
1;
PERL

    return $tempdir;
}

xt/release/cpan-changes.t  view on Meta::CPAN

use strict;
use warnings;

# this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.012

use Test::More 0.96 tests => 1;
use Test::CPAN::Changes;
subtest 'changes_ok' => sub {
    changes_file_ok('Changes');
};



( run in 1.263 second using v1.01-cache-2.11-cpan-88abd93f124 )