Skip to content

Commit 7a0e234

Browse files
Merge pull request #81 from storyblok/EXT-2186-update-storyblok-cli
feat: add region-helper functionality
2 parents cce1fef + 0a6838b commit 7a0e234

21 files changed

+109
-98
lines changed

.github/.dependabot.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2+
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
3+
4+
version: 2
5+
updates:
6+
- package-ecosystem: "npm"
7+
directory: "/"
8+
schedule:
9+
interval: "monthly"
10+
allow:
11+
- dependency-name: "@storyblok/region-helper"
12+
reviewers:
13+
- "storyblok/plugins-team"

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ $ storyblok login
4444

4545
**For Both login options you nedd to pass the region**
4646

47-
* `region`: region you would like to work in. Please keep in mind that the region must match the region of your space. You can use `us`, `cn`, `eu`, `ca` and `ap`, if left empty, default is `eu`. This region flag will be used for the other cli's commands.
47+
* `region` (default: `eu`): the region you would like to work in. All the supported regions can be found [here](https://www.storyblok.com/faq/define-specific-region-storyblok-api).
48+
49+
> [!NOTE]
50+
> Please keep in mind that the region must match the region of your space, and also that it will be used for all future commands you may perform.
4851
4952
#### Login with token flag
5053
You can also add the token directly from the login’s command, like the example below:

__mocks__/axios.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
const { USERS_ROUTES } = require('../src/constants')
2-
const { EMAIL_TEST, PASSWORD_TEST, TOKEN_TEST } = require('../tests/constants')
1+
const { USERS_ROUTES, EMAIL_TEST, PASSWORD_TEST, TOKEN_TEST } = require('../tests/constants')
32

43
const isCredCorrects = (email, pass) => {
54
return email === EMAIL_TEST && pass === PASSWORD_TEST

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"author": "Dominik Angerer <dominikangerer1@gmail.com>, Alexander Feiglstorfer <delooks@gmail.com>",
2626
"license": "MIT",
2727
"dependencies": {
28+
"@storyblok/region-helper": "^1.0.0",
2829
"axios": "^0.27.2",
2930
"chalk": "^4.1.0",
3031
"clear": "0.1.0",

src/cli.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ const chalk = require('chalk')
77
const clear = require('clear')
88
const figlet = require('figlet')
99
const inquirer = require('inquirer')
10+
const { ALL_REGIONS, EU_CODE, isRegion } = require('@storyblok/region-helper')
1011

1112
const updateNotifier = require('update-notifier')
1213
const pkg = require('../package.json')
1314

1415
const tasks = require('./tasks')
1516
const { getQuestions, lastStep, api, creds } = require('./utils')
1617
const { SYNC_TYPES, COMMANDS } = require('./constants')
18+
const allRegionsText = ALL_REGIONS.join(', ')
1719

1820
clear()
1921
console.log(chalk.cyan(figlet.textSync('storyblok')))
@@ -39,8 +41,8 @@ program
3941
program
4042
.command(COMMANDS.LOGIN)
4143
.description('Login to the Storyblok cli')
42-
.option('-t, --token <token>', 'Token to login directly without questions, like for CI enviroments')
43-
.option('-r, --region <region>', 'The region you would like to work in. Please keep in mind that the region must match the region of your space. You can use us, cn or eu, if left empty, default is eu. This region flag will be used for the other cli\'s commands')
44+
.option('-t, --token <token>', 'Token to login directly without questions, like for CI environments')
45+
.option('-r, --region <region>', `The region you would like to work in. Please keep in mind that the region must match the region of your space. This region flag will be used for the other cli's commands. You can use the values: ${allRegionsText}.`, EU_CODE)
4446
.action(async (options) => {
4547
const { token, region } = options
4648

@@ -49,6 +51,11 @@ program
4951
return
5052
}
5153

54+
if (!isRegion(region)) {
55+
console.log(chalk.red('X') + `The provided region ${region} is not valid. Please use one of the following: ${allRegionsText}`)
56+
return
57+
}
58+
5259
try {
5360
await api.processLogin(token, region)
5461
process.exit(0)
@@ -524,7 +531,8 @@ if (program.rawArgs.length <= 2) {
524531

525532
function errorHandler (e, command) {
526533
if (/404/.test(e.message)) {
527-
console.log(chalk.yellow('/!\\') + ' If your space was created under US, CA, AP or CN region, you must provide the region us, ca, ap or cn upon login.')
534+
const allRegionsButDefault = ALL_REGIONS.filter(region => region !== EU_CODE).join(' ,')
535+
console.log(chalk.yellow('/!\\') + ` If your space was not created under ${EU_CODE} region, you must provide the region (${allRegionsButDefault}) upon login.`)
528536
} else {
529537
console.log(chalk.red('X') + ' An error occurred when executing the ' + command + ' task: ' + e || e.message)
530538
}

src/constants.js

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
const SYNC_TYPES = [
2-
'folders',
3-
'components',
4-
'roles',
5-
'stories',
6-
'datasources'
7-
]
1+
const SYNC_TYPES = ['folders', 'components', 'roles', 'stories', 'datasources']
82

93
const COMMANDS = {
104
GENERATE_MIGRATION: 'generate-migration',
@@ -28,43 +22,8 @@ const DEFAULT_AGENT = {
2822
SB_Agent_Version: process.env.npm_package_version || '3.0.0'
2923
}
3024

31-
const REGIONS = {
32-
cn: {
33-
key: 'cn',
34-
name: 'China',
35-
apiEndpoint: 'https://app.storyblokchina.cn/v1/'
36-
},
37-
eu: {
38-
key: 'eu',
39-
name: 'Europe',
40-
apiEndpoint: 'https://api.storyblok.com/v1/'
41-
},
42-
us: {
43-
key: 'us',
44-
name: 'United States',
45-
apiEndpoint: 'https://api-us.storyblok.com/v1/'
46-
},
47-
ca: {
48-
key: 'ca',
49-
name: 'Canada',
50-
apiEndpoint: 'https://api-ca.storyblok.com/v1/'
51-
},
52-
ap: {
53-
key: 'ap',
54-
name: 'Australia',
55-
apiEndpoint: 'https://api-ap.storyblok.com/v1/'
56-
}
57-
}
58-
59-
const USERS_ROUTES = {
60-
LOGIN: `${REGIONS.eu.apiEndpoint}users/login`,
61-
SIGNUP: `${REGIONS.eu.apiEndpoint}users/signup`
62-
}
63-
6425
module.exports = {
6526
SYNC_TYPES,
66-
USERS_ROUTES,
6727
COMMANDS,
68-
DEFAULT_AGENT,
69-
REGIONS
28+
DEFAULT_AGENT
7029
}

src/tasks/delete-datasources.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,25 @@ const deleteDatasources = async (api, options) => {
1313
let datasources = await api.getDatasources()
1414

1515
if (bySlug) {
16-
datasources = datasources.filter(datasource => datasource.slug.toLowerCase().startsWith(bySlug.toLowerCase()));
17-
const filteredSlugs = datasources.map(obj => obj.slug);
18-
const formattedSlugs = filteredSlugs.join(', ');
16+
datasources = datasources.filter(datasource => datasource.slug.toLowerCase().startsWith(bySlug.toLowerCase()))
17+
const filteredSlugs = datasources.map(obj => obj.slug)
18+
const formattedSlugs = filteredSlugs.join(', ')
1919

20-
console.log(`${chalk.blue('-')} Datasources where slug starts with ${bySlug}: ${formattedSlugs}`);
20+
console.log(`${chalk.blue('-')} Datasources where slug starts with ${bySlug}: ${formattedSlugs}`)
2121
}
2222

2323
if (byName) {
24-
datasources = datasources.filter(datasource => datasource.name.toLowerCase().startsWith(byName.toLowerCase()));
25-
const filteredNames = datasources.map(obj => obj.name);
26-
const formattedNames = filteredNames.join(', ');
24+
datasources = datasources.filter(datasource => datasource.name.toLowerCase().startsWith(byName.toLowerCase()))
25+
const filteredNames = datasources.map(obj => obj.name)
26+
const formattedNames = filteredNames.join(', ')
2727

28-
console.log(`${chalk.blue('-')} Datasources where name starts with ${byName}: ${formattedNames}`);
28+
console.log(`${chalk.blue('-')} Datasources where name starts with ${byName}: ${formattedNames}`)
2929
}
3030

3131
for (const datasource of datasources) {
3232
console.log(`${chalk.blue('-')} Deleting ${datasource.name}`)
3333
await api.deleteDatasource(datasource.id)
3434
}
35-
3635
} catch (e) {
3736
console.error(`${chalk.red('X')} An error ocurred in delete-components task when deleting a datasource`)
3837
return Promise.reject(new Error(e))

src/tasks/list-spaces.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
const chalk = require('chalk')
2-
const { REGIONS } = require('../constants')
2+
const { ALL_REGIONS, getRegionName, CN_CODE } = require('@storyblok/region-helper')
33
/**
44
* @method listSpaces
55
* @param api - Pass the api instance as a parameter
66
* @return {Promise}
77
*/
88

99
const listSpaces = async (api, currentRegion) => {
10-
const isChinaEnv = currentRegion === 'cn'
10+
const isChinaEnv = currentRegion === CN_CODE
1111

1212
console.log()
1313
console.log(chalk.green('✓') + ' Loading spaces...')
@@ -34,8 +34,8 @@ const listSpaces = async (api, currentRegion) => {
3434
return spaces
3535
} else {
3636
const spacesList = []
37-
for (const key in REGIONS) {
38-
if (key === 'cn') continue
37+
for (const key of ALL_REGIONS) {
38+
if (key === CN_CODE) continue
3939
spacesList.push(await api.getAllSpacesByRegion(key)
4040
.then((res) => {
4141
return {
@@ -50,9 +50,8 @@ const listSpaces = async (api, currentRegion) => {
5050
return []
5151
}
5252
spacesList.forEach(region => {
53-
const regionName = REGIONS[region.key].name
5453
console.log()
55-
console.log(`${chalk.blue(' -')} Spaces From ${regionName} region:`)
54+
console.log(`${chalk.blue(' -')} Spaces From ${getRegionName(region.key)} region:`)
5655
region.res.forEach((space) => {
5756
console.log(` ${space.name} (id: ${space.id})`)
5857
})

src/tasks/sync-commands/components.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ class SyncComponents {
7373

7474
if (this.componentsGroups && !this.componentsGroups.includes(sourceGroupUuid)) {
7575
console.log(
76-
chalk.yellow("-") +
76+
chalk.yellow('-') +
7777
` Component ${component.name} does not belong to the ${this.componentsGroups} group(s).`
78-
);
79-
continue;
78+
)
79+
continue
8080
}
8181

8282
// if the component belongs to a group
@@ -112,7 +112,7 @@ class SyncComponents {
112112
await this.presetsLib.createPresets(componentPresets, componentCreated.id)
113113
}
114114
} catch (e) {
115-
if (e.response && e.response.status || e.status === 422) {
115+
if ((e.response && e.response.status) || e.status === 422) {
116116
console.log(
117117
`${chalk.yellow('-')} Component ${component.name} already exists, updating it...`
118118
)
@@ -217,7 +217,10 @@ class SyncComponents {
217217
return Object.keys(sourceSchema).reduce((acc, key) => {
218218
// handle blocks separately
219219
const sourceSchemaItem = sourceSchema[key]
220-
if (sourceSchemaItem?.type === 'bloks' || sourceSchemaItem?.type === 'richtext') {
220+
const isBloksType = sourceSchemaItem && sourceSchemaItem.type === 'bloks'
221+
const isRichtextType = sourceSchemaItem && sourceSchemaItem.type === 'richtext'
222+
223+
if (isBloksType || isRichtextType) {
221224
acc[key] = this.mergeBloksSchema(sourceSchemaItem)
222225
return acc
223226
}

src/utils/api.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ const inquirer = require('inquirer')
55

66
const creds = require('./creds')
77
const getQuestions = require('./get-questions')
8-
const { REGIONS, USERS_ROUTES, DEFAULT_AGENT } = require('../constants')
8+
const { DEFAULT_AGENT } = require('../constants')
9+
const { getRegionApiEndpoint } = require('./region')
10+
const { EU_CODE } = require('@storyblok/region-helper')
911

1012
module.exports = {
1113
accessToken: '',
@@ -39,7 +41,7 @@ module.exports = {
3941
},
4042

4143
async login (content) {
42-
const { email, password, region = 'eu' } = content
44+
const { email, password, region = EU_CODE } = content
4345
try {
4446
const response = await axios.post(`${this.apiSwitcher(region)}users/login`, {
4547
email: email,
@@ -96,7 +98,7 @@ module.exports = {
9698
}
9799
},
98100

99-
persistCredentials (email, token = null, region = 'eu') {
101+
persistCredentials (email, token = null, region = EU_CODE) {
100102
if (token) {
101103
this.oauthToken = token
102104
creds.set(email, token, region)
@@ -168,8 +170,8 @@ module.exports = {
168170
creds.set(null)
169171
},
170172

171-
signup (email, password, region = 'eu') {
172-
return axios.post(USERS_ROUTES.SIGNUP, {
173+
signup (email, password, region = EU_CODE) {
174+
return axios.post(`${this.apiSwitcher(region)}users/signup`, {
173175
email: email,
174176
password: password,
175177
region
@@ -255,7 +257,6 @@ module.exports = {
255257
.catch(err => Promise.reject(err))
256258
},
257259

258-
259260
post (path, props) {
260261
return this.sendRequest(path, 'post', props)
261262
},
@@ -310,6 +311,6 @@ module.exports = {
310311
},
311312

312313
apiSwitcher (region) {
313-
return region ? REGIONS[region].apiEndpoint : REGIONS[this.region].apiEndpoint
314+
return region ? getRegionApiEndpoint(region) : getRegionApiEndpoint(this.region)
314315
}
315316
}

src/utils/get-questions.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const { REGIONS } = require('../constants')
1+
const { ALL_REGIONS, EU_CODE } = require('@storyblok/region-helper')
2+
23
const getOptions = (subCommand, argv = {}, api = {}) => {
34
let email = ''
45
const moreOptions = [
@@ -7,17 +8,17 @@ const getOptions = (subCommand, argv = {}, api = {}) => {
78
'push-components',
89
'scaffold'
910
]
10-
const regionsPrefixList = Object.keys(REGIONS)
1111
const regionInput = {
1212
type: 'input',
1313
name: 'region',
14-
message: `Please enter the region you would like to work in (${regionsPrefixList}) - if not set, default is eu:`,
14+
message: `Please enter the region you would like to work in (${ALL_REGIONS}):`,
15+
default: EU_CODE,
1516
validate: function (value) {
16-
if (regionsPrefixList.indexOf(value) > -1) {
17+
if (ALL_REGIONS.indexOf(value) > -1) {
1718
return true
1819
}
1920

20-
return `Please enter a valid region: ${regionsPrefixList}`
21+
return `Please enter a valid region: ${ALL_REGIONS}`
2122
}
2223
}
2324

src/utils/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ module.exports = {
66
capitalize: require('./capitalize'),
77
findByProperty: require('./find-by-property'),
88
parseError: require('./parse-error'),
9+
region: require('./region'),
910
saveFileFactory: require('./save-file-factory')
1011
}

src/utils/last-step.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const lastStep = answers => {
4949
console.log(chalk.green('✓') + ' - The github repository ' + gitRepo + ' will be cloned now...')
5050

5151
ghdownload(gitRepo, outputDir, async (err) => {
52-
if(err) {
52+
if (err) {
5353
if (err.code === 'ENOTEMPTY') {
5454
console.log(chalk.red(' Oh Snap! It seems that you already have a project with the name: ' + name))
5555
reject(new Error('This repository already has been cloned'))

src/utils/region.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const { getRegionBaseUrl } = require('@storyblok/region-helper')
2+
3+
const getRegionApiEndpoint = (region) => `${getRegionBaseUrl(region)}/v1/`
4+
5+
module.exports = {
6+
getRegionApiEndpoint
7+
}

tests/constants.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
const { getRegionApiEndpoint } = require('../src/utils/region')
2+
const { EU_CODE } = require('@storyblok/region-helper')
13
const EMAIL_TEST = 'test@storyblok.com'
24
const PASSWORD_TEST = 'test'
35
const TOKEN_TEST = 'storyblok1234'
4-
const REGION_TEST = 'eu'
6+
const REGION_TEST = EU_CODE
57

68
// use functions to always returns 'new' data
79
const FAKE_COMPONENTS = () => [
@@ -289,9 +291,15 @@ const FAKE_PRESET = () => ({
289291
description: 'page preset'
290292
})
291293

294+
const USERS_ROUTES = {
295+
LOGIN: `${getRegionApiEndpoint(EU_CODE)}users/login`,
296+
SIGNUP: `${getRegionApiEndpoint(EU_CODE)}users/signup`
297+
}
298+
292299
module.exports = {
293300
EMAIL_TEST,
294301
TOKEN_TEST,
302+
USERS_ROUTES,
295303
FAKE_STORIES,
296304
PASSWORD_TEST,
297305
FAKE_COMPONENTS,

0 commit comments

Comments
 (0)