dorky 2.3.9 → 2.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +6 -2
  2. package/bin/index.js +50 -19
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -381,8 +381,8 @@ ISC License - see [LICENSE](LICENSE) file for details.
381
381
  ## Roadmap
382
382
 
383
383
  - [x] Update README with AWS IAM policy (bug fix release)
384
- - [*] Handle invalid access token for Google Drive and AWS (edge cases)
385
- - [ ] rm + push should delete file from storage (minor release)
384
+ - [x] Handle invalid access token for Google Drive and AWS (edge cases)
385
+ - [x] rm + push should delete file from remote storage (minor release)
386
386
  - [ ] Uninitialize dorky setup (Bug fix release)
387
387
  - [ ] dorky --list remote --update should sync metadata according to remote (Minor release)
388
388
  - [ ] Extension for VS Code to list and highlight them like git (Major release)
@@ -390,4 +390,8 @@ ISC License - see [LICENSE](LICENSE) file for details.
390
390
  - [ ] Encryption of files (Minor release)
391
391
  - [ ] Add stages for variables (Major release)
392
392
  - [ ] Migrate dorky project to another storage (partially implemented)
393
+ - [ ] Add more test cases
394
+ - [ ] Deletion of files
395
+ - [ ] Edge cases for failure when credentials are invalid
396
+ - [ ] Add coverage reports badges
393
397
 
package/bin/index.js CHANGED
@@ -8,7 +8,7 @@ const path = require("path");
8
8
  const mimeTypes = require("mime-types");
9
9
  const md5 = require('md5');
10
10
  const EOL = require("os").type() == "Darwin" ? "\r\n" : "\n";
11
- const { GetObjectCommand, PutObjectCommand, ListObjectsV2Command, S3Client } = require("@aws-sdk/client-s3");
11
+ const { GetObjectCommand, PutObjectCommand, ListObjectsV2Command, DeleteObjectCommand, S3Client } = require("@aws-sdk/client-s3");
12
12
  const { authenticate } = require('@google-cloud/local-auth');
13
13
  const { google } = require('googleapis');
14
14
 
@@ -232,14 +232,15 @@ async function runS3(creds, fn) {
232
232
  }
233
233
  }
234
234
 
235
- async function getFolderId(pathStr, drive) {
235
+ async function getFolderId(pathStr, drive, create = true) {
236
236
  let parentId = 'root';
237
237
  if (!pathStr || pathStr === '.') return parentId;
238
238
  for (const folder of pathStr.split("/")) {
239
239
  if (!folder) continue;
240
- const res = await drive.files.list({ q: `name='${folder}' and mimeType='application/vnd.google-apps.folder' and '${parentId}' in parents`, fields: 'files(id)' });
240
+ const res = await drive.files.list({ q: `name='${folder}' and mimeType='application/vnd.google-apps.folder' and '${parentId}' in parents and trashed=false`, fields: 'files(id)' });
241
241
  if (res.data.files[0]) parentId = res.data.files[0].id;
242
- else parentId = (await drive.files.create({ requestBody: { name: folder, mimeType: 'application/vnd.google-apps.folder', parents: [parentId] }, fields: 'id' })).data.id;
242
+ else if (create) parentId = (await drive.files.create({ requestBody: { name: folder, mimeType: 'application/vnd.google-apps.folder', parents: [parentId] }, fields: 'id' })).data.id;
243
+ else return null;
243
244
  }
244
245
  return parentId;
245
246
  }
@@ -263,36 +264,66 @@ async function push() {
263
264
  checkDorkyProject();
264
265
  if (!await checkCredentials()) return;
265
266
  const meta = readJson(METADATA_PATH);
266
- const files = Object.keys(meta["stage-1-files"])
267
+ const filesToUpload = Object.keys(meta["stage-1-files"])
267
268
  .filter(f => !meta["uploaded-files"][f] || meta["stage-1-files"][f].hash !== meta["uploaded-files"][f].hash)
268
269
  .map(f => ({ name: f, ...meta["stage-1-files"][f] }));
269
270
 
270
- if (files.length === 0) return console.log(chalk.yellow("ℹ Nothing to push."));
271
+ const filesToDelete = Object.keys(meta["uploaded-files"])
272
+ .filter(f => !meta["stage-1-files"][f]);
273
+
274
+ if (filesToUpload.length === 0 && filesToDelete.length === 0) return console.log(chalk.yellow("ℹ Nothing to push."));
271
275
 
272
276
  const creds = readJson(CREDENTIALS_PATH);
273
277
  if (creds.storage === "aws") {
274
278
  await runS3(creds, async (s3, bucket) => {
275
- await Promise.all(files.map(async f => {
276
- const key = path.join(path.basename(process.cwd()), f.name);
277
- await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: readFileSync(f.name) }));
278
- console.log(chalk.green(`✔ Uploaded: ${f.name}`));
279
- }));
279
+ if (filesToUpload.length > 0) {
280
+ await Promise.all(filesToUpload.map(async f => {
281
+ const key = path.join(path.basename(process.cwd()), f.name);
282
+ await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: readFileSync(f.name) }));
283
+ console.log(chalk.green(`✔ Uploaded: ${f.name}`));
284
+ }));
285
+ }
286
+ if (filesToDelete.length > 0) {
287
+ await Promise.all(filesToDelete.map(async f => {
288
+ const key = path.join(path.basename(process.cwd()), f);
289
+ await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
290
+ console.log(chalk.yellow(`✔ Deleted remote: ${f}`));
291
+ }));
292
+ }
280
293
  });
281
294
  } else if (creds.storage === "google-drive") {
282
295
  await runDrive(async (drive) => {
283
- for (const f of files) {
296
+ if (filesToUpload.length > 0) {
297
+ for (const f of filesToUpload) {
298
+ const root = path.basename(process.cwd());
299
+ const parentId = await getFolderId(path.dirname(path.join(root, f.name)), drive);
300
+ await drive.files.create({
301
+ requestBody: { name: path.basename(f.name), parents: [parentId] },
302
+ media: { mimeType: f["mime-type"], body: createReadStream(f.name) }
303
+ });
304
+ console.log(chalk.green(`✔ Uploaded: ${f.name}`));
305
+ }
306
+ }
307
+ if (filesToDelete.length > 0) {
284
308
  const root = path.basename(process.cwd());
285
- const parentId = await getFolderId(path.dirname(path.join(root, f.name)), drive);
286
- await drive.files.create({
287
- requestBody: { name: path.basename(f.name), parents: [parentId] },
288
- media: { mimeType: f["mime-type"], body: createReadStream(f.name) }
289
- });
290
- console.log(chalk.green(`✔ Uploaded: ${f.name}`));
309
+ for (const f of filesToDelete) {
310
+ const parentId = await getFolderId(path.dirname(path.join(root, f)), drive, false);
311
+ if (parentId) {
312
+ const res = await drive.files.list({
313
+ q: `name='${path.basename(f)}' and '${parentId}' in parents and trashed=false`,
314
+ fields: 'files(id)'
315
+ });
316
+ if (res.data.files[0]) {
317
+ await drive.files.delete({ fileId: res.data.files[0].id });
318
+ console.log(chalk.yellow(`✔ Deleted remote: ${f}`));
319
+ }
320
+ }
321
+ }
291
322
  }
292
323
  });
293
324
  }
294
325
 
295
- meta["uploaded-files"] = { ...meta["uploaded-files"], ...meta["stage-1-files"] };
326
+ meta["uploaded-files"] = { ...meta["stage-1-files"] };
296
327
  writeJson(METADATA_PATH, meta);
297
328
  }
298
329
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dorky",
3
- "version": "2.3.9",
3
+ "version": "2.3.10",
4
4
  "description": "DevOps Records Keeper.",
5
5
  "bin": {
6
6
  "dorky": "bin/index.js"