-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add new mc-scripts config:sync
command
#2524
Conversation
🦋 Changeset detectedLatest commit: fe05ab7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/commercetools/merchant-center-application-kit/2AMw91rpjrtHxXfpLSpgUjvLz2DH |
04055fb
to
e700bc8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, functionality wise looks good. I left some feedback to improve different minor things.
@@ -62,6 +62,16 @@ const explorer = cosmiconfigSync(moduleName, { | |||
}, | |||
}); | |||
|
|||
export const getCustomApplicationConfigPath = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think we can simply name this getConfigPath
(as we have the other functions loadConfig
, processConfig
)
.changeset/eleven-nails-change.md
Outdated
This command allows users to synchronize the local custom application config with the one available on the merchant center organization. | ||
|
||
It creates a new custom application if there is no custom application with the entryPointUriPath in the local config file. | ||
|
||
If there is a custom application with the entryPointUriPath available in the merchant center, it is updated with the local configuration upon confirmation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This command allows users to synchronize the local custom application config with the one available on the merchant center organization. | |
It creates a new custom application if there is no custom application with the entryPointUriPath in the local config file. | |
If there is a custom application with the entryPointUriPath available in the merchant center, it is updated with the local configuration upon confirmation. | |
This command allows users to synchronize the local Custom Application config with the Merchant Center. The sync implies that a new Custom Application will be created or an existing one will be updated. | |
Developers can use the `config:sync` command to automatically manage the configuration of a Custom Application from the config file instead of having to manually fill out the information in the Merchant Center. | |
If a new Custom Application needs to be created, an interactive prompt will ask the user to select the Organization where the Custom Application should be configured to. | |
Additionally, the Custom Application ID is automatically synced when running the `config:sync` command. | |
Note that this command requires a valid API token. You can get one by using the `mc-scripts login` command. |
@@ -1,3 +1,4 @@ | |||
export { default as processConfig } from './process-config'; | |||
export { getCustomApplicationConfigPath } from './load-config'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add a separate changeset for the new changes in this package.
const permissionKeys = entryPointUriPathToPermissionKeys( | ||
const permissionKeys = entryPointUriPathToResourceAccesses( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
packages/mc-scripts/src/bin/cli.js
Outdated
@@ -44,6 +44,7 @@ Commands: | |||
|
|||
login Log in to your Merchant Center account through the CLI, using the cloud environment information from the Custom Application config file. An API token is generated and stored in a configuration file for the related cloud environment, and valid for 36 hours. | |||
|
|||
config:sync Synchronizes the local custom application config with the one stored on the merchant center cloud. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config:sync Synchronizes the local custom application config with the one stored on the merchant center cloud. | |
config:sync Synchronizes the local Custom Application config with the Merchant Center. A new Custom Application will be created if none existed, otherwise it will be updated. |
const userOrganizations = await fetchUserOrganizations({ mcApiUrl, token }); | ||
|
||
let organizationId, organizationName; | ||
|
||
if (userOrganizations.total > 1) { | ||
const organizationChoices = userOrganizations.results.map( | ||
(organization) => ({ | ||
title: organization.name, | ||
value: organization.id, | ||
}) | ||
); | ||
|
||
organizationId = await prompts({ | ||
type: 'select', | ||
name: 'organizationId', | ||
message: 'Select Organization', | ||
choices: organizationChoices, | ||
initial: 0, | ||
})['organizationId']; | ||
|
||
organizationName = organizationChoices.find( | ||
({ value }) => value === organizationId | ||
).title; | ||
} else { | ||
organizationId = userOrganizations.results[0].id; | ||
organizationName = userOrganizations.results[0].name; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prompting for the organization is only required for creating a new Custom App.
If the app exists, we already have the organizationId
from the response.
const { confirmation } = await prompts({ | ||
type: 'text', | ||
name: 'confirmation', | ||
message: `You are about to create the configuration in the "${organizationName}" organization in environment ${location}. Are you sure you want to proceed?`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message: `You are about to create the configuration in the "${organizationName}" organization in environment ${location}. Are you sure you want to proceed?`, | |
message: `You are about to create a new Custom Application in the "${organizationName}" organization for the ${mcApiUrl} environment. Are you sure you want to proceed?`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nicola recommendation is great, but bear in mind that perhaps we have an extra "environment" word over there:
You are about to create a new Custom Application in the "${organizationName}" organization for the environment ${mcApiUrl} environment. Are you sure you want to proceed?
Maybe we could use only one:
You are about to create a new Custom Application in the "${organizationName}" organization for the ${mcApiUrl} environment. Are you sure you want to proceed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes thanks, it's a typo.
); | ||
console.log( | ||
chalk.green( | ||
`You have successfully created the configuration in the "${organizationName}" organization in environment ${location}.\nYour local configuration has also been updated with the newly created application identifier: ${createdCustomApplication.id}.\nLink to the created custom application is ${customAppLink}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`You have successfully created the configuration in the "${organizationName}" organization in environment ${location}.\nYour local configuration has also been updated with the newly created application identifier: ${createdCustomApplication.id}.\nLink to the created custom application is ${customAppLink}` | |
`Custom Application created.\nThe "applicationId" in your local Custom Application config file has been updated with the application ID.\nYou can see the Custom Application data in the Merchant Center at ${customAppLink}.` |
const { confirmation } = await prompts({ | ||
type: 'text', | ||
name: 'confirmation', | ||
message: `You are about to update the configuration in the "${organizationName}" organization in environment ${location}. Are you sure you want to proceed?`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message: `You are about to update the configuration in the "${organizationName}" organization in environment ${location}. Are you sure you want to proceed?`, | |
message: `You are about to update the Custom Application "${entryPointUriPath}" in the ${mcApiUrl} environment. Are you sure you want to proceed?`, |
); | ||
console.log( | ||
chalk.green( | ||
`You have successfully updated the configuration in the "${organizationName}" organization in environment ${location}.\nLink to the created custom application is ${customAppLink}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`You have successfully updated the configuration in the "${organizationName}" organization in environment ${location}.\nLink to the created custom application is ${customAppLink}` | |
`You have successfully updated the configuration in the "${organizationName}" organization in environment ${location}.\nLink to the created custom application is ${customAppLink}` | |
`Custom Application updated.\nYou can see the Custom Application data in the Merchant Center at ${customAppLink}.` |
@@ -0,0 +1,138 @@ | |||
const omit = require('lodash/omit'); | |||
const prompts = require('prompts'); | |||
const chalk = require('react-dev-utils/chalk'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we are relying in the fact that react-dev-utils
dependency currently export chalk
.
Given that we are going to use that dependency directly I guess it would be safer to explicitly depend on it by itself declaring it in our package.json
.
initial: 'yes', | ||
}); | ||
if (confirmation.toLowerCase().charAt(0) !== 'y') { | ||
console.log('Aborted.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we could use chalk
(red?) here to be more explicit with the message.
initial: 'yes', | ||
}); | ||
if (confirmation.toLowerCase().charAt(0) !== 'y') { | ||
console.log('Aborted.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we could use chalk
(red?) here to be more explicit with the message.
}; | ||
|
||
configSync().catch((error) => { | ||
console.error(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we could use chalk
(red?) here to be more explicit with the message.
getCustomApplicationConfigPath, | ||
} = require('@commercetools-frontend/application-config'); | ||
|
||
function updateApplicationIdInCustomApplicationConfig(applicationId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering if we could maybe just update the applicationId using a regular expression to make this process simpler.
Maybe something like:
configFileContents.replace(/("env":.*"production":.*"applicationId":\s?)"(\w*)"/, '$1"[REPLACER]"')
(perhaps this is more complex than I can see)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: we use this also int he create-mc-app
CLI, as we need to update more fields.
Also to note, that this is only for JS files. For JSON we can update it directly. @Rhotimee I think I mentioned this last time but I forgot to follow up with you. We need to adjust the update logic in case the config is a JSON file.
…custom application
…application-config package
f1e7128
to
db8d013
Compare
@emmenko @CarlosCortizasCT, thanks for the feedback. All feedback above has been Implemented. Kindly take another look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, looks much better now thanks!
Just a few minor adjustments and then we're good to go 🚀
.changeset/tidy-zoos-applaud.md
Outdated
'@commercetools-frontend/application-config': minor | ||
--- | ||
|
||
Implement and expose getConfigPath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement and expose getConfigPath | |
Expose a new function `getConfigPath` to return the absolute file path of the Custom Application config file. |
if (userOrganizations.total > 1) { | ||
const organizationChoices = userOrganizations.results.map( | ||
(organization) => ({ | ||
title: organization.name, | ||
value: organization.id, | ||
}) | ||
); | ||
|
||
organizationId = await prompts({ | ||
type: 'select', | ||
name: 'organizationId', | ||
message: 'Select Organization', | ||
choices: organizationChoices, | ||
initial: 0, | ||
})['organizationId']; | ||
|
||
organizationName = organizationChoices.find( | ||
({ value }) => value === organizationId | ||
).title; | ||
} else { | ||
organizationId = userOrganizations.results[0].id; | ||
organizationName = userOrganizations.results[0].name; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also check if there are no organizations. In this case we need to throw an error.
And maybe invert the condition.
if (userOrganizations.total > 1) { | |
const organizationChoices = userOrganizations.results.map( | |
(organization) => ({ | |
title: organization.name, | |
value: organization.id, | |
}) | |
); | |
organizationId = await prompts({ | |
type: 'select', | |
name: 'organizationId', | |
message: 'Select Organization', | |
choices: organizationChoices, | |
initial: 0, | |
})['organizationId']; | |
organizationName = organizationChoices.find( | |
({ value }) => value === organizationId | |
).title; | |
} else { | |
organizationId = userOrganizations.results[0].id; | |
organizationName = userOrganizations.results[0].name; | |
} | |
if (userOrganizations.total === 0) { | |
throw new Error(`It seems you are not an admin of any Organization. Please make sure to be part of the Administrators team of the Organization you want the Custom Application to be configured to.`); | |
} | |
if (userOrganizations.total === 1) { | |
organizationId = userOrganizations.results[0].id; | |
organizationName = userOrganizations.results[0].name; | |
} else { | |
const organizationChoices = userOrganizations.results.map( | |
(organization) => ({ | |
title: organization.name, | |
value: organization.id, | |
}) | |
); | |
organizationId = await prompts({ | |
type: 'select', | |
name: 'organizationId', | |
message: 'Select Organization', | |
choices: organizationChoices, | |
initial: 0, | |
})['organizationId']; | |
organizationName = organizationChoices.find( | |
({ value }) => value === organizationId | |
).title; | |
} |
'x-graphql-target': target, | ||
'x-mc-cli-access-token': token, | ||
'x-user-agent': userAgent, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'x-graphql-target': target, | |
'x-mc-cli-access-token': token, | |
'x-user-agent': userAgent, | |
Accept: 'application/json', | |
'Content-Type': 'application/json', | |
'x-graphql-target': target, | |
'x-mc-cli-access-token': token, | |
'x-user-agent': userAgent, |
@@ -0,0 +1,113 @@ | |||
const { GraphQLClient } = require('graphql-request'); | |||
const { GRAPHQL_TARGETS } = require('@commercetools-frontend/constants'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please define this dependency in the package.json
.
customApplicationConfig.env.production.applicationId = applicationId; | ||
fs.writeFileSync( | ||
filePath, | ||
JSON.stringify(customApplicationConfig, null, 2), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's format this with Prettier as well.
|
||
If a new Custom Application needs to be created, an interactive prompt will ask the user to select the Organization where the Custom Application should be configured to. | ||
|
||
Additionally, the Custom Application ID is automatically synced when running the `config:sync` command. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, the Custom Application ID is automatically synced when running the `config:sync` command. | |
Additionally, the [Custom Application ID](/api-reference/application-config#envproductionapplicationid) is automatically synced when running the `config:sync` command. |
```console | ||
mc-scripts config:sync | ||
``` | ||
--> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--> | |
<Info> | |
The command uses the [cloud Region](/concepts/merchant-center-api#cloud-regions) environment information from the Custom Application config. | |
</Info> | |
--> |
// update applicationID in the custom-application-config file | ||
updateApplicationIdInCustomApplicationConfig( | ||
fetchedCustomApplication.application.id | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it actually possible for the ID of a Custom Application to change after its creation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to my knowledge. It's a Prisma generated cuid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. But, it is possible that the user created the custom app on the merchant center and not with the cli.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is to update the local custom-application-config with the applicationId.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Speaking of the applicationId
, we need to consider this use case: the config might use an env placeholder for the application id, e.g. ${env:APPLICATION_ID}
.
In this case, we can't really replace the value.
I suppose we should only do that when we create a new Custom App. When updating, we shouldn't rewrite the value.
@Rhotimee Could you adjust the logic? Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure 👍🏽
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
I noticed that the build bundle does not contain the I'll also add a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 🚀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work 👏
Implement a new
config:sync
command formc-scripts
.See changelog for more information