@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 +5 -2
- package/src/cli/deploy/index.js +56 -14
- package/src/cli/release/constants.js +1 -1
- package/src/config/deploy.js +2 -0
- package/src/generators/project/index.js +46 -6
- package/src/generators/project/templates/_common/README.md +0 -4
- package/src/generators/project/templates/_common/package.json +3 -2
- package/src/utils/ftp.js +75 -0
- package/src/utils/text.js +12 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abcnews/aunty",
|
|
3
|
-
"version": "13.0
|
|
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.
|
|
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"
|
package/src/cli/deploy/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
128
|
+
const spinner = spin('Deploying');
|
|
90
129
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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'],
|
package/src/config/deploy.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
|
@@ -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
|
}
|
package/src/utils/ftp.js
ADDED
|
@@ -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, '');
|