Skip to content

Commit

Permalink
Fix upload
Browse files Browse the repository at this point in the history
It was badly promised.
Also add tests.
  • Loading branch information
j0k3r committed Jun 12, 2024
1 parent 9e73e5e commit f4cc0b5
Show file tree
Hide file tree
Showing 12 changed files with 1,842 additions and 89 deletions.
8 changes: 0 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,29 @@ on:
jobs:
lint:
name: Quality checks

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'yarn'

- run: yarn install
- run: yarn build
- run: yarn lint

test:
name: Tests

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'yarn'

- run: yarn install
- run: yarn test
2 changes: 1 addition & 1 deletion .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
node-version: 20
registry-url: https://registry.npmjs.org/
- run: yarn install
- run: yarn test
- run: yarn build-and-test
- run: yarn publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
node_modules

.DS_Store
*.zip

esm/
lib/
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
.nvmrc
babel.config.js
src
tests
jest.config.js
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ await s3UnzipPlus({
bucket: 'test-bucket-in-s3',
file: 'Companies.zip',
targetBucket: 'test-output-bucket',
targetKey: 'test-folder',
targetFolder: 'test-folder',
copyMetadata: true,
deleteOnSuccess: true,
verbose: false
Expand Down
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @type {import('jest').Config} */
const config = {
verbose: true,
testEnvironment: 'node',
"transform": {
"^.+\\.(js)$": "babel-jest"
},
}

module.exports = config
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
"build:cjs": "BABEL_ENV=cjs babel src --out-dir lib",
"build:esm": "BABEL_ENV=esm babel src --out-dir esm",
"clean": "rimraf ./dist ./lib ./esm",
"test": "yarn clean && yarn build",
"lint": "eslint bin/s3-unzip-plus src/"
"build-and-test": "yarn clean && yarn build && yarn test",
"test": "jest --silent",
"test:watch": "jest --watch",
"lint": "eslint bin/s3-unzip-plus src/ tests/"
},
"repository": {
"type": "git",
Expand All @@ -42,6 +44,8 @@
"@babel/eslint-parser": "^7.24.7",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"aws-sdk-client-mock": "^4.0.1",
"aws-sdk-client-mock-jest": "^4.0.1",
"eslint": "8",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0",
Expand All @@ -50,6 +54,7 @@
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.2",
"jest": "^29.7.0",
"prettier": "^3.3.1",
"rimraf": "^5.0.7"
}
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default async ({
deleteOnSuccess = false,
copyMetadata = false,
verbose = false,
region = null,
}) => {
await decompress({
bucket,
Expand All @@ -40,6 +41,7 @@ export default async ({
deleteOnSuccess: !!deleteOnSuccess,
copyMetadata: !!copyMetadata,
verbose: !!verbose,
region,
})
}

Expand Down
112 changes: 64 additions & 48 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ SOFTWARE.
*/

import { Upload } from '@aws-sdk/lib-storage'
import { S3 } from '@aws-sdk/client-s3'
import { DeleteObjectCommand, GetObjectCommand, S3Client } from '@aws-sdk/client-s3'
import AdmZip from 'adm-zip'
import fs from 'fs'
import md5 from 'md5'
import mime from 'mime-types'

const s3 = new S3()

export const decompress = async (command) => {
const client = new S3Client({
region: command.region,
})

const targetBucket = command.targetBucket ?? command.bucket
let targetFolder = command.targetFolder ?? ''
if (targetFolder.length > 0) {
Expand All @@ -38,16 +40,18 @@ export const decompress = async (command) => {

if (!command.bucket || !command.file) {
// bucket and file are required
console.error('Error: missing either bucket name, full filename, targetBucket or targetKey!')
console.error('Error: missing either "bucket" or "file"!')

return
}

const getObject = new GetObjectCommand({
Bucket: command.bucket,
Key: command.file,
})

try {
const data = await s3.getObject({
Bucket: command.bucket,
Key: command.file,
})
const data = await client.send(getObject)

if (command.verbose) {
console.log(`Zip file '${command.file}' found in S3 bucket!`)
Expand All @@ -56,7 +60,10 @@ export const decompress = async (command) => {
let metadata = {}
if (command.copyMetadata) {
metadata = data.Metadata
console.log('zip metadata', metadata)

if (command.verbose) {
console.log('Zip metadata', JSON.stringify(metadata))
}
}

// write the zip file locally in a tmp dir
Expand Down Expand Up @@ -92,55 +99,64 @@ export const decompress = async (command) => {

// for each file in the zip, decompress and upload it to S3; once all are uploaded, delete the tmp zip and zip on S3
let counter = 0
zipEntries.forEach(async (zipEntry) => {
try {
const dataUpload = await new Upload({
client: s3,
params: {
Bucket: targetBucket,
Key: targetFolder + zipEntry.entryName,
Body: zipEntry.getData(),
Metadata: metadata,
},
}).done()

counter += 1

if (command.verbose) {
console.log(`File decompressed to S3: ${dataUpload.Location}`)
}

// if all files are unzipped...
if (zipEntryCount === counter) {
// delete the tmp (local) zip file
fs.unlinkSync(`/tmp/${tmpZipFilename}.zip`)
await Promise.all(
zipEntries.map(async (zipEntry) => {
try {
const dataUpload = await new Upload({
client,
params: {
Bucket: targetBucket,
Key: targetFolder + zipEntry.entryName,
Body: zipEntry.getData(),
Metadata: metadata,
},
}).done()

counter += 1

if (command.verbose) {
console.log('Local temp zip file deleted.')
console.log(`File decompressed to S3: ${dataUpload.Location}`)
}

// delete the zip file up on S3
if (command.deleteOnSuccess) {
try {
await s3.deleteObject({ Bucket: command.bucket, Key: command.file })
// if all files are unzipped...
if (zipEntryCount === counter) {
// delete the tmp (local) zip file
fs.unlinkSync(`/tmp/${tmpZipFilename}.zip`)

if (command.verbose) {
console.log(`S3 file '${command.file}' deleted.`)
}
if (command.verbose) {
console.log('Local temp zip file deleted.')
}

// delete the zip file up on S3
if (command.deleteOnSuccess) {
const deleteObject = new DeleteObjectCommand({
Bucket: command.bucket,
Key: command.file,
})
try {
await client.send(deleteObject)

if (command.verbose) {
console.log(`S3 file '${command.file}' deleted.`)
}

console.log('Success!')
} catch (errDelete) {
console.error(`Delete Error: ${errDelete.message}`)
}
} else {
console.log('Success!')
} catch (errDelete) {
console.error(`Delete Error: ${errDelete.message}`)
}
} else {
console.log('Success!')
}
} catch (errUpload) {
console.error(errUpload)
console.error(`Upload Error: ${errUpload.message}`)
fs.unlinkSync(`/tmp/${tmpZipFilename}.zip`)
}
} catch (errUpload) {
console.error(`Upload Error: ${errUpload.message}`)
fs.unlinkSync(`/tmp/${tmpZipFilename}.zip`)
}
})

return true
})
)
} catch (err) {
console.error(`File Error: ${err.message}`)
}
Expand Down
Binary file added tests/fixtures/t.zip
Binary file not shown.
Loading

0 comments on commit f4cc0b5

Please sign in to comment.