diff --git a/.eslintignore b/.eslintignore index 38235dc..0d64493 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ lib/**/* src/lib/vendor/**/* *.ts +wallaby.js diff --git a/README.md b/README.md index 571ed10..64dee20 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-creden ```js import Uploader from 's3-batch-upload'; -await new Uploader({ +const files = await new Uploader({ config: './config/configS3.json', // can also use environment variables bucket: 'bucket-name', localPath: './files', @@ -80,6 +80,9 @@ await new Uploader({ }, accessControlLevel: 'bucket-owner-full-control' // optional, not passed if undefined. - available options - "private"|"public-read"|"public-read-write"|"authenticated-read"|"aws-exec-read"|"bucket-owner-read"|"bucket-owner-full-control" }).upload(); + +// the files array contains a list of uploaded keys, which you can use to build up the S3 urls. +// e.g. "remote/path/in/bucket/demo.jpg" ``` ### S3 Authentication diff --git a/docs/assets/js/search.js b/docs/assets/js/search.js index 40827df..40e11f9 100644 --- a/docs/assets/js/search.js +++ b/docs/assets/js/search.js @@ -1,3 +1,3 @@ var typedoc = typedoc || {}; typedoc.search = typedoc.search || {}; - typedoc.search.data = {"kinds":{"32":"Variable","64":"Function","128":"Class","512":"Constructor","1024":"Property","2048":"Method","65536":"Type literal","2097152":"Object literal","4194304":"Type alias"},"rows":[{"id":0,"kind":4194304,"name":"Options","url":"globals.html#options","classes":"tsd-kind-type-alias"},{"id":1,"kind":64,"name":"streamBatch","url":"globals.html#streambatch","classes":"tsd-kind-function"},{"id":2,"kind":128,"name":"Uploader","url":"classes/uploader.html","classes":"tsd-kind-class"},{"id":3,"kind":1024,"name":"s3","url":"classes/uploader.html#s3","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":4,"kind":1024,"name":"options","url":"classes/uploader.html#options","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":5,"kind":1024,"name":"bar","url":"classes/uploader.html#bar","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":6,"kind":512,"name":"constructor","url":"classes/uploader.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class","parent":"Uploader"},{"id":7,"kind":2048,"name":"upload","url":"classes/uploader.html#upload","classes":"tsd-kind-method tsd-parent-kind-class","parent":"Uploader"},{"id":8,"kind":2048,"name":"run","url":"classes/uploader.html#run","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":9,"kind":2048,"name":"getFiles","url":"classes/uploader.html#getfiles","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":10,"kind":2048,"name":"uploadFile","url":"classes/uploader.html#uploadfile","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":11,"kind":32,"name":"glob","url":"globals.html#glob","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":12,"kind":32,"name":"path","url":"globals.html#path","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":13,"kind":32,"name":"AWS","url":"globals.html#aws","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":14,"kind":32,"name":"ProgressBar","url":"globals.html#progressbar","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":15,"kind":32,"name":"ora","url":"globals.html#ora","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":16,"kind":32,"name":"chalk","url":"globals.html#chalk","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":17,"kind":32,"name":"fs","url":"globals.html#fs","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":18,"kind":32,"name":"mime","url":"globals.html#mime","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":19,"kind":65536,"name":"__type","url":"globals.html#options.__type","classes":"tsd-kind-type-literal tsd-parent-kind-type-alias tsd-is-not-exported","parent":"Options"},{"id":20,"kind":32,"name":"bucket","url":"globals.html#options.__type.bucket","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":21,"kind":32,"name":"localPath","url":"globals.html#options.__type.localpath","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":22,"kind":32,"name":"remotePath","url":"globals.html#options.__type.remotepath","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":23,"kind":32,"name":"config","url":"globals.html#options.__type.config","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":24,"kind":32,"name":"glob","url":"globals.html#options.__type.glob","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":25,"kind":32,"name":"concurrency","url":"globals.html#options.__type.concurrency","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":26,"kind":32,"name":"dryRun","url":"globals.html#options.__type.dryrun","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":27,"kind":2097152,"name":"defaultOptions","url":"globals.html#defaultoptions","classes":"tsd-kind-object-literal tsd-is-not-exported"},{"id":28,"kind":32,"name":"dryRun","url":"globals.html#defaultoptions.dryrun","classes":"tsd-kind-variable tsd-parent-kind-object-literal tsd-is-not-exported","parent":"defaultOptions"},{"id":29,"kind":32,"name":"concurrency","url":"globals.html#defaultoptions.concurrency","classes":"tsd-kind-variable tsd-parent-kind-object-literal tsd-is-not-exported","parent":"defaultOptions"},{"id":30,"kind":32,"name":"glob","url":"globals.html#defaultoptions.glob","classes":"tsd-kind-variable tsd-parent-kind-object-literal tsd-is-not-exported","parent":"defaultOptions"},{"id":31,"kind":32,"name":"yargs","url":"globals.html#yargs","classes":"tsd-kind-variable tsd-is-not-exported"}]}; \ No newline at end of file + typedoc.search.data = {"kinds":{"32":"Variable","64":"Function","128":"Class","512":"Constructor","1024":"Property","2048":"Method","65536":"Type literal","2097152":"Object literal","4194304":"Type alias"},"rows":[{"id":0,"kind":4194304,"name":"Options","url":"globals.html#options","classes":"tsd-kind-type-alias"},{"id":1,"kind":64,"name":"streamBatch","url":"globals.html#streambatch","classes":"tsd-kind-function tsd-has-type-parameter"},{"id":2,"kind":128,"name":"Uploader","url":"classes/uploader.html","classes":"tsd-kind-class"},{"id":3,"kind":1024,"name":"s3","url":"classes/uploader.html#s3","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":4,"kind":1024,"name":"options","url":"classes/uploader.html#options","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":5,"kind":1024,"name":"bar","url":"classes/uploader.html#bar","classes":"tsd-kind-property tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":6,"kind":512,"name":"constructor","url":"classes/uploader.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class","parent":"Uploader"},{"id":7,"kind":2048,"name":"upload","url":"classes/uploader.html#upload","classes":"tsd-kind-method tsd-parent-kind-class","parent":"Uploader"},{"id":8,"kind":2048,"name":"run","url":"classes/uploader.html#run","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":9,"kind":2048,"name":"getFiles","url":"classes/uploader.html#getfiles","classes":"tsd-kind-method tsd-parent-kind-class tsd-is-private","parent":"Uploader"},{"id":10,"kind":2048,"name":"uploadFile","url":"classes/uploader.html#uploadfile","classes":"tsd-kind-method tsd-parent-kind-class","parent":"Uploader"},{"id":11,"kind":2048,"name":"getCacheControlValue","url":"classes/uploader.html#getcachecontrolvalue","classes":"tsd-kind-method tsd-parent-kind-class","parent":"Uploader"},{"id":12,"kind":32,"name":"glob","url":"globals.html#glob","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":13,"kind":32,"name":"minimatch","url":"globals.html#minimatch","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":14,"kind":32,"name":"path","url":"globals.html#path","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":15,"kind":32,"name":"AWS","url":"globals.html#aws","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":16,"kind":32,"name":"ProgressBar","url":"globals.html#progressbar","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":17,"kind":32,"name":"ora","url":"globals.html#ora","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":18,"kind":32,"name":"chalk","url":"globals.html#chalk","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":19,"kind":32,"name":"fs","url":"globals.html#fs","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":20,"kind":32,"name":"mime","url":"globals.html#mime","classes":"tsd-kind-variable tsd-is-not-exported"},{"id":21,"kind":65536,"name":"__type","url":"globals.html#options.__type","classes":"tsd-kind-type-literal tsd-parent-kind-type-alias tsd-is-not-exported","parent":"Options"},{"id":22,"kind":32,"name":"bucket","url":"globals.html#options.__type.bucket","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":23,"kind":32,"name":"localPath","url":"globals.html#options.__type.localpath","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":24,"kind":32,"name":"remotePath","url":"globals.html#options.__type.remotepath","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":25,"kind":32,"name":"config","url":"globals.html#options.__type.config","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":26,"kind":32,"name":"glob","url":"globals.html#options.__type.glob","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":27,"kind":32,"name":"concurrency","url":"globals.html#options.__type.concurrency","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":28,"kind":32,"name":"dryRun","url":"globals.html#options.__type.dryrun","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":29,"kind":32,"name":"cacheControl","url":"globals.html#options.__type.cachecontrol","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":30,"kind":32,"name":"s3Client","url":"globals.html#options.__type.s3client","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":31,"kind":32,"name":"accessControlLevel","url":"globals.html#options.__type.accesscontrollevel","classes":"tsd-kind-variable tsd-parent-kind-type-literal tsd-is-not-exported","parent":"Options.__type"},{"id":32,"kind":2097152,"name":"defaultOptions","url":"globals.html#defaultoptions","classes":"tsd-kind-object-literal tsd-is-not-exported"},{"id":33,"kind":32,"name":"dryRun","url":"globals.html#defaultoptions.dryrun","classes":"tsd-kind-variable tsd-parent-kind-object-literal tsd-is-not-exported","parent":"defaultOptions"},{"id":34,"kind":32,"name":"concurrency","url":"globals.html#defaultoptions.concurrency","classes":"tsd-kind-variable tsd-parent-kind-object-literal tsd-is-not-exported","parent":"defaultOptions"},{"id":35,"kind":32,"name":"glob","url":"globals.html#defaultoptions.glob","classes":"tsd-kind-variable tsd-parent-kind-object-literal tsd-is-not-exported","parent":"defaultOptions"},{"id":36,"kind":32,"name":"yargs","url":"globals.html#yargs","classes":"tsd-kind-variable tsd-is-not-exported"}]}; \ No newline at end of file diff --git a/docs/classes/uploader.html b/docs/classes/uploader.html index 5614a1f..de6b66e 100644 --- a/docs/classes/uploader.html +++ b/docs/classes/uploader.html @@ -95,10 +95,11 @@

Properties

Methods

@@ -116,7 +117,7 @@

constructor

  • Parameters

    @@ -138,7 +139,7 @@

    Private bar

    bar: any
    @@ -148,7 +149,7 @@

    Private options

    options: Options
    @@ -158,13 +159,42 @@

    Private s3

    s3: S3

    Methods

    +
    + +

    getCacheControlValue

    +
      +
    • getCacheControlValue(file: string): string
    • +
    +
      +
    • + +
      +
      +

      Parameters

      +
        +
      • +
        file: string
        +
        +

        Path to a local file, either relative to cwd, or absolute

        +
        +
      • +
      +

      Returns string

      +

      The resolved CacheControl value based on the provided settings

      +
    • +
    +

    Private getFiles

    @@ -175,10 +205,17 @@

    Private getFiles

  • +
    +
    +

    Based on the local path and the provided glob pattern, this util function will find all relevant + files, which will be used to upload in another step.

    +
    +

    Returns Promise<Array<string>>

    +

    A list of resolved files based on the glob pattern

  • @@ -186,16 +223,16 @@

    Returns Promise

    Private run

      -
    • run(): Promise<void>
    • +
    • run(): Promise<string[]>
    • -

      Returns Promise<void>

      +

      Returns Promise<string[]>

    @@ -203,42 +240,61 @@

    Returns Promise

    upload

      -
    • upload(): Promise<void>
    • +
    • upload(): Promise<string[]>
    • -

      Returns Promise<void>

      +
      +
      +

      Executes the upload operation based on the provided options in the Uploader constructor.

      +
      +
      +

      Returns Promise<string[]>

      +

      A list of paths of the upload files relative to the bucket.

    -
    +
    -

    Private uploadFile

    -
      -
    • uploadFile(localFilePath: string, remotePath: string): Promise<void>
    • +

      uploadFile

      +
        +
      • uploadFile(localFilePath: string, remotePath: string): Promise<string>
      • +
        +
        +

        Uploads a single file to S3 from the local to the remote path with the available options, + and returns the uploaded location.

        +
        +

        Parameters

        • localFilePath: string
          +
          +

          Path to the local file, either relative to cwd, or absolute

          +
        • remotePath: string
          +
          +

          The path to upload the file to in the bucket

          +
        -

        Returns Promise<void>

        +

        Returns Promise<string>

        +

        The remote path upload location relative to the bucket

    @@ -271,6 +327,9 @@

    Returns Promise s3

  • +
  • + getCacheControlValue +
  • getFiles
  • @@ -280,7 +339,7 @@

    Returns Promise upload -
  • +
  • uploadFile
  • @@ -308,6 +367,9 @@

    Returns Promise mime +
  • + minimatch +
  • ora
  • @@ -317,7 +379,7 @@

    Returns Promise yargs -
  • +
  • streamBatch
  • diff --git a/docs/globals.html b/docs/globals.html index 0824e7e..ad6be4d 100644 --- a/docs/globals.html +++ b/docs/globals.html @@ -88,6 +88,7 @@

    Variables

  • fs
  • glob
  • mime
  • +
  • minimatch
  • ora
  • path
  • yargs
  • @@ -96,7 +97,7 @@

    Variables

    Functions

    @@ -116,16 +117,22 @@

    Options

    Options: object

    Type declaration

      +
    • +
      Optional accessControlLevel?: S3.ObjectCannedACL
      +
    • bucket: string
    • +
    • +
      Optional cacheControl?: string | object
      +
    • Optional concurrency?: number
    • @@ -144,6 +151,9 @@
      localPath:
      remotePath: string
      +
    • +
      Optional s3Client?: S3
      +
    @@ -156,7 +166,7 @@

    AWS

    AWS: any = require('aws-sdk')
    @@ -166,7 +176,7 @@

    ProgressBar

    ProgressBar: any = require('progress')
    @@ -176,7 +186,7 @@

    chalk

    chalk: any = require('chalk')
    @@ -186,7 +196,7 @@

    fs

    fs: any = require('fs')
    @@ -196,7 +206,7 @@

    glob

    glob: any = require('glob')
    @@ -206,7 +216,17 @@

    mime

    mime: any = require('mime')
    + +
    + +

    minimatch

    +
    minimatch: any = require('minimatch')
    +
    @@ -216,7 +236,7 @@

    ora

    ora: any = require('ora')
    @@ -226,7 +246,7 @@

    path

    path: any = require('path')
    @@ -236,26 +256,32 @@

    yargs

    yargs: any = require('yargs')

    Functions

    -
    +

    streamBatch

    -
      -
    • streamBatch(__namedParameters: object): Promise<void>
    • +
        +
      • streamBatch<T>(__namedParameters: object): Promise<T[]>
      • +

        Type parameters

        +
          +
        • +

          T

          +
        • +

        Parameters

        • @@ -287,7 +313,7 @@
          processItem:
          • -
          • (file: string): Promise<void>
          • +
          • (file: string): Promise<T>
          • @@ -297,7 +323,7 @@

            Parameters

            file: string
          -

          Returns Promise<void>

          +

          Returns Promise<T>

      • @@ -306,7 +332,7 @@

        Returns Promise

      -

      Returns Promise<void>

      +

      Returns Promise<T[]>

    @@ -319,7 +345,7 @@

    defaultOptions

    defaultOptions: object
    @@ -328,7 +354,7 @@

    concurrency

    concurrency: number = 100
    @@ -338,7 +364,7 @@

    dryRun

    dryRun: boolean = false
    @@ -348,7 +374,7 @@

    glob

    glob: string = "*.*"
    @@ -389,6 +415,9 @@

    glob

  • mime
  • +
  • + minimatch +
  • ora
  • @@ -398,7 +427,7 @@

    glob

  • yargs
  • -
  • +
  • streamBatch
  • diff --git a/docs/index.html b/docs/index.html index 4d049ef..5394f39 100644 --- a/docs/index.html +++ b/docs/index.html @@ -79,19 +79,71 @@

    CLI

    # with env vars AWS_ACCESS_KEY_ID=AKIA...Q AWS_SECRET_ACCESS_KEY=jY...uJ s3-batch-upload -b bucket-name -p ./files -r remote/path/in/bucket -g "*.jpg -C 200 -d" -

    API

    -
    import Uploader from 's3-batch-upload';
    +				
    Usage: cli.js <command> [options]
     
    -await new Uploader({
    -  config: './config/configS3.json', // can also use environment variables
    +Commands:
    +  cli.js upload  Upload files to s3                                                                            [default]
    +
    +Required:
    +  -b, --bucket       The bucket to upload to.                                                        [string] [required]
    +  -p, --local-path   The path to the folder to upload.                                               [string] [required]
    +  -r, --remote-path  The remote path in the bucket to upload the files to.                           [string] [required]
    +
    +Options:
    +  -d, --dry-run        Do a dry run, don't do any upload.                                     [boolean] [default: false]
    +  -C, --concurrency    The amount of simultaneous uploads, increase on faster internet connection.
    +                                                                                                 [number] [default: 100]
    +  -g, --glob           A glob on filename level to filter the files to upload                  [string] [default: "*.*"]
    +  -a, --cache-control  Cache control for uploaded files, can be string for single value or list of glob settings
    +                                                                                                  [string] [default: ""]
    +  -acl, --access-control-level  Sets the access control level for uploaded files
    +                                                                                                  [string] [default: "undefined"]
    +  -c, --config         The AWS config json path to load S3 credentials with loadFromPath.                       [string]
    +  -h, --help           Show help                                                                               [boolean]
    +
    +Examples:
    +  cli.js -b bucket-name -p ./files  -r /data                    Upload files from a local folder to a s3 bucket path
    +  cli.js ... -a "max-age=300"                                  Set cache-control for all files
    +  cli.js ... -a '{ "**/*.json": "max-age=300", "**/*.*":       Upload files from a local folder to a s3 bucket path
    +  "max-age=3600" }'
    +  cli.js -d ...                                                 Dry run upload
    +
    +for more information about AWS authentication, please visit
    +https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html
    +

    API

    +
    import Uploader from 's3-batch-upload';
    +
    +const files = await new Uploader({
    +  config: './config/configS3.json', // can also use environment variables
       bucket: 'bucket-name',
    -  localPath: './files',
    -  remotePath: 'remote/path/in/bucket',
    -  glob: '*.jpg', // default is '*.*'
    +  localPath: './files',
    +  remotePath: 'remote/path/in/bucket',
    +  glob: '*.jpg', // default is '*.*'
       concurrency: '200', // default is 100
       dryRun: true, // default is false
    +  cacheControl: 'max-age=300', // can be a string, for all uploade resources
    +  cacheControl: { // or an object with globs as keys to match the input path
    +    '**/settings.json': 'max-age=60', // 1 mins for settings, specific matches should go first
    +    '**/*.json': 'max-age=300', // 5 mins for other jsons
    +    '**/*.*': 'max-age=3600', // 1 hour for everthing else
    +  },
    +  accessControlLevel: 'bucket-owner-full-control' // optional, not passed if undefined. - available options - "private"|"public-read"|"public-read-write"|"authenticated-read"|"aws-exec-read"|"bucket-owner-read"|"bucket-owner-full-control"
     }).upload();
    +
    +// the files array contains a list of uploaded keys, which you can use to build up the S3 urls.
    +// e.g. "remote/path/in/bucket/demo.jpg"
    +
    +

    S3 Authentication

    +

    As seem above, you can either use environment variables, or a config file.

    +

    When using a config file, add it to the .gitignore, because you don't want your credentials + in your repo. Use the following template for the config file as stated in the AWS Docs:

    +
    {
    +  "accessKeyId": "<YOUR_ACCESS_KEY_ID>",
    +  "secretAccessKey": "<YOUR_SECRET_ACCESS_KEY>",
    +  "region": "us-east-1"
    +}
     
    +

    When using environment variables, check the AWS docs.

    Documentation

    View the generated documentation.

    Building

    @@ -160,6 +212,9 @@

    LICENSE

  • mime
  • +
  • + minimatch +
  • ora
  • @@ -169,7 +224,7 @@

    LICENSE

  • yargs
  • -
  • +
  • streamBatch
  • diff --git a/src/lib/Uploader.ts b/src/lib/Uploader.ts index 46f3d67..a8d592f 100644 --- a/src/lib/Uploader.ts +++ b/src/lib/Uploader.ts @@ -53,11 +53,15 @@ export default class Uploader { this.s3 = this.options.s3Client || new AWS.S3(); } - public upload(): Promise { + /** + * Executes the upload operation based on the provided options in the Uploader constructor. + * @returns A list of paths of the upload files relative to the bucket. + */ + public upload(): Promise { return this.run(); } - private async run(): Promise { + private async run(): Promise { const files = await this.getFiles(); const { concurrency, localPath, remotePath } = this.options; @@ -70,10 +74,10 @@ export default class Uploader { }); // do the work! - await streamBatch({ + const results = await streamBatch({ files, concurrency, - processItem: (file: string): Promise => { + processItem: (file: string): Promise => { const key = path.join(remotePath, file); return this.uploadFile(path.resolve(localPath, file), key); }, @@ -82,8 +86,15 @@ export default class Uploader { // tslint:disable-next-line no-console console.log('Upload complete!'); + + return results; } + /** + * Based on the local path and the provided glob pattern, this util function will find all relevant + * files, which will be used to upload in another step. + * @returns A list of resolved files based on the glob pattern + */ private getFiles(): Promise> { const { localPath, glob: globPath } = this.options; const gatheringSpinner = ora(`Gathering files from ${chalk.blue(localPath)} (please wait) ...`); @@ -106,7 +117,15 @@ export default class Uploader { }); } - public uploadFile(localFilePath: string, remotePath: string): Promise { + /** + * Uploads a single file to S3 from the local to the remote path with the available options, + * and returns the uploaded location. + * + * @param localFilePath Path to the local file, either relative to cwd, or absolute + * @param remotePath The path to upload the file to in the bucket + * @returns The remote path upload location relative to the bucket + */ + public uploadFile(localFilePath: string, remotePath: string): Promise { const body = fs.createReadStream(localFilePath); const { dryRun, bucket: Bucket, accessControlLevel: ACL } = this.options; const params: S3.PutObjectRequest = { @@ -125,14 +144,19 @@ export default class Uploader { this.s3.upload(params, err => { // tslint:disable-next-line no-console if (err) console.error('err:', err); - resolve(); + resolve(params.Key); }); } else { - resolve(); + resolve(params.Key); } }); } + /** + * + * @param file Path to a local file, either relative to cwd, or absolute + * @return The resolved CacheControl value based on the provided settings + */ public getCacheControlValue(file: string): string { const { cacheControl } = this.options; if (cacheControl) { diff --git a/src/lib/batch.ts b/src/lib/batch.ts index 37d58e1..ff190d3 100644 --- a/src/lib/batch.ts +++ b/src/lib/batch.ts @@ -1,22 +1,24 @@ -export type Options = { +export type Options = { concurrency: number; files: Array; - processItem: (file: string) => Promise; + processItem: (file: string) => Promise; onProgress: () => void; }; -export default function streamBatch({ +export default function streamBatch({ concurrency, files, processItem, onProgress, -}: Options): Promise { +}: Options): Promise { return new Promise(resolve => { let count = 0; const total = files.length; + const results: T[] = []; // when upload for one item is done, complete or process the next - const onItemDone = () => { + const onItemDone = (result: T) => { + results.push(result); count += 1; // if completed @@ -24,7 +26,7 @@ export default function streamBatch({ // temp fix for https://github.com/visionmedia/node-progress/pull/183 setTimeout(() => { onProgress(); - resolve(); + resolve(results); }, 50); } else { onProgress(); diff --git a/test/Uploader.spec.ts b/test/Uploader.spec.ts index 3b865b7..b0d817a 100644 --- a/test/Uploader.spec.ts +++ b/test/Uploader.spec.ts @@ -163,5 +163,62 @@ describe('Uploader', () => { }); }); + describe('with uploadFile', () => { + it('should return the uploaded path', async function() { + this.timeout(5000); + + const s3 = { + upload(_, cb) { + cb(null); + } + }; + spy(s3, "upload"); + + uploader = new Uploader({ + localPath: 'test/files', + remotePath: 'fake', + bucket: 'fake', + glob: '**/demo.png', + s3Client: s3, + }); + + const result = await uploader.uploadFile('files/demo.png', 'foo\\bar.png'); + + expect(result).to.equal('foo/bar.png'); + + (s3.upload).restore(); + }); + }); + + describe('with uploadFile', () => { + it('should return the uploaded paths', async function() { + this.timeout(10000); + + const s3 = { + upload(_, cb) { + cb(null); + } + }; + spy(s3, "upload"); + + uploader = new Uploader({ + localPath: 'test/files', + remotePath: 'fake', + bucket: 'fake', + glob: '**/demo.png', + s3Client: s3, + accessControlLevel: 'bucket-owner-full-control' + }); + + const results = await uploader.upload(); + + expect(results).to.deep.equal([ + 'fake/demo.png' + ]); + + (s3.upload).restore(); + }); + }); + }); }); diff --git a/wallaby.js b/wallaby.js new file mode 100644 index 0000000..eb1a3f7 --- /dev/null +++ b/wallaby.js @@ -0,0 +1,24 @@ +module.exports = function(wallaby) { + + return { + files: [ + 'tsconfig.json', + 'src/**/*.*', + 'test/**/*.*', + '!test/**/*.spec.ts', + ], + + tests: ['test/**/*.spec.ts'], + + env: { + type: 'node', + runner: 'node', + }, + + compilers: { + '**/*.ts': wallaby.compilers.babel() + }, + + testFramework: 'mocha', + }; +};