Skip to content
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(cli): cloud cli commands (v4) #20119

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open

Conversation

nathan-pichon
Copy link
Member

@nathan-pichon nathan-pichon commented Apr 15, 2024

What does it do?

This pull request introduces new commands to the Strapi CLI for interacting with Strapi Cloud:

  • strapi login: This command allows users to log in to their Strapi Cloud application directly from the command line.
  • strapi logout: This command enables users to log out of their currently authenticated Strapi Cloud session.
  • strapi deploy: This command provides a streamlined way to deploy the local Strapi project directly to Strapi Cloud.
    These functionalities aim to enhance the developer experience by simplifying authentication and deployment workflows for Strapi Cloud users and providing a seamless hosting solution for Strapi CMS users.

Important Update to create-strapi-app CLI:

Previously, when creating a new Strapi project using create-strapi-app, there was no option to directly connect to a Strapi Cloud project. This pull request also introduces changes to the create-strapi-app command. Users will now be prompted during project creation if they want to create and log in to a new Strapi Cloud project. This simplifies the workflow for developers who intend to deploy their Strapi project to Strapi Cloud from the very beginning.

⚠️ As an MVP restriction, for now, only trial project can be created and managed from the deploy command ⚠️

Why is it needed?

Streamlining deployments: The deploy command automates the deployment process, allowing developers to push their local project to Strapi Cloud directly from the CLI.

How to test it?

  1. Login: Use the strapi login command to authenticate with your Strapi Cloud account. You'll likely be prompted for your credentials during this process (Google / GitHub or GitLab login providers ATM).
  2. Deploy: Ensure you have a local Strapi project ready, you must be able to deploy a trial project (never had any project on Strapi Cloud). Use the strapi deploy command to deploy your project to Strapi Cloud. Verify that the deployment process was completed successfully and your application is accessible on Strapi Cloud.
  3. Logout: User the strapi logout command to disconnect the CLI from your Strapi Cloud account. The strapi deploy should not work after being logged out.

Related issue(s)/PR(s)

Let us know if this is related to any issue/pull request

@nathan-pichon nathan-pichon added source: cli Source is cli package pr: feature This PR adds a new feature echoes/type: feature Effort to deliver new features, significant feature changes and new functionality labels Apr 15, 2024
@nathan-pichon nathan-pichon self-assigned this Apr 15, 2024
@nathan-pichon nathan-pichon changed the title Feat: cloud cli commands (v4) feat(cli): cloud cli commands (v4) Apr 15, 2024
Copy link

vercel bot commented Apr 15, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
contributor-docs ❌ Failed (Inspect) May 7, 2024 10:18am

Co-authored-by: Ben Irvin <ben.irvin@strapi.io>
Copy link
Member

@alexandrebodin alexandrebodin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good 👍

A nice improvement would be to add the "deploy" in the generate package.json script so you can run

yarn deploy, & add it in the log at the end of the creation CLI

import { env } from '@strapi/utils';

export const apiConfig = {
apiBaseUrl: env('STRAPI_CLI_CLOUD_API', 'https://cli.cloud.strapi.io'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

side note: libraries should avoid using env vars and get that as an input param unless it's a debug env var

Considering this will be just a way to test we can live with it. @innerdvations wdyt of a specific prefix for all hardcoded env var ? STRAPI_DEBUG 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds fine to me. STRAPI_ will already be reserved for us, so if we want to call STRAPI_DEBUG_ the debugging prefix it won't cause any issues.

export function getTmpStoragePath() {
const storagePath = path.join(os.tmpdir(), APP_FOLDER_NAME);
if (!checkDirectoryExists(storagePath)) {
fs.mkdirSync(storagePath, { recursive: true });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use fs-extra everywhere in the codebase you could use the ensure fn directly

}

function getConfigPath() {
const configDirs = XDGAppPaths(APP_FOLDER_NAME).configDirs();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would be the advantage ? we are not storing a pwd but just a temp access token 🤔

side note, Also this CLI could be used to automate deployment so we need to support tokens via the CLI in the CI.

}
}

export function saveLocalConfig(data: LocalConfig) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make all those file manipulation async instead ?

case 403:
logger.error(
error.response.data ||
'You do not have permission to create a project. Please contact support for assistance.'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in what case would you get a forbidden considering we do not really have an authorization system ?

packages/cli/cloud/src/services/logger.ts Show resolved Hide resolved
packages/cli/cloud/src/services/logger.ts Show resolved Hide resolved
project?: ProjectInfos;
};

export function save(data: LocalSave, { directoryPath }: { directoryPath?: string } = {}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment on using async fs methods instead

@@ -0,0 +1,43 @@
import chalk from 'chalk';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a //TODO to remove the duplicated code later with a share CLI pkg or sth

packages/cli/create-strapi-app/src/create-strapi-app.ts Outdated Show resolved Hide resolved
@alexandrebodin
Copy link
Member

Should we move "loadPkg" and "logger" to strapi/utils ?

Probably beyond the scope of this PR, but yeah, I think we need a generic logger to use for all these cases outside of Strapi. We've reinvented the wheel about 10 times already.

This should definitely be part of the CLI context passed to all commands 👍 but it goes beyond that as a topic for the CLI API overall

}

function getConfigPath() {
const configDirs = XDGAppPaths(APP_FOLDER_NAME).configDirs();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would allow the user control the security level on the token and keeps it encrypted.

For example, I think most systems would allow users to configure their keychain to ask for verification before the token is accessed (so, someone sitting down at their system couldn't deploy without re-entering password/fingerprint/whatever). But I think what we're doing here is still secure enough for most cases.

I do think a separation by project would be extremely helpful though, otherwise someone with multiple clients on Strapi cloud would have to log in and out between each project, or accidentally attempt to deploy a project with the wrong account (though I assume it wouldn't work).

Alternatively, a login manager to switch between them, but that's a huge feature in itself 😆

import { isIgnoredFile } from '../compress-files';

describe('isIgnoredFile', () => {
const folderPath = os.tmpdir(); // Use the system's temporary directory as a dummy folder path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use mock-fs here to avoid real effects in the test runs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi we use memfs already

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, that one, I misremembered which one we used 😆

Copy link
Member

@joshuaellis joshuaellis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor feedback

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we document here what commands are available?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes me think, don't we have in the contrbiuting guide the CLI command list too ? worth it if the others are listed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy Joel Mchale GIF by ABC Network

);
return;
case 400:
logger.error('Invalid input. Please check your inputs and try again.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can improve this error message, it's really vague. Do you not return a good error message from the API you can utilise?

}
}
logger.error(
'We encountered an issue while creating your project. Please try again in a moment. If the problem persists, contact support for assistance.'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you propose using the debug flag to find more info?


logger.debug(JSON.stringify(error));
if (error instanceof AxiosError) {
switch (error.response?.status) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's 5XX should we handle it to show it's our problem not theres? at the moment it's not clear imo

ctx.logger.log('📦 Project compressed successfully!');
} catch (error: unknown) {
ctx.logger.error(
'⚠️ Project compression failed. Try again later or check for large/incompatible files.'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would trying again later do anything different here?

ctx.logger.error(error.response.data);
}
} else {
ctx.logger.error('An error occurred while deploying the project. Please try again later.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we propose individuals use the debug option to learn more about their issue?

import * as path from 'path';
import { minimatch } from 'minimatch';

const IGNORED_PATTERNS = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why blocklist over allowlist? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allowing custom user code / resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
echoes/type: feature Effort to deliver new features, significant feature changes and new functionality pr: feature This PR adds a new feature source: cli Source is cli package
Projects
Status: To be reviewed (Open)
Development

Successfully merging this pull request may close these issues.

None yet

5 participants