@leverege/build-tools 2.0.5 → 2.0.7

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.
@@ -1,320 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const chalk = require( 'chalk' )
4
- const cliArgs = require( 'command-line-args' )
5
- const cliHelp = require( 'command-line-usage' )
6
- const exec = require( 'child_process' ).execSync
7
- const fs = require( 'fs' )
8
- const glob = require( 'glob' )
9
- const parse = require( 'parse-gitignore' )
10
- const ask = require( 'readline-sync' )
11
- const YAML = require( 'js-yaml' )
12
-
13
- const optionsDefinitions = [
14
- { name : 'context', alias : 'x', type : String, default : '' },
15
- { name : 'section', alias : 's', type : String, default : 'default' },
16
- { name : 'key', alias : 'k', type : String },
17
- { name : 'export', alias : 'e', type : Boolean, default : false },
18
- { name : 'continue', alias : 'c', type : Boolean, default : false },
19
- { name : 'checkctx', alias : 't', type : Boolean, default : false },
20
- { name : 'verbose', alias : 'v', type : Boolean, default : false },
21
- ]
22
- const args = cliArgs( optionsDefinitions )
23
-
24
- // The kubernetes context is equal to the git branch name.
25
- const gitBranch = require( 'git-branch' ).sync()
26
- const context = args.context || gitBranch
27
-
28
- if ( context == 'master' ) {
29
- console.log( '***ERROR: master context is forbidden; change to a different branch\n\n' )
30
- process.exit( 1 )
31
- }
32
-
33
- // Load the default values and then overlay with the project specific yaml
34
- // values. This supports the notion of this type of approach in the
35
- // overwhelm yaml settings:
36
- // default:
37
- // GCE_MACHINE : "n1-standard-2"
38
- //
39
- // my-project:
40
- // GCE_MACHINE : "n1-highcpu-8"
41
- //
42
- // fashion, but it is advised not to set a default region with this
43
- // approach in order to keep us cognizant of exactly where a cluster is
44
- // being formed.
45
- //
46
- const yaml = YAML.safeLoad( fs.readFileSync( 'overwhelm.yaml', 'utf-8' ) )
47
- const over = yaml.default
48
- let cfgs = yaml[context]
49
- let wtfs = cfgs
50
-
51
- // If we just need to check context return 0 if cfgs exists, else error.
52
- if ( args.checkctx ) { process.exit( !cfgs ) }
53
-
54
- if ( !cfgs ) {
55
- console.log( `***ERROR: Unknown context => [${context}]\n` )
56
- console.log( ' Known k8s contexts are:' )
57
- Object.keys( yaml ).forEach( ( key ) => {
58
- if ( key !== 'default' ) { console.log( ` ${key}` ) }
59
- } )
60
- console.log( `Add a section into overwhelm.yaml for ${context}\n\n` )
61
- process.exit( 1 )
62
- }
63
-
64
- // Check to see if we are deriving from another configuration.
65
- if ( cfgs['PROJECT_BASE'] ) {
66
- const baseName = cfgs['PROJECT_BASE']
67
- const tempCfgs = cfgs
68
- cfgs = yaml[baseName]
69
- Object.keys( tempCfgs ).forEach( ( key ) => { cfgs[key] = tempCfgs[key] } )
70
- console.log( "PROJECT_BASE still under evaluation" )
71
- console.log( "\n cfgs=", cfgs )
72
- process.exit( 1 ) //XXX HERE
73
- }
74
-
75
- Object.keys( cfgs ).forEach( ( key ) => { over[key] = cfgs[key] || over[key] } )
76
-
77
- // Expand any variables that reference other variable settings. A perfect
78
- // example of where this is useful is in the setting of a PROJECT_NAME and
79
- // a PROJECT_ID. Most of the time these values are identical, which is why
80
- // this setting exists in the default section:
81
- // default:
82
- // PROJECT_ID : ${PROJECT_NAME}
83
- //
84
- // However, in the case of projects like Siren Marine, this is the more
85
- // likely setup due to legacy naming schemes:
86
- // sire-marine:
87
- // PROJECT_NAME : siren-marine
88
- // PROJECT_ID : prod-rt-data
89
- //
90
- const varErrors = []
91
- Object.keys( over ).forEach( ( key ) => {
92
- if ( !over[key] ) return // no value to work with - skip it
93
-
94
- // Look for something in the form of "thing-${VAR1}-${VAR2}-${VARn}-stuff"
95
- const matches = over[key].match( /\$\{\w+\}/g )
96
- if ( !matches ) return
97
-
98
- matches.forEach( ( replaceThis ) => {
99
- // The matched variable names will be in the form of ${VARNAME} so drop
100
- // the ${} characters before using the VARNAME to map into the
101
- // overwhelm map containing the desired replacement value.
102
- const withThat = over[replaceThis.replace( /\W+/g, '' )]
103
- if ( !withThat ) {
104
- varErrors.push( `${key} : ${over[key]}` )
105
- return
106
- }
107
- // Store the replaced string back in the overwhelm value map.
108
- over[key] = over[key].replace( replaceThis, withThat )
109
- } )
110
- } )
111
-
112
- if ( varErrors.length > 0 ) {
113
- console.log( '***ERROR: unkown variable reference(s) in overwhelm.yaml:\n' )
114
- varErrors.forEach( ( error ) => {
115
- console.log( ` ${error}` )
116
- } )
117
- console.log('' )
118
- process.exit( 1 )
119
- }
120
-
121
- // Grab a list of the existing yaml templates.
122
- const yams = glob.sync( 'values-*.yaml' )
123
-
124
- // A function to apply the replacements to all of the matching yaml which
125
- // will error out if it runs into an unknown OVH<tag>.
126
- const doReplacements = ( yamls, replacements ) => {
127
- let replYaml = yamls
128
-
129
- Object.keys( replacements ).forEach( ( repl ) => {
130
- const replaceThis = new RegExp( `OVH:<${repl}>`, 'g' )
131
- const withThat = `${replacements[repl]}`
132
- replYaml = replYaml.replace( replaceThis, withThat )
133
- } )
134
-
135
- // Verify all replaceables have been handled, or error out.
136
- const missed = replYaml.match( /OVH:<(.*)>/g )
137
-
138
- if ( missed ) {
139
- console.log( '\n***ERROR: missing replacements in overwhelm.yaml for these tags:\n' )
140
- missed.forEach( ( miss ) => {
141
- console.log( ` TAG: ${miss.match( /OVH:<(.*)>/)[1]}` )
142
- } )
143
- console.log('' )
144
- process.exit( 1 )
145
- }
146
-
147
- return replYaml
148
- }
149
-
150
- // Collect all of the yaml from the yams, and always expect the default and
151
- // platform yamls to be in that list.
152
- const buildYaml = ( yamls, replacements ) => {
153
- // We always start with default but values-platform is no longer needed.
154
- const always = [ 'values-default.yaml' ]
155
- const values = [ ...always, ...yamls ]
156
- const loaded = []
157
- let allYamls = ''
158
-
159
- values.forEach( ( yaml ) => {
160
- if ( !fs.existsSync( yaml ) ) {
161
- console.log( `\n***ERROR: yaml file missing => ${yaml}\n` )
162
- process.exit( 1 )
163
- }
164
-
165
- if ( !loaded.includes( yaml ) ) {
166
- allYamls += `\n# AHOY => ${yaml}\n\n`
167
- allYamls += fs.readFileSync( yaml, { encoding : 'utf-8' } )
168
- loaded.push( yaml )
169
- }
170
- } )
171
-
172
- // Now apply all of the replacements from the overwhelm file.
173
- return doReplacements( allYamls, replacements )
174
- }
175
-
176
- // Call buildYaml to replace the OVH strings in the yaml files.
177
- const values = buildYaml( yams, over )
178
-
179
- // Check to see if someone is requesting a value from the yaml.
180
- if ( args.key ) {
181
- const section = args.section || 'default'
182
- const keys = yaml[section]
183
- if ( args.verbose ) {
184
- console.log( 'replacements' )
185
- console.log( keys )
186
- }
187
- if ( args.export ) {
188
- console.log( `export ${args.key}=${keys[args.key]}` )
189
- }
190
- else {
191
- console.log( keys[args.key] )
192
- }
193
- if ( ! args.continue ) process.exit()
194
- }
195
-
196
- // Find all of the potential target dirs. Utilize .gitignore to ignore files
197
- const opt = {
198
- ignore : parse( fs.readFileSync( '.gitignore' ) )
199
- }
200
-
201
- const ahoy = glob.sync( '*/', opt )
202
-
203
- // Keel supports a "never" policy which will cause it to skip over a release
204
- // if it is properly set. Adding a .nokeel file to a release directoy will
205
- // cause the creation of the file if it does not already exist.
206
- const generateKeelNeverPolicy = ( fileName ) => {
207
- if ( fs.existsSync( fileName ) ) return
208
- const neverPolicy = `
209
- keel:
210
- # keel policy (all/major/minor/patch/force)
211
- policy: "never"
212
- # approvals
213
- # approvals: 1
214
- # approvalDeadline: 24
215
- # # images to track and update
216
- # images:
217
- # - repository: never.IMAGE # [1]
218
- # tag: never.VERSION # [2]
219
- `
220
- fs.writeFileSync( fileName, neverPolicy )
221
- }
222
-
223
- // Generate the values.yaml files in directories not marked with .nohelm.
224
- ahoy.forEach( ( dir ) => {
225
- if ( !fs.existsSync( `${dir}/.nohelm` ) ) {
226
- console.log( `Generating values in ${dir}` )
227
-
228
- let valuesOut = [] // An accumulator for all of the output values.
229
-
230
- // Add support for localized values for things like keel (or whatever)
231
- const valuesLocal = `${dir}values-local.yaml`
232
-
233
- if ( fs.existsSync( `${dir}.nokeel` ) ) {
234
- generateKeelNeverPolicy( valuesLocal )
235
- }
236
-
237
- if ( fs.existsSync( valuesLocal ) ) {
238
- console.log( ` Local values in ${valuesLocal}` )
239
- valuesOut += `\n# AHOY => values-local.yaml\n\n`
240
- valuesOut += fs.readFileSync( valuesLocal, { encoding : 'utf-8' } )
241
- }
242
- valuesOut += `\n${values}`
243
- valuesOut = doReplacements( valuesOut, over )
244
-
245
- fs.writeFileSync( `${dir}/values.yaml`, valuesOut )
246
- }
247
- } )
248
-
249
- // Set the GCP context for safety!
250
- const clusterName = over['CLUSTER_NAME']
251
- const projectId = over['PROJECT_ID']
252
- const zone = over['GCE_REGION'] + ( over['GCE_ZONE'] ? `-${over['GCE_ZONE']}` : '' )
253
-
254
- if ( !clusterName ) {
255
- console.log( chalk.yellow(
256
- `
257
-
258
- The overwhelm.yaml file in this branch is missing a CLUSTER_NAME setting,
259
- which was added to support cluster names that do not match the project
260
- name. Since the mismatch is rare, you can probably get by with simply
261
- adding this line following PROJECT_NAME in the default section of
262
- overwhelm.yaml:
263
-
264
- ${chalk.bold.green( `CLUSTER_NAME : "\${PROJECT_NAME}"` )}
265
-
266
- However, if the CLUSTER_NAME is not the same as the PROJECT_NAME then go
267
- ahead and add the CLUSTER_NAME setting to the ${chalk.bold.green(projectId)} section of the
268
- overwhelm.yaml file.
269
-
270
- ` ) )
271
- process.exit( 1 )
272
- }
273
-
274
- let kubeout = '_no_current_context_'
275
- try {
276
- // if current is not set exec will throw
277
- kubeout = exec( 'kubectl config current-context' )
278
- } catch (err) { }
279
-
280
- const currentCtx = kubeout.toString().trim()
281
- const desiredCtx = `gke_${projectId}_${zone}_${clusterName}`
282
- const matchedCtx = ( currentCtx === desiredCtx )
283
- const cmd = `gcloud container clusters get-credentials ${clusterName} --zone ${zone} --project ${projectId}`
284
-
285
- if ( matchedCtx ) {
286
- console.log( `
287
-
288
- Current context ${chalk.bold.green(currentCtx)} matches the desired
289
- context. Do you want to update credentials anyway?
290
-
291
- ` )
292
- }
293
- else {
294
- console.log( `
295
-
296
- You are about to change your GCP context to:
297
- CLUSTER_NAME => ${chalk.bold.green(clusterName)}
298
- PROJECT_ID => ${chalk.bold.green(projectId)}
299
- GCE_REGION => ${chalk.bold.green(zone)}
300
-
301
- ` )
302
- }
303
- const ans = ask.question( `Enter "${chalk.bold.green( 'yes' )}" if you wish to proceed => ` )
304
- if ( ans !== 'yes' ) {
305
- if ( matchedCtx ) {
306
- console.log( chalk.bold.yellow( `\n\nSkipping a refetch of your GCP context and credentials\n\n` ) )
307
- process.exit( 0 )
308
- }
309
-
310
- console.log( chalk.bold.red( `\n\nYour GCP context and credentials do NOT match - this could be bad!\n\n` ) )
311
- process.exit( 1 )
312
- }
313
-
314
- console.log( `\n\nExecuting: ${cmd}\n\n` )
315
- exec( `${cmd}`, ( error, out ) => {
316
- if ( error ) {
317
- console.log( `\n\n***ERROR ${error}\n\n` )
318
- process.exit( 1 )
319
- }
320
- } )
package/lib/server/pkgck DELETED
@@ -1,136 +0,0 @@
1
- #!/bin/bash
2
-
3
- C_off='\e[0m'
4
- C_yellow='\e[93m'
5
- C_red='\e[101m'
6
- C_green='\e[92m'
7
-
8
- good() {
9
- printf "\e[32m✔${C_off}"
10
- }
11
-
12
- bad() {
13
- printf "\e[31m✘${C_off}"
14
- }
15
-
16
- semver() {
17
- local version=$1
18
- local isSemver=`echo $version | egrep -e "^v\d+\.\d+\.\d+$"`
19
- if [ -z "$version" ];
20
- then
21
- printf "UNTAGGD"
22
- elif [ $isSemver ];
23
- then
24
- printf "$version"
25
- else
26
- printf "!SEMVER"
27
- fi
28
- }
29
-
30
- check_babel () {
31
- local C_stat=$(bad)
32
- [ -f .babelrc ] && grep --silent @babel/plugin-proposal-optional-chaining .babelrc
33
- [ $? -eq 0 ] && C_stat=$(good)
34
- printf $C_stat
35
- }
36
-
37
- check_circle () {
38
- local C_stat=$(bad)
39
- [ -f ".circleci/config.yml" ] && C_stat=$(good)
40
- printf $C_stat
41
- }
42
-
43
- check_eslint () {
44
- local C_stat=$(bad)
45
- [ -f .eslintrc ] && grep --silent @leverege/eslint-config-leverege .eslintrc
46
- [ $? -eq 0 ] && C_stat=$(good)
47
- printf $C_stat
48
- }
49
-
50
- check_license () {
51
- local C_stat=$(bad)
52
- local lic="`node -p \"require('./package.json').scripts.licenseCheck !== undefined\"`"
53
- [ $lic == true ] && C_stat=$(good)
54
- printf $C_stat
55
- }
56
-
57
- # Invoke as: version_ck $GITTAG $NPMVER
58
- #
59
- check_git_version() {
60
- local tag=$1
61
- local pkg=$2
62
- local clr=$C_green
63
-
64
- if [ "$tag" == 'UNTAGGD' ];
65
- then
66
- clr=$C_red
67
- elif [ "$tag" != "$pkg" ];
68
- then
69
- clr=$C_yellow
70
- fi
71
-
72
- printf "$clr$tag$C_off"
73
- }
74
-
75
- check_nodemon() {
76
- nodemon="`getjson --file ./package.json --key nodemon`"
77
- }
78
-
79
- check_scope() {
80
- private="`node -p \"require('./package.json').private == true\"`"
81
- scoped="`getjson --file ./package.json --key name --regex '^@\w{3}'`"
82
- result="${C_red}PUBL${C_off}"
83
- if [[ "$scoped" == "" ]] && [[ "$private" == "true" ]];
84
- then
85
- result="${C_yellow}PRVT"
86
- elif [[ "$scoped" != "" ]];
87
- then
88
- result="${C_green}${scoped}"
89
- elif [[ "$private" == "true" ]];
90
- then
91
- result="${C_green}prv"
92
- fi
93
- printf "${result}${C_off}"
94
- }
95
-
96
- repos=0
97
- check_repo() {
98
- local dir=$1
99
- [ ! -d $dir/.git ] || [ ! -f $dir/package.json ] && return
100
- cd $dir &> /dev/null
101
- local gperrs=0
102
- git pull -q &> /dev/null; [ $? -ne 0 ] && let "gperrs++"
103
- git pull -q --tags &> /dev/null; [ $? -ne 0 ] && let "gperrs++"
104
-
105
- # It is necessary to use the output from printf to set localmods in order
106
- # to get the ANSI escape codes expanded.
107
- local localmods=$(good)
108
- [ $gperrs -ne 0 ] && localmods=$(bad)
109
- pkgver=$(semver "v`node -p \"require('./package.json').version\"`")
110
- gitver=$(semver `git describe --abbrev=0 2>/dev/null`)
111
- [ $? -ne 0 ] && gitver='UNTAGGD'
112
- local needspush=
113
- if [ "$pkgver" == "$gitver" ];
114
- then
115
- git ls-remote --tags origin | grep $gitver &> /dev/null
116
- [ $? -ne 0 ] && needspush='!tags'
117
- fi
118
- local babel7=$(check_babel)
119
- local circle=$(check_circle)
120
- local eslint=$(check_eslint)
121
- local license=$(check_license)
122
- local scoped=$(check_scope)
123
- [ $(( $repos % 15)) -eq 0 ] && printf "\n%35s pkg git cln scop cir lic esl bl7\n"
124
- printf "%32s: %-8s %-16s %s %8s %s %s %s %s %s\n" $dir $pkgver $(check_git_version $gitver $pkgver) $localmods $scoped $circle $license $eslint $babel7 "$needspush"
125
- let "repos++"
126
- cd - &> /dev/null
127
- }
128
-
129
- clear
130
-
131
- pkgs="$@"
132
- for dir in $@; do
133
- check_repo $dir
134
- done
135
-
136
- printf "\ntotal repoitories checked: $repos\n\n"
@@ -1,35 +0,0 @@
1
- #!/bin/bash
2
-
3
- C_off='\e[0m'
4
- C_yellow='\e[93m'
5
-
6
- good() {
7
- printf "\e[32m✔${C_off}"
8
- }
9
-
10
- bad() {
11
- printf "\e[31m✘${C_off}"
12
- }
13
-
14
- check_file() {
15
- local C_stat=$(bad)
16
- local filename=$1
17
-
18
- if [ -f $filename ]; then
19
- C_stat=$(good)
20
- printf "$C_stat $filename\n"
21
- else
22
- printf "$C_stat $filename is missing\n\n"
23
- printf "${C_yellow} Please create $filename before pushing to prod\n\n"
24
- exit 1
25
- fi
26
- }
27
-
28
- printf "\nChecking repo for markdown files\n\n"
29
-
30
- files=( README.md LICENSE.md )
31
- for file in ${files[@]}; do
32
- check_file $file
33
- done
34
-
35
- printf "\nAll required files exist\n\n"
@@ -1,4 +0,0 @@
1
- {
2
- "name": "@leverege/packagename",
3
- "main": "lib/index.js"
4
- }
@@ -1,99 +0,0 @@
1
- const ora = require( 'ora' )
2
- const fs = require( 'fs' )
3
- const path = require( 'path' )
4
- const { promisify } = require( 'util' )
5
-
6
- class CloudflareAPI {
7
- constructor( options ) {
8
- const { args } = options
9
- const { url, proxy, ipaddress, account } = args
10
-
11
- this.url = url
12
- this.proxy = proxy
13
- this.ipaddress = ipaddress
14
- this.spinner = ora( { text : 'Creating DNS record...', spinner : 'monkey' } )
15
- this.account = account
16
- }
17
-
18
- async decrypt(
19
- projectId = 'leverege-docker-images',
20
- keyRingId = 'build-tools',
21
- cryptoKeyId = 'circle-ci',
22
- ciphertextFileName = './accounts.json.enc',
23
- plaintextFileName = './accounts.json'
24
- ) {
25
-
26
- // Import the library and create a client
27
- const kms = require( '@google-cloud/kms' )
28
- const client = new kms.KeyManagementServiceClient()
29
-
30
- // The location of the crypto key's key ring, e.g. "global"
31
- const locationId = 'us-east4'
32
-
33
- // Reads the file to be decrypted
34
- const readFile = promisify( fs.readFile );
35
- const contentsBuffer = await readFile( path.resolve( __dirname, ciphertextFileName ) )
36
- const name = client.cryptoKeyPath(
37
- projectId,
38
- locationId,
39
- keyRingId,
40
- cryptoKeyId
41
- );
42
- const ciphertext = contentsBuffer.toString( 'base64' )
43
-
44
- // Decrypts the file using the specified crypto key
45
- const [ result ] = await client.decrypt( { name, ciphertext } )
46
-
47
- // Writes the decrypted file to disk
48
- const writeFile = promisify( fs.writeFile )
49
- await writeFile( path.resolve( __dirname, plaintextFileName ), Buffer.from( result.plaintext, 'base64' ) )
50
- }
51
-
52
- setAccountValues() {
53
- const accountJson = require( path.resolve( __dirname, './accounts.json' ) )
54
- const accountInfo = accountJson[this.account]
55
- const { email, key, zone } = accountInfo
56
-
57
- this.cf = require( 'cloudflare' )( {
58
- email,
59
- key
60
- } )
61
- this.zone = zone
62
- }
63
-
64
- async deleteSecrets() {
65
- const deleteFile = promisify( fs.unlink )
66
- await deleteFile( path.resolve( __dirname, './accounts.json' ) )
67
- }
68
-
69
- async createDNSRecord() {
70
- try {
71
- this.spinner.start()
72
-
73
- this.spinner.text = 'Decrypting Cloudflare secrets...'
74
- await this.decrypt()
75
-
76
- this.spinner.text = 'Initializing Cloudflare API...'
77
- this.setAccountValues()
78
-
79
- this.spinner.text = 'Adding A name record...'
80
- await this.cf.dnsRecords.add( this.zone,
81
- { type : 'A',
82
- name : this.url,
83
- content : this.ipaddress,
84
- proxied : this.proxy
85
- } )
86
-
87
- this.spinner.text = 'Removing secrets...'
88
- await this.deleteSecrets()
89
-
90
- this.spinner.stop()
91
- } catch ( ex ) {
92
- this.spinner.stop()
93
- console.log( ex )
94
- throw ex
95
- }
96
- }
97
- }
98
-
99
- module.exports = CloudflareAPI
Binary file
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env node
2
- const commandLineArgs = require( 'command-line-args' )
3
- const commandLineUsage = require( 'command-line-usage' )
4
- const Cloudflare = require( './CloudflareAPI' )
5
-
6
- const defaultConfig = {
7
- account : 'leverege',
8
- proxy : true
9
- }
10
-
11
- const sections = [
12
- {
13
- content : 'Wraps Cloudflare to modify DNS configs for new UI/Servers'
14
- },
15
- {
16
- header : 'Options',
17
- optionList : [
18
- {
19
- name : 'account',
20
- alias : 'a',
21
- description : 'Cloudflare account to use'
22
- },
23
- {
24
- name : 'ipaddress',
25
- alias : 'i',
26
- description : 'IP address to point DNS account to (e.g. 35.178.29.10)'
27
- },
28
- {
29
- name : 'url',
30
- alias : 'u',
31
- description : 'URL name (e.g. myserver)'
32
- },
33
- {
34
- name : 'proxy',
35
- alias : 'p',
36
- description : 'Turn on Cloudflare proxy (optional)'
37
- },
38
- {
39
- name : 'help',
40
- description : 'Print this usage guide.'
41
- }
42
- ]
43
- }
44
- ]
45
-
46
- const usage = commandLineUsage( sections )
47
-
48
- const optionDefinitions = [
49
- { name : 'account', alias : 'a', type : String, defaultValue : defaultConfig.account },
50
- { name : 'ipaddress', alias : 'i', type : String },
51
- { name : 'url', alias : 'u', type : String },
52
- { name : 'proxy', alias : 'p', type : Boolean, defaultValue : defaultConfig.proxy },
53
- { name : 'help', alias : 'h', type : Boolean }
54
- ]
55
-
56
- const args = commandLineArgs( optionDefinitions )
57
-
58
- async function main() {
59
- if ( args.help ) {
60
- console.log( usage )
61
- }
62
-
63
- if ( !args.url || !args.ipaddress ) {
64
- console.log( '\n*******************************************' )
65
- console.log( '** **' )
66
- console.log( '** Need to specify URL and/or IP address **' )
67
- console.log( '** **' )
68
- console.log( '*******************************************' )
69
- console.log( usage )
70
- } else {
71
- const CF = new Cloudflare( { ...defaultConfig, args } )
72
- try {
73
- await CF.createDNSRecord()
74
- console.log( 'Successfully created a new DNS record' )
75
- console.log( 'It may take a few minutes for DNS to propagate' )
76
- } catch ( ex ) {
77
- console.error( ex.message )
78
- }
79
- }
80
- }
81
-
82
- main()