Skip to content

Commit

Permalink
Merge pull request #81 from storyblok/EXT-2186-update-storyblok-cli
Browse files Browse the repository at this point in the history
feat: add region-helper functionality
  • Loading branch information
demetriusfeijoo committed Mar 6, 2024
2 parents cce1fef + 0a6838b commit 7a0e234
Show file tree
Hide file tree
Showing 21 changed files with 109 additions and 98 deletions.
13 changes: 13 additions & 0 deletions .github/.dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "monthly"
allow:
- dependency-name: "@storyblok/region-helper"
reviewers:
- "storyblok/plugins-team"
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ $ storyblok login

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

* `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.
* `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).

> [!NOTE]
> 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.
#### Login with token flag
You can also add the token directly from the login’s command, like the example below:
Expand Down
3 changes: 1 addition & 2 deletions __mocks__/axios.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const { USERS_ROUTES } = require('../src/constants')
const { EMAIL_TEST, PASSWORD_TEST, TOKEN_TEST } = require('../tests/constants')
const { USERS_ROUTES, EMAIL_TEST, PASSWORD_TEST, TOKEN_TEST } = require('../tests/constants')

const isCredCorrects = (email, pass) => {
return email === EMAIL_TEST && pass === PASSWORD_TEST
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"author": "Dominik Angerer <dominikangerer1@gmail.com>, Alexander Feiglstorfer <delooks@gmail.com>",
"license": "MIT",
"dependencies": {
"@storyblok/region-helper": "^1.0.0",
"axios": "^0.27.2",
"chalk": "^4.1.0",
"clear": "0.1.0",
Expand Down
14 changes: 11 additions & 3 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ const chalk = require('chalk')
const clear = require('clear')
const figlet = require('figlet')
const inquirer = require('inquirer')
const { ALL_REGIONS, EU_CODE, isRegion } = require('@storyblok/region-helper')

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

const tasks = require('./tasks')
const { getQuestions, lastStep, api, creds } = require('./utils')
const { SYNC_TYPES, COMMANDS } = require('./constants')
const allRegionsText = ALL_REGIONS.join(', ')

clear()
console.log(chalk.cyan(figlet.textSync('storyblok')))
Expand All @@ -39,8 +41,8 @@ program
program
.command(COMMANDS.LOGIN)
.description('Login to the Storyblok cli')
.option('-t, --token <token>', 'Token to login directly without questions, like for CI enviroments')
.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')
.option('-t, --token <token>', 'Token to login directly without questions, like for CI environments')
.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)
.action(async (options) => {
const { token, region } = options

Expand All @@ -49,6 +51,11 @@ program
return
}

if (!isRegion(region)) {
console.log(chalk.red('X') + `The provided region ${region} is not valid. Please use one of the following: ${allRegionsText}`)
return
}

try {
await api.processLogin(token, region)
process.exit(0)
Expand Down Expand Up @@ -524,7 +531,8 @@ if (program.rawArgs.length <= 2) {

function errorHandler (e, command) {
if (/404/.test(e.message)) {
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.')
const allRegionsButDefault = ALL_REGIONS.filter(region => region !== EU_CODE).join(' ,')
console.log(chalk.yellow('/!\\') + ` If your space was not created under ${EU_CODE} region, you must provide the region (${allRegionsButDefault}) upon login.`)
} else {
console.log(chalk.red('X') + ' An error occurred when executing the ' + command + ' task: ' + e || e.message)
}
Expand Down
45 changes: 2 additions & 43 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
const SYNC_TYPES = [
'folders',
'components',
'roles',
'stories',
'datasources'
]
const SYNC_TYPES = ['folders', 'components', 'roles', 'stories', 'datasources']

const COMMANDS = {
GENERATE_MIGRATION: 'generate-migration',
Expand All @@ -28,43 +22,8 @@ const DEFAULT_AGENT = {
SB_Agent_Version: process.env.npm_package_version || '3.0.0'
}

const REGIONS = {
cn: {
key: 'cn',
name: 'China',
apiEndpoint: 'https://app.storyblokchina.cn/v1/'
},
eu: {
key: 'eu',
name: 'Europe',
apiEndpoint: 'https://api.storyblok.com/v1/'
},
us: {
key: 'us',
name: 'United States',
apiEndpoint: 'https://api-us.storyblok.com/v1/'
},
ca: {
key: 'ca',
name: 'Canada',
apiEndpoint: 'https://api-ca.storyblok.com/v1/'
},
ap: {
key: 'ap',
name: 'Australia',
apiEndpoint: 'https://api-ap.storyblok.com/v1/'
}
}

const USERS_ROUTES = {
LOGIN: `${REGIONS.eu.apiEndpoint}users/login`,
SIGNUP: `${REGIONS.eu.apiEndpoint}users/signup`
}

module.exports = {
SYNC_TYPES,
USERS_ROUTES,
COMMANDS,
DEFAULT_AGENT,
REGIONS
DEFAULT_AGENT
}
17 changes: 8 additions & 9 deletions src/tasks/delete-datasources.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,25 @@ const deleteDatasources = async (api, options) => {
let datasources = await api.getDatasources()

if (bySlug) {
datasources = datasources.filter(datasource => datasource.slug.toLowerCase().startsWith(bySlug.toLowerCase()));
const filteredSlugs = datasources.map(obj => obj.slug);
const formattedSlugs = filteredSlugs.join(', ');
datasources = datasources.filter(datasource => datasource.slug.toLowerCase().startsWith(bySlug.toLowerCase()))
const filteredSlugs = datasources.map(obj => obj.slug)
const formattedSlugs = filteredSlugs.join(', ')

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

if (byName) {
datasources = datasources.filter(datasource => datasource.name.toLowerCase().startsWith(byName.toLowerCase()));
const filteredNames = datasources.map(obj => obj.name);
const formattedNames = filteredNames.join(', ');
datasources = datasources.filter(datasource => datasource.name.toLowerCase().startsWith(byName.toLowerCase()))
const filteredNames = datasources.map(obj => obj.name)
const formattedNames = filteredNames.join(', ')

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

for (const datasource of datasources) {
console.log(`${chalk.blue('-')} Deleting ${datasource.name}`)
await api.deleteDatasource(datasource.id)
}

} catch (e) {
console.error(`${chalk.red('X')} An error ocurred in delete-components task when deleting a datasource`)
return Promise.reject(new Error(e))
Expand Down
11 changes: 5 additions & 6 deletions src/tasks/list-spaces.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const chalk = require('chalk')
const { REGIONS } = require('../constants')
const { ALL_REGIONS, getRegionName, CN_CODE } = require('@storyblok/region-helper')
/**
* @method listSpaces
* @param api - Pass the api instance as a parameter
* @return {Promise}
*/

const listSpaces = async (api, currentRegion) => {
const isChinaEnv = currentRegion === 'cn'
const isChinaEnv = currentRegion === CN_CODE

console.log()
console.log(chalk.green('✓') + ' Loading spaces...')
Expand All @@ -34,8 +34,8 @@ const listSpaces = async (api, currentRegion) => {
return spaces
} else {
const spacesList = []
for (const key in REGIONS) {
if (key === 'cn') continue
for (const key of ALL_REGIONS) {
if (key === CN_CODE) continue
spacesList.push(await api.getAllSpacesByRegion(key)
.then((res) => {
return {
Expand All @@ -50,9 +50,8 @@ const listSpaces = async (api, currentRegion) => {
return []
}
spacesList.forEach(region => {
const regionName = REGIONS[region.key].name
console.log()
console.log(`${chalk.blue(' -')} Spaces From ${regionName} region:`)
console.log(`${chalk.blue(' -')} Spaces From ${getRegionName(region.key)} region:`)
region.res.forEach((space) => {
console.log(` ${space.name} (id: ${space.id})`)
})
Expand Down
13 changes: 8 additions & 5 deletions src/tasks/sync-commands/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ class SyncComponents {

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

// if the component belongs to a group
Expand Down Expand Up @@ -112,7 +112,7 @@ class SyncComponents {
await this.presetsLib.createPresets(componentPresets, componentCreated.id)
}
} catch (e) {
if (e.response && e.response.status || e.status === 422) {
if ((e.response && e.response.status) || e.status === 422) {
console.log(
`${chalk.yellow('-')} Component ${component.name} already exists, updating it...`
)
Expand Down Expand Up @@ -217,7 +217,10 @@ class SyncComponents {
return Object.keys(sourceSchema).reduce((acc, key) => {
// handle blocks separately
const sourceSchemaItem = sourceSchema[key]
if (sourceSchemaItem?.type === 'bloks' || sourceSchemaItem?.type === 'richtext') {
const isBloksType = sourceSchemaItem && sourceSchemaItem.type === 'bloks'
const isRichtextType = sourceSchemaItem && sourceSchemaItem.type === 'richtext'

if (isBloksType || isRichtextType) {
acc[key] = this.mergeBloksSchema(sourceSchemaItem)
return acc
}
Expand Down
15 changes: 8 additions & 7 deletions src/utils/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ const inquirer = require('inquirer')

const creds = require('./creds')
const getQuestions = require('./get-questions')
const { REGIONS, USERS_ROUTES, DEFAULT_AGENT } = require('../constants')
const { DEFAULT_AGENT } = require('../constants')
const { getRegionApiEndpoint } = require('./region')
const { EU_CODE } = require('@storyblok/region-helper')

module.exports = {
accessToken: '',
Expand Down Expand Up @@ -39,7 +41,7 @@ module.exports = {
},

async login (content) {
const { email, password, region = 'eu' } = content
const { email, password, region = EU_CODE } = content
try {
const response = await axios.post(`${this.apiSwitcher(region)}users/login`, {
email: email,
Expand Down Expand Up @@ -96,7 +98,7 @@ module.exports = {
}
},

persistCredentials (email, token = null, region = 'eu') {
persistCredentials (email, token = null, region = EU_CODE) {
if (token) {
this.oauthToken = token
creds.set(email, token, region)
Expand Down Expand Up @@ -168,8 +170,8 @@ module.exports = {
creds.set(null)
},

signup (email, password, region = 'eu') {
return axios.post(USERS_ROUTES.SIGNUP, {
signup (email, password, region = EU_CODE) {
return axios.post(`${this.apiSwitcher(region)}users/signup`, {
email: email,
password: password,
region
Expand Down Expand Up @@ -255,7 +257,6 @@ module.exports = {
.catch(err => Promise.reject(err))
},


post (path, props) {
return this.sendRequest(path, 'post', props)
},
Expand Down Expand Up @@ -310,6 +311,6 @@ module.exports = {
},

apiSwitcher (region) {
return region ? REGIONS[region].apiEndpoint : REGIONS[this.region].apiEndpoint
return region ? getRegionApiEndpoint(region) : getRegionApiEndpoint(this.region)
}
}
11 changes: 6 additions & 5 deletions src/utils/get-questions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { REGIONS } = require('../constants')
const { ALL_REGIONS, EU_CODE } = require('@storyblok/region-helper')

const getOptions = (subCommand, argv = {}, api = {}) => {
let email = ''
const moreOptions = [
Expand All @@ -7,17 +8,17 @@ const getOptions = (subCommand, argv = {}, api = {}) => {
'push-components',
'scaffold'
]
const regionsPrefixList = Object.keys(REGIONS)
const regionInput = {
type: 'input',
name: 'region',
message: `Please enter the region you would like to work in (${regionsPrefixList}) - if not set, default is eu:`,
message: `Please enter the region you would like to work in (${ALL_REGIONS}):`,
default: EU_CODE,
validate: function (value) {
if (regionsPrefixList.indexOf(value) > -1) {
if (ALL_REGIONS.indexOf(value) > -1) {
return true
}

return `Please enter a valid region: ${regionsPrefixList}`
return `Please enter a valid region: ${ALL_REGIONS}`
}
}

Expand Down
1 change: 1 addition & 0 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ module.exports = {
capitalize: require('./capitalize'),
findByProperty: require('./find-by-property'),
parseError: require('./parse-error'),
region: require('./region'),
saveFileFactory: require('./save-file-factory')
}
2 changes: 1 addition & 1 deletion src/utils/last-step.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const lastStep = answers => {
console.log(chalk.green('✓') + ' - The github repository ' + gitRepo + ' will be cloned now...')

ghdownload(gitRepo, outputDir, async (err) => {
if(err) {
if (err) {
if (err.code === 'ENOTEMPTY') {
console.log(chalk.red(' Oh Snap! It seems that you already have a project with the name: ' + name))
reject(new Error('This repository already has been cloned'))
Expand Down
7 changes: 7 additions & 0 deletions src/utils/region.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { getRegionBaseUrl } = require('@storyblok/region-helper')

const getRegionApiEndpoint = (region) => `${getRegionBaseUrl(region)}/v1/`

module.exports = {
getRegionApiEndpoint
}
10 changes: 9 additions & 1 deletion tests/constants.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const { getRegionApiEndpoint } = require('../src/utils/region')
const { EU_CODE } = require('@storyblok/region-helper')
const EMAIL_TEST = 'test@storyblok.com'
const PASSWORD_TEST = 'test'
const TOKEN_TEST = 'storyblok1234'
const REGION_TEST = 'eu'
const REGION_TEST = EU_CODE

// use functions to always returns 'new' data
const FAKE_COMPONENTS = () => [
Expand Down Expand Up @@ -289,9 +291,15 @@ const FAKE_PRESET = () => ({
description: 'page preset'
})

const USERS_ROUTES = {
LOGIN: `${getRegionApiEndpoint(EU_CODE)}users/login`,
SIGNUP: `${getRegionApiEndpoint(EU_CODE)}users/signup`
}

module.exports = {
EMAIL_TEST,
TOKEN_TEST,
USERS_ROUTES,
FAKE_STORIES,
PASSWORD_TEST,
FAKE_COMPONENTS,
Expand Down

0 comments on commit 7a0e234

Please sign in to comment.