Skip to content

Commit 533ad73

Browse files
authored
Merge pull request #14 from cloudinary-devs/add-headless-mode-doc
fix: add headless mode validation and documentation
2 parents 7f6db64 + 157c94c commit 533ad73

3 files changed

Lines changed: 74 additions & 41 deletions

File tree

‎README.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ The CLI will guide you through:
4949
3. **Upload Preset** (Optional): handling unsigned uploads
5050
4. **AI Assistant**: generating custom rules for your tool of choice (Cursor, VS Code, etc.)
5151

52+
## ⚙️ Headless Mode
53+
54+
For CI/CD pipelines, scripts, or automated workflows, pass `--headless` along with all options as flags to skip the interactive prompts:
55+
56+
```bash
57+
npx create-cloudinary-react --headless \
58+
--cloudName your-cloud-name \
59+
--projectName my-app
60+
```
61+
62+
**All options:**
63+
64+
| Flag | Type | Default | Description |
65+
|---|---|---|---|
66+
| `--cloudName` | string | *(required)* | Your Cloudinary cloud name |
67+
| `--projectName` | string | `my-cloudinary-app` | Output directory name |
68+
| `--hasUploadPreset` | boolean | `false` | Set if you have an unsigned upload preset |
69+
| `--uploadPreset` | string | — | Your unsigned upload preset name (required if `--hasUploadPreset`) |
70+
| `--aiTools` | string (repeatable) | `cursor` | AI tools to configure: `cursor`, `copilot`, `claude`, `generic` |
71+
| `--installDeps` | boolean | `true` | Install dependencies after scaffolding |
72+
| `--startDev` | boolean | `false` | Start the dev server after install |
73+
| `--packageManager` | string | *(auto-detected)* | `npm`, `pnpm`, `yarn`, or `bun` |
74+
75+
> **Note:** Shell variables should be quoted to prevent unexpected expansion: `--cloudName "$CLOUD_NAME"`.
76+
5277
## 🛠️ What's Included
5378

5479
Your new project comes with:

‎cli.js‎

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -88,47 +88,55 @@ async function main() {
8888

8989
if (process.argv.includes('--headless')) {
9090

91-
const { values, positionals } = parseArgs({
92-
options: {
93-
headless: {
94-
type: 'boolean'
95-
},
96-
projectName: {
97-
type: 'string',
98-
default: 'my-cloudinary-app'
99-
},
100-
cloudName: {
101-
type: 'string'
102-
},
103-
hasUploadPreset: {
104-
type: 'boolean',
105-
default: false
106-
},
107-
uploadPreset: {
108-
type: 'string'
109-
},
110-
aiTools: {
111-
type: 'string',
112-
multiple: true,
113-
default: ['cursor']
114-
},
115-
installDeps: {
116-
type: 'boolean',
117-
default: true
118-
},
119-
startDev: {
120-
type: 'boolean',
121-
default: false
122-
},
123-
packageManager: {
124-
type: 'string',
91+
let values;
92+
try {
93+
({ values } = parseArgs({
94+
args: process.argv.slice(2).filter(a => a !== '--'),
95+
options: {
96+
headless: { type: 'boolean' },
97+
projectName: { type: 'string', default: 'my-cloudinary-app' },
98+
cloudName: { type: 'string' },
99+
hasUploadPreset: { type: 'boolean', default: false },
100+
uploadPreset: { type: 'string' },
101+
aiTools: { type: 'string', multiple: true, default: ['cursor'] },
102+
installDeps: { type: 'boolean', default: true },
103+
startDev: { type: 'boolean', default: false },
104+
packageManager: { type: 'string' },
125105
},
126-
},
127-
allowPositionals: true,
128-
});
129-
106+
allowPositionals: true,
107+
}));
108+
} catch (e) {
109+
console.error(chalk.red(`Error: ${e.message}`));
110+
process.exit(1);
111+
}
112+
130113
Object.assign(answers, values);
131-
114+
115+
const errors = [];
116+
117+
if (!isValidProjectName(values.projectName)) {
118+
errors.push('--projectName can only contain letters, numbers, hyphens, and underscores');
119+
} else if (existsSync(values.projectName)) {
120+
errors.push(`Directory "${values.projectName}" already exists. Please choose a different name.`);
121+
}
122+
123+
if (!values.cloudName) {
124+
errors.push('--cloudName is required');
125+
} else if (!isValidCloudName(values.cloudName)) {
126+
errors.push('--cloudName can only contain lowercase letters, numbers, hyphens, and underscores');
127+
}
128+
129+
if (values.hasUploadPreset && !values.uploadPreset) {
130+
errors.push('--uploadPreset is required when --hasUploadPreset is set');
131+
}
132+
133+
if (errors.length > 0) {
134+
for (const err of errors) {
135+
console.error(chalk.red(`Error: ${err}`));
136+
}
137+
process.exit(1);
138+
}
139+
132140
} else {
133141

134142
console.log(chalk.cyan.bold('\n🚀 Cloudinary React Starter Kit\n'));

‎package-lock.json‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)