Skip to content

Commit

Permalink
Merge pull request #11 from cloudinary/2.1.0-release
Browse files Browse the repository at this point in the history
2.1.0 release
  • Loading branch information
achumachenko-cloudinary authored Nov 19, 2024
2 parents dc9822b + 75c1d63 commit 1d7a124
Show file tree
Hide file tree
Showing 19 changed files with 499 additions and 139 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# CHANGELOG


[2.1.0] / 2024-11-12
====================

### Added
- Scripts to monitor logs for an ongoing bulk operation with instructions in README
- Explicitly reporting API responses with `existing` property as `SkippedAlreadyExists` value for the `Cld_Operation` column in a migration report file

### Changed
- Updated outdated dependencies


[2.0.1] / 2024-02-09
====================

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ Follow these steps to successfully migrate your assets:
3. [⚙️ Configure the Script](./readme/configure.md) - Customize the script's settings for your specific migration needs.
4. [🚚 Run the Script and Obtain the Report](./readme/run-migration-obtain-report.md) - Execute the script and review the migration report.
5. [🔄 Iterate for Failed Migrations](./readme/identify-reattempt-failed.md) - Identify failed asset migrations and rerun the script to fix them.

# How to Tweak It
Things to know are covered in the [🧑‍💻 dev readme](./readme/dev/readme.md).
28 changes: 19 additions & 9 deletions __input-to-api-payload.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,26 @@
* - options: options for the Cloudinary Upload API call
*/
exports.input2ApiPayload = function(csvRec) {
const file = csvRec.Url;
const options = {
public_id: csvRec.Id,
unique_filename: false,
resource_type: 'auto',
type: 'upload',
tags: csvRec.Tags,
// Pass value from 'Url' column with the asset URLs or paths
const file = csvRec['Url'];

// Optional parameters for the Cloudinary API
const options = {
public_id: csvRec['Id'], // Pass value from 'Id' column to be used as public_id
unique_filename: false, // Do not add random suffix to the public_id
resource_type: 'auto', // Let Cloudinary determine the resource type
overwrite: false, // Do not overwrite the asset with same public_id if it already exists
type: 'upload', // Explicitly set delivery type
tags: csvRec['Tags'], // Pass value from 'Tags' column as tags

context: {
caption: csvRec.Description,
}
caption: csvRec['Description'], // Pass value from 'Description' column as contextual metadata
},

metadata: {
sample_field: csvRec['SampleField'], // Pass value from 'SampleField' column into the structured metadata field
// with external_id of 'sample_field'
},
};

return { file, options };
Expand Down
7 changes: 6 additions & 1 deletion __log-to-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ function extractMigrationFlowRecord(logLine) {
}
migrationSummaryRec.Cld_Error = errInfo;
} else {
migrationSummaryRec.Cld_Operation = logRec.response.overwritten ? 'Overwritten' : 'Uploaded';
// Resolving operation
let resolvedMigrationOp = 'Uploaded';
if (logRec.response.existing === true) { resolvedMigrationOp = 'SkippedAlreadyExists' }
if (logRec.response.overwritten === true) { resolvedMigrationOp = 'Overwritten' }

migrationSummaryRec.Cld_Operation = resolvedMigrationOp;
migrationSummaryRec.Cld_PublicId = logRec.response.public_id;
migrationSummaryRec.Cld_Etag = logRec.response.etag;
}
Expand Down
2 changes: 1 addition & 1 deletion cld-bulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function configureProgram(program) {
program
.name('cld-bulk')
.description('Extensible CLI tool to efficiently translate CSV file records into Cloudinary API operations')
.version('2.0.1');
.version('2.1.0');
}


Expand Down
6 changes: 0 additions & 6 deletions jest.config.js

This file was deleted.

36 changes: 36 additions & 0 deletions monitor-migration/count-log-ops.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash

# File to be monitored
LOGFILE=$1

# Processing payload entries from the log to produce tally
grep -F '"flow":"payload"' $LOGFILE | \
awk '
BEGIN {
# Explicitly initialize variables to 0
created = 0
overwritten = 0
existing = 0
failure = 0
}
{
migrated = index($0, "\"status\":\"MIGRATED\"")
if (migrated) {
if (index($0, "\"existing\":true")) {
existing++
} else if (index($0, "\"overwritten\":true")) {
overwritten++
} else {
created++
}
} else {
failure++
}
}
END {
print "🟢 Created : ", created
print "🟡 Overwritten : ", overwritten
print "⚪️ Existing (skipped) : ", existing
print "🔴 Failed : ", failure
}
'
8 changes: 8 additions & 0 deletions monitor-migration/trace-failed-log-ops.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

# Log file to be scanned
LOGFILE=$1

# Processing payload entries with status different from MIGRATED
grep -F '"flow":"payload"' $LOGFILE | grep -F -v '"status":"MIGRATED"' | \
jq -r '(.summary.err | tostring)'
31 changes: 18 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"jest": "^29.6.2"
},
"scripts": {
"test": "jest --verbose"
"test": "node ./test/jest.run-all-tests.js"
},
"version": "2.0.1"
"version": "2.1.0"
}
23 changes: 23 additions & 0 deletions readme/dev/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Things to know about

## Layout

### App Components
All of the app components (and tests for them) are expected to be under the `lib` folder.

This is important because tests are explicitly invoked from under the folder

### App Tests
jest test framework is used. Use `npm test` to run all tests (unit tests and end-to-end tests).

Custom configuration is used - see the `scripts.test` in `package.json`.

Test modules are maintained under the `test` folder.


## End2End Tests
End to end tests require to be executed in certain order (see the `test/jest.run-all-tests.js` file).

- a temporary cloud is provisioned when running tests
- if you want to use a different cloud (for debugging purposes, for example) - place `.env` file with Cloudinary credentials under the `test/end2end` folder
* then the test migration operations will be performed against that cloud
35 changes: 28 additions & 7 deletions readme/run-migration-obtain-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,38 @@ node ./cld-bulk.js migrate \

# Monitoring for errors

The migration script keeps updating the `log.json` file in the specified output folder.
The migration script keeps updating the `log.jsonl` file in the specified output folder.

Oftentime when errors do occur it is helpful to know what types of errors those are (network "hiccups" or incorrect upload API parameters).

If you would like to monitor for errors in the log file during the script execution you can adjust the following command:
To assist with monitoring an ongoing bulk migration the following scripts are available with the tool.

## Script to count tally of operations performed so far

```bash
#
# Make sure to replace <input-field-name> with a column name from the input CSV file
# (for example, the one you use to pass `public_id` for the asset)
#
# Assumes you are in the root folder of the repository
monitor-migration/count-log-ops.sh path/to/ongoing/migration/log.jsonl
```

Provides output such as:
```
🟢 Created : 987
🟡 Overwritten : 65
⚪️ Existing (skipped) : 43
🔴 Failed : 21
```

tail -f log.jsonl | jq -r 'select(.summary.status != "MIGRATED") | [.input.<input-field-name>, .summary.status, "--", .summary.err] | join(" ")'
## Script to output information for all failed operations
```bash
# Assumes you are in the root folder of the repository
monitor-migration/trace-failed-log-ops.sh path/to/ongoing/migration/log.jsonl
```

Provides output such as:
```
{"error":{"message":"Request Timeout","http_code":499,"name":"TimeoutError"}}
{"message":"Error in loading https://test.img/url - 503 Service Unavailable","name":"Error","http_code":400}
{"error":{"message":"Request Timeout","http_code":499,"name":"TimeoutError"}}
{"error":{"message":"Request Timeout","http_code":499,"name":"TimeoutError"}}
{"message":"Server returned unexpected status code - 502","http_code":502,"name":"UnexpectedResponse"}
```
14 changes: 0 additions & 14 deletions test/__global-e2e-setup.js

This file was deleted.

14 changes: 0 additions & 14 deletions test/__global-e2e-teardown.js

This file was deleted.

Loading

0 comments on commit 1d7a124

Please sign in to comment.