@abcnews/aunty 13.0.3 → 13.1.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abcnews/aunty",
3
- "version": "13.0.3",
3
+ "version": "13.1.0",
4
4
  "description": "A toolkit for working with ABC News projects",
5
5
  "repository": "abcnews/aunty",
6
6
  "license": "MIT",
@@ -38,11 +38,13 @@
38
38
  "@babel/preset-env": "^7.6.0",
39
39
  "@babel/preset-react": "^7.0.0",
40
40
  "@babel/preset-typescript": "^7.10.4",
41
+ "await-to-js": "^3.0.0",
41
42
  "babel-core": "^7.0.0-bridge.0",
42
43
  "babel-jest": "^26.1.0",
43
44
  "babel-loader": "^8.2.2",
45
+ "basic-ftp": "^5.0.2",
44
46
  "chalk": "^4.1.2",
45
- "cli-select": "^1.1.0",
47
+ "cli-select": "^1.1.2",
46
48
  "copy-webpack-plugin": "^8.1.1",
47
49
  "css-loader": "^6.7.1",
48
50
  "csv-loader": "^3.0.3",
@@ -95,6 +97,7 @@
95
97
  "@abcaustralia/postcss-config": "^11.2.5"
96
98
  },
97
99
  "devDependencies": {
100
+ "babel-eslint": "^10.1.0",
98
101
  "eslint": "^7.7.0",
99
102
  "eslint-config-prettier": "^8.2.0",
100
103
  "release-it": "^15.1.4"
@@ -5,6 +5,9 @@ const { join } = require('path');
5
5
  // External
6
6
  const importLazy = require('import-lazy')(require);
7
7
  const loadJsonFile = importLazy('load-json-file');
8
+ const { deploymentExists } = require('../../utils/ftp');
9
+ const { to: wrap } = require('await-to-js');
10
+ const cliSelect = importLazy('cli-select');
8
11
 
9
12
  // Ours
10
13
  const { command } = require('../');
@@ -12,10 +15,12 @@ const { addProfileProperties } = require('../../config/deploy');
12
15
  const { getProjectConfig } = require('../../config/project');
13
16
  const { DEPLOY_FILE_NAME, OUTPUT_DIRECTORY_NAME } = require('../../constants');
14
17
  const { packs, throws, unpack } = require('../../utils/async');
15
- const { dry, info, spin, warn } = require('../../utils/logging');
18
+ const { dry, info, spin, warn, log, error } = require('../../utils/logging');
16
19
  const { ftp, rsync } = require('../../utils/remote');
17
20
  const { combine } = require('../../utils/structures');
18
21
  const { DEFAULTS, MESSAGES, VALID_TYPES } = require('./constants');
22
+ const { dim, opt } = require('../../utils/color');
23
+ const { check } = require('prettier');
19
24
 
20
25
  module.exports = command(
21
26
  {
@@ -83,24 +88,61 @@ module.exports = command(
83
88
  // 4b) Deploy
84
89
 
85
90
  for (let target of targets) {
86
- const { publicPath, type } = target;
87
- info(MESSAGES.deploy(target));
91
+ const { publicPath, type, to } = target;
92
+ let shouldOverwrite = false;
93
+
94
+ // If not ftp don't worry about checking external directory
95
+ if (type === 'ftp') {
96
+ const [checkErr] = await wrap(deploymentExists(to));
97
+
98
+ if (checkErr) {
99
+ if (checkErr.code === 550) {
100
+ // Directory doesn't exist. This is actually good though. OK to write.
101
+ shouldOverwrite = true;
102
+ } else {
103
+ error('An FTP error ocurred');
104
+ }
105
+ } else {
106
+ warn('Destination directory exists? OK to overwrite?');
107
+
108
+ const overwriteSelection = (
109
+ await cliSelect({
110
+ defaultValue: 1,
111
+ selected: opt('❯'),
112
+ unselected: ' ',
113
+ values: [
114
+ { label: 'Yes', choice: true },
115
+ { label: 'No', choice: false }
116
+ ],
117
+ valueRenderer: ({ label }, selected) => (selected ? opt(label) : label)
118
+ })
119
+ ).value;
120
+ shouldOverwrite = overwriteSelection.choice;
121
+ log(`${dim(`Destination overwrite: ${shouldOverwrite}`)}\n`);
122
+ }
123
+ }
124
+
125
+ if (shouldOverwrite || type === 'ssh') {
126
+ info(MESSAGES.deploy(target));
88
127
 
89
- const spinner = spin('Deploying');
128
+ const spinner = spin('Deploying');
90
129
 
91
- try {
92
- if (type === 'ftp') {
93
- throws(await ftp(target, spinner));
94
- } else if (type === 'ssh') {
95
- throws(await rsync(target));
130
+ try {
131
+ if (type === 'ftp') {
132
+ throws(await ftp(target, spinner));
133
+ } else if (type === 'ssh') {
134
+ throws(await rsync(target));
135
+ }
136
+ } catch (err) {
137
+ spinner.fail('Deployment failed');
138
+
139
+ throw err;
96
140
  }
97
- } catch (err) {
98
- spinner.fail('Deployment failed');
99
141
 
100
- throw err;
142
+ spinner.succeed(MESSAGES.deployed(publicPath));
143
+ } else {
144
+ log('Exiting');
101
145
  }
102
-
103
- spinner.succeed(MESSAGES.deployed(publicPath));
104
146
  }
105
147
  }
106
148
  );
@@ -2,7 +2,7 @@
2
2
  const { cmd, hvy, ok, opt, sec } = require('../../utils/color');
3
3
 
4
4
  const FORCE_REMINDER = `Use the ${opt('--force')} option to ignore warnings or release without tagging.`;
5
- const VALID_BUMPS = (module.exports.VALID_BUMPS = new Set(['major', 'minor', 'patch','prerelease']));
5
+ const VALID_BUMPS = (module.exports.VALID_BUMPS = new Set(['major', 'minor', 'patch', 'prerelease']));
6
6
 
7
7
  const OPTIONS = (module.exports.OPTIONS = {
8
8
  string: ['bump', 'git-remote'],
@@ -139,3 +139,5 @@ module.exports.addProfileProperties = config => {
139
139
 
140
140
  return combine(config, profileProps);
141
141
  };
142
+
143
+ module.exports.addKnownProfileProperties = addKnownProfileProperties;
@@ -6,6 +6,8 @@ const getAllPaths = require('get-all-paths');
6
6
  const makeDir = require('make-dir');
7
7
  const requireg = require('requireg');
8
8
  const Generator = require('yeoman-generator');
9
+ const { to: wrap } = require('await-to-js');
10
+ const importLazy = require('import-lazy')(require);
9
11
 
10
12
  // Ours
11
13
  const { OUTPUT_DIRECTORY_NAME } = require('../../constants');
@@ -13,6 +15,9 @@ const { cmd, hvy, opt, sec } = require('../../utils/color');
13
15
  const { success } = require('../../utils/logging');
14
16
  const { installDependencies } = require('../../utils/npm');
15
17
  const { combine } = require('../../utils/structures');
18
+ const { sluggify } = require('../../utils/text');
19
+ const { projectExists } = require('../../utils/ftp');
20
+ const { warn, info, error } = importLazy('../../utils/logging');
16
21
 
17
22
  module.exports = class extends Generator {
18
23
  constructor(args, opts) {
@@ -46,13 +51,51 @@ Shorthand examples (assuming xyz is your project name):
46
51
  let prompts = [];
47
52
 
48
53
  if (this.options.here) {
49
- this.options.projectName = path.basename(process.cwd());
54
+ const currentDirectory = path.basename(process.cwd());
55
+
56
+ info(`Info: Using currect directory name as project name:`, currentDirectory, '\n');
57
+
58
+ const [err, exists] = await wrap(projectExists(sluggify(currentDirectory)));
59
+
60
+ if (exists)
61
+ warn(
62
+ 'Warning: Project with the same name detected externally. ' +
63
+ 'Danger of data loss if you continue. ' +
64
+ 'Press ctrl+c to exit and rename project directory.'
65
+ );
66
+
67
+ if (err) {
68
+ warn(
69
+ 'Warning: Unable to check if project name already exists, most likely ' +
70
+ 'due to a connection or credentials error. Please check manually before deploying.\n'
71
+ );
72
+ }
73
+
74
+ this.options.projectName = currentDirectory;
50
75
  } else {
51
76
  prompts.push({
52
77
  type: 'input',
53
78
  name: 'projectName',
54
79
  message: 'What is your project called?',
55
- default: this.options.projectName || 'New Project'
80
+ default: this.options.projectName || 'New Project',
81
+ validate: async input => {
82
+ const [err, exists] = await wrap(projectExists(sluggify(input)));
83
+
84
+ if (exists)
85
+ return (
86
+ 'Error: Project seems to aleady exist on the FTP server and is in ' +
87
+ 'danger of being overwritten. Please try a different name.'
88
+ );
89
+
90
+ if (err) {
91
+ warn(
92
+ 'Warning: Unable to check if project name already exists, most likely ' +
93
+ 'due to a connection or credentials error. Please check manually before deploying.\n'
94
+ );
95
+ }
96
+
97
+ return true;
98
+ }
56
99
  });
57
100
  }
58
101
 
@@ -90,10 +133,7 @@ Shorthand examples (assuming xyz is your project name):
90
133
 
91
134
  this.options.projectName = this.options.projectName.replace(/[^\w\-\_\s]/g, '');
92
135
 
93
- this.options.projectNameSlug = this.options.projectName
94
- .toLowerCase()
95
- .replace(/\s/g, '-')
96
- .replace(/[^0-9a-z\-\_]/g, '');
136
+ this.options.projectNameSlug = sluggify(this.options.projectName);
97
137
 
98
138
  this.options.projectNameFlat = this.options.projectNameSlug.replace(/-/g, '');
99
139
 
@@ -1,7 +1,3 @@
1
1
  # <%= projectName %>
2
2
 
3
3
  A project generated from [aunty](https://github.com/abcnews/aunty)'s `<%= projectType %>` project template.
4
-
5
- ## Authors
6
-
7
- - <%= authorName %> ([<%= authorEmail %>](mailto:<%= authorEmail %>))
@@ -12,12 +12,13 @@
12
12
  },
13
13
  "scripts": {
14
14
  "start": "aunty serve",
15
+ "dev": "aunty serve",
15
16
  "test": "aunty test"
16
- },
17
+ }<% if (projectType === "react") { %>,
17
18
  "abc": {
18
19
  "css": {
19
20
  "libraryDir": "./node_modules/@abcaustralia/nucleus/css",
20
21
  "logVariables": "false"
21
22
  }
22
- }
23
+ }<% } %>
23
24
  }
@@ -0,0 +1,75 @@
1
+ // @ts-check
2
+
3
+ const ftp = require('basic-ftp');
4
+ const { to: wrap } = require('await-to-js');
5
+
6
+ const { addProfileProperties, addKnownProfileProperties } = require('../config/deploy');
7
+
8
+ /**
9
+ * Check if a project exists on FTP
10
+ * @param {string} projectNameSlug
11
+ * @returns {Promise<boolean>}
12
+ */
13
+ const projectExists = async projectNameSlug => {
14
+ const config = addProfileProperties(addKnownProfileProperties({}));
15
+ const { host, username: user, password, to } = config;
16
+ const [baseDir] = to.split('<name>');
17
+
18
+ if (!host || !user || !password) throw new Error('Missing FTP credentials');
19
+
20
+ const client = new ftp.Client();
21
+
22
+ try {
23
+ await client.access({
24
+ host,
25
+ user,
26
+ password,
27
+ secure: false
28
+ });
29
+ await client.cd(baseDir);
30
+ const list = await client.list();
31
+
32
+ for (const item of list) {
33
+ if (projectNameSlug === item.name) return true;
34
+ }
35
+ } catch (err) {
36
+ throw err;
37
+ }
38
+
39
+ client.close();
40
+
41
+ return false;
42
+ };
43
+
44
+ /**
45
+ * Quick FTP check if deployment dir exists
46
+ * @param {string} deployToDir - Remote dir to check
47
+ * @returns {Promise<boolean>}
48
+ */
49
+ const deploymentExists = async deployToDir => {
50
+ const config = addProfileProperties(addKnownProfileProperties({}));
51
+ const { host, username: user, password, to } = config;
52
+
53
+ const client = new ftp.Client();
54
+
55
+ const [accessErr] = await wrap(
56
+ client.access({
57
+ host,
58
+ user,
59
+ password,
60
+ secure: false
61
+ })
62
+ );
63
+ if (accessErr) throw accessErr;
64
+
65
+ const [cdError] = await wrap(client.cd(deployToDir));
66
+ if (cdError) {
67
+ throw cdError;
68
+ }
69
+
70
+ client.close();
71
+
72
+ return false;
73
+ };
74
+
75
+ module.exports = { projectExists, deploymentExists };
package/src/utils/text.js CHANGED
@@ -50,3 +50,15 @@ module.exports.styleLastSegment = (str, style = identity, separator = SLASH) =>
50
50
  })
51
51
  .join(separator);
52
52
  };
53
+
54
+ /**
55
+ * Return a sluggified version of the string
56
+ *
57
+ * @param {string} input - The string to convert
58
+ * @returns {string}
59
+ */
60
+ module.exports.sluggify = input =>
61
+ input
62
+ .toLowerCase()
63
+ .replace(/\s/g, '-')
64
+ .replace(/[^0-9a-z\-\_]/g, '');