From 8de8e3038aa57d8cc92bf0d9ede46fd5c28d0fbc Mon Sep 17 00:00:00 2001 From: Tate Date: Fri, 17 Jul 2026 12:02:52 +1200 Subject: [PATCH 01/12] Add sites create command for git-connected sites --- README.md | 46 +++++++-- biome.json | 3 +- src/orgs.ts | 15 +-- src/orgs/inboxes.ts | 11 +- src/orgs/resolve.ts | 31 ++++-- src/orgs/sites.ts | 11 +- src/sites.ts | 2 + src/sites/create.ts | 239 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 319 insertions(+), 39 deletions(-) create mode 100644 src/sites/create.ts diff --git a/README.md b/README.md index d409982..2ea36e4 100644 --- a/README.md +++ b/README.md @@ -284,35 +284,37 @@ cloudcannon orgs list --- -### `orgs get --org ` +### `orgs get [org]` -Get an organisation by name, ID, or UUID. +Get an organisation by name, ID, or UUID. If you belong to only one organisation, it is selected automatically. ```sh cloudcannon orgs get --org my-org +cloudcannon orgs get ``` **Flags** | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID (required) | +| `--org ` | The organisation name, ID, or UUID | --- -### `orgs sites list --org ` +### `orgs sites list [org]` -List all sites for an organisation. +List all sites for an organisation. If you belong to only one organisation, it is selected automatically. ```sh cloudcannon orgs sites list --org my-org +cloudcannon orgs sites list ``` **Flags** | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID (required) | +| `--org ` | The organisation name, ID, or UUID | | `--page ` | Page number to fetch | | `--items ` | Number of items per page | | `--sort-by ` | Field name to sort by | @@ -321,19 +323,20 @@ cloudcannon orgs sites list --org my-org --- -### `orgs inboxes list --org ` +### `orgs inboxes list [org]` -List all inboxes for an organisation. +List all inboxes for an organisation. If you belong to only one organisation, it is selected automatically. ```sh cloudcannon orgs inboxes list --org my-org +cloudcannon orgs inboxes list ``` **Flags** | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID (required) | +| `--org ` | The organisation name, ID, or UUID | | `--page ` | Page number to fetch | | `--items ` | Number of items per page | | `--sort-by ` | Field name to sort by | @@ -352,6 +355,31 @@ cloudcannon sites list --- +### `sites create [source]` + +Create a new site connected to a git repository. The `source` positional is a git remote URL with an optional `#branch` suffix. + +```sh +# Interactive — prompts for org, name, and source +cloudcannon sites create + +# Non-interactive — all fields provided +cloudcannon sites create --org my-org --name my-site https://github.com/owner/repo.git#main +``` + +Run without all required fields to get interactive prompts for the missing pieces. If you belong to only one organisation, it is selected automatically — use `--org` to override. The source URL defaults to your local `git remote get-url origin` if available. After creating the site, a link to open it in CloudCannon is printed. + +**Flags** + +| Flag | Description | +|---|---| +| `--org ` | The organisation name, ID, or UUID | +| `--name ` | The site name | + +Supported git hosts: `github.com`, `gitlab.com`, `bitbucket.org`. + +--- + ### `sites get --site ` Get a site by name, ID, UUID, or domain. diff --git a/biome.json b/biome.json index 12d4b53..5039353 100644 --- a/biome.json +++ b/biome.json @@ -13,7 +13,8 @@ "!package.json", "!package-lock.json", "!.github", - "!toolproof-tests/test-sites" + "!toolproof-tests/test-sites", + "!src/templates" ] }, "formatter": { diff --git a/src/orgs.ts b/src/orgs.ts index 57da3bd..e002b16 100644 --- a/src/orgs.ts +++ b/src/orgs.ts @@ -3,7 +3,7 @@ import { defineCommand } from 'citty'; import { printJson } from './configure/utility.ts'; import { buildListOptions, listFlagDefs } from './list-options.ts'; import { orgsInboxesCommand } from './orgs/inboxes.ts'; -import { resolveOrgUuid } from './orgs/resolve.ts'; +import { resolveOrg } from './orgs/resolve.ts'; import { orgsSitesCommand } from './orgs/sites.ts'; import { getSdkClient, handleAPIError } from './sdk-client.ts'; @@ -41,23 +41,16 @@ export const orgsGetCommand = defineCommand({ type: 'string', description: 'The organisation name, ID, or UUID', valueHint: 'name|id|uuid', - required: true, }, }, async run(ctx): Promise { const client = await getSdkClient(); - const orgUuid = await resolveOrgUuid(client, ctx.args.org); - if (!orgUuid) { + const org = await resolveOrg(client, ctx.args.org); + if (!org) { process.exitCode = 1; return; } - try { - const org = await client.org(orgUuid).get(); - printJson(org); - } catch (err: unknown) { - handleAPIError(err); - process.exitCode = 1; - } + printJson(org); }, }); diff --git a/src/orgs/inboxes.ts b/src/orgs/inboxes.ts index 385c610..5a8c195 100644 --- a/src/orgs/inboxes.ts +++ b/src/orgs/inboxes.ts @@ -3,7 +3,7 @@ import { defineCommand } from 'citty'; import { printJson } from '../configure/utility.ts'; import { buildListOptions, listFlagDefs } from '../list-options.ts'; import { getSdkClient, handleAPIError } from '../sdk-client.ts'; -import { resolveOrgUuid } from './resolve.ts'; +import { resolveOrg } from './resolve.ts'; export const orgsInboxesListCommand = defineCommand({ meta: { @@ -15,21 +15,20 @@ export const orgsInboxesListCommand = defineCommand({ type: 'string', description: 'The organisation name, ID, or UUID', valueHint: 'name|id|uuid', - required: true, }, ...listFlagDefs, }, async run(ctx): Promise { const client = await getSdkClient(); - const orgUuid = await resolveOrgUuid(client, ctx.args.org); - if (!orgUuid) { + const org = await resolveOrg(client, ctx.args.org); + if (!org) { process.exitCode = 1; return; } - const org = client.org(orgUuid); + const orgClient = client.org(org.uuid); const options = buildListOptions(ctx.args); try { - const inboxes = await org.getInboxes(options as ListOrgInboxesOptions); + const inboxes = await orgClient.getInboxes(options as ListOrgInboxesOptions); printJson({ current_page: inboxes.current_page, total_pages: inboxes.total_pages, diff --git a/src/orgs/resolve.ts b/src/orgs/resolve.ts index 29b030c..bf17ea0 100644 --- a/src/orgs/resolve.ts +++ b/src/orgs/resolve.ts @@ -1,16 +1,34 @@ import type CloudCannonClient from '@cloudcannon/sdk'; -import type { ListOrgsOptions } from '@cloudcannon/sdk'; +import type { ListOrgsOptions, Org } from '@cloudcannon/sdk'; import { printJson } from '../configure/utility.ts'; import { handleAPIError } from '../sdk-client.ts'; const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; -export async function resolveOrgUuid( +export async function resolveOrg( client: CloudCannonClient, - identifier: string -): Promise { + identifier?: string +): Promise { + if (!identifier) { + try { + const orgs = await client.orgs(); + if (orgs.items.length === 1) { + return orgs.items[0]; + } + return; + } catch (err: unknown) { + handleAPIError(err); + return; + } + } + if (UUID_REGEX.test(identifier)) { - return identifier; + try { + return await client.org(identifier).get(); + } catch (err: unknown) { + handleAPIError(err); + return; + } } const filters: ListOrgsOptions['filters'] = {}; @@ -21,6 +39,7 @@ export async function resolveOrgUuid( } else { filters.search = identifier; } + try { const orgs = await client.orgs({ filters }); @@ -35,7 +54,7 @@ export async function resolveOrgUuid( return; } - return orgs.items[0].uuid; + return orgs.items[0]; } catch (err: unknown) { handleAPIError(err); return; diff --git a/src/orgs/sites.ts b/src/orgs/sites.ts index 839e5b9..3f151ef 100644 --- a/src/orgs/sites.ts +++ b/src/orgs/sites.ts @@ -3,7 +3,7 @@ import { defineCommand } from 'citty'; import { printJson } from '../configure/utility.ts'; import { buildListOptions, listFlagDefs } from '../list-options.ts'; import { getSdkClient, handleAPIError } from '../sdk-client.ts'; -import { resolveOrgUuid } from './resolve.ts'; +import { resolveOrg } from './resolve.ts'; export const orgsSitesListCommand = defineCommand({ meta: { @@ -15,21 +15,20 @@ export const orgsSitesListCommand = defineCommand({ type: 'string', description: 'The organisation name, ID, or UUID', valueHint: 'name|id|uuid', - required: true, }, ...listFlagDefs, }, async run(ctx): Promise { const client = await getSdkClient(); - const orgUuid = await resolveOrgUuid(client, ctx.args.org); - if (!orgUuid) { + const org = await resolveOrg(client, ctx.args.org as string | undefined); + if (!org) { process.exitCode = 1; return; } - const org = client.org(orgUuid); + const orgClient = client.org(org.uuid); const options = buildListOptions(ctx.args); try { - const sites = await org.sites(options as ListOrgSitesOptions); + const sites = await orgClient.sites(options as ListOrgSitesOptions); printJson({ current_page: sites.current_page, total_pages: sites.total_pages, diff --git a/src/sites.ts b/src/sites.ts index 61a0dae..a785735 100644 --- a/src/sites.ts +++ b/src/sites.ts @@ -3,6 +3,7 @@ import { defineCommand } from 'citty'; import { printJson } from './configure/utility.ts'; import { getSdkClient, handleAPIError } from './sdk-client.ts'; import { sitesBuildsCommand } from './sites/builds.ts'; +import { sitesCreateCommand } from './sites/create.ts'; import { sitesFilesCommand } from './sites/files.ts'; import { sitesPrintLastBuildCommand, @@ -251,6 +252,7 @@ export const sitesCommand = defineCommand({ subCommands: { list: sitesListCommand, get: sitesGetCommand, + create: sitesCreateCommand, rebuild: sitesRebuildCommand, 'update-build-config': sitesUpdateBuildConfigCommand, files: sitesFilesCommand, diff --git a/src/sites/create.ts b/src/sites/create.ts new file mode 100644 index 0000000..2ebd19d --- /dev/null +++ b/src/sites/create.ts @@ -0,0 +1,239 @@ +import { execFile } from 'node:child_process'; +import { basename } from 'node:path'; +import { promisify } from 'node:util'; +import * as p from '@clack/prompts'; +import type CloudCannonClient from '@cloudcannon/sdk'; +import type { Org, Provider } from '@cloudcannon/sdk'; +import { defineCommand } from 'citty'; +import { exitOnCancel, text } from '../configure/utility.ts'; +import { resolveOrg } from '../orgs/resolve.ts'; +import { getSdkClient, handleAPIError } from '../sdk-client.ts'; + +const execFileAsync = promisify(execFile); + +const PROVIDER_HOSTS: Record = { + 'github.com': 'github', + 'gitlab.com': 'gitlab', + 'bitbucket.org': 'bitbucket', +}; + +interface ParsedSource { + provider: Provider; + repository: string; + branch?: string; +} + +export function parseSourceUrl(raw: string): ParsedSource | undefined { + // Normalize SCP-style SSH (git@host:path or git@host/path) to ssh://git@host/path + const normalized = raw + .trim() + .replace(/^git@([^:]+):(.+)$/, 'ssh://git@$1/$2') + .replace(/^git@([^/]+)\/(.+)$/, 'ssh://git@$1/$2'); + + let url: URL; + try { + url = new URL(normalized); + } catch { + return undefined; + } + + const provider = PROVIDER_HOSTS[url.host]; + if (!provider) { + return undefined; + } + + // pathname: /owner/repo.git -> owner/repo + const path = url.pathname + .replace(/^\/+/, '') + .replace(/\/+$/, '') + .replace(/\.git$/, ''); + const parts = path.split('/'); + if (parts.length < 2) { + return undefined; + } + + const repository = parts.slice(-2).join('/'); + const branch = url.hash ? url.hash.slice(1) || undefined : undefined; + + return { provider, repository, branch }; +} + +async function getLocalGitRemote(): Promise { + try { + const { stdout } = await execFileAsync('git', ['remote', 'get-url', 'origin']); + return stdout.trim() || undefined; + } catch { + return undefined; + } +} + +async function getLocalGitBranch(): Promise { + try { + const { stdout } = await execFileAsync('git', ['branch', '--show-current']); + return stdout.trim() || undefined; + } catch { + return undefined; + } +} + +async function promptOrg(client: CloudCannonClient, prefilled?: string): Promise { + const resolved = await resolveOrg(client, prefilled); + if (resolved) { + return resolved; + } + + if (typeof prefilled === 'string') { + process.exitCode = 1; + return; + } + + try { + const orgs = await client.orgs(); + if (orgs.items.length === 0) { + console.error('No organisations found for this account.'); + return; + } + + const options = orgs.items.map((org) => ({ + value: org.uuid, + label: org.name ?? org.uuid, + })); + + const choice = await p.select({ + message: 'Select an organisation:', + options, + }); + exitOnCancel(choice); + + const selected = orgs.items.find((org) => org.uuid === choice); + return selected; + } catch (err: unknown) { + handleAPIError(err); + return; + } +} + +export const sitesCreateCommand = defineCommand({ + meta: { + name: 'create', + description: 'Create a new site connected to a git repository.', + }, + args: { + source: { + type: 'positional', + description: 'Git remote URL with optional #branch suffix', + valueHint: 'url[#branch]', + required: false, + }, + org: { + type: 'string', + description: 'The organisation name, ID, or UUID', + valueHint: 'name|id|uuid', + }, + name: { + type: 'string', + description: 'The site name', + valueHint: 'name', + }, + }, + async run(ctx): Promise { + const client = await getSdkClient(); + + const org = await promptOrg(client, ctx.args.org); + if (!org) { + process.exitCode = 1; + return; + } + + const defaultRemote = await getLocalGitRemote(); + + let defaultParsed: ParsedSource | undefined = ctx.args.source + ? parseSourceUrl(ctx.args.source) + : undefined; + defaultParsed ??= defaultRemote ? parseSourceUrl(defaultRemote) : undefined; + + let siteName: string; + if (ctx.args.name) { + siteName = ctx.args.name; + } else { + const defaultName = defaultParsed?.repository.split('/')[1] ?? basename(process.cwd()); + const nameInput = await p.text({ + message: 'Site name:', + placeholder: defaultName, + defaultValue: defaultName, + }); + exitOnCancel(nameInput); + siteName = nameInput; + } + + let source: ParsedSource | undefined; + if (ctx.args.source) { + source = parseSourceUrl(ctx.args.source); + if (!source) { + console.error( + text.bad( + `Could not parse "${ctx.args.source}".\n` + + 'Supported hosts: github.com, gitlab.com, bitbucket.org.\n' + + 'Expected formats: https://github.com/owner/repo.git#branch or git@github.com:owner/repo.git#branch' + ) + ); + process.exitCode = 1; + return; + } + } else { + const sourceInput = await p.text({ + message: 'Enter the git remote URL for your site:', + placeholder: defaultRemote ?? 'https://github.com/owner/repo.git#main', + defaultValue: defaultRemote ?? '', + }); + exitOnCancel(sourceInput); + + source = parseSourceUrl(sourceInput); + if (!source) { + console.error( + text.bad( + `Could not parse "${sourceInput}".\n` + + 'Supported hosts: github.com, gitlab.com, bitbucket.org.\n' + + 'Expected formats: https://github.com/owner/repo.git#branch or git@github.com:owner/repo.git#branch' + ) + ); + process.exitCode = 1; + return; + } + } + + let branch = source?.branch; + if (!branch) { + const defaultBranch = (await getLocalGitBranch()) ?? 'main'; + const branchInput = await p.text({ + message: 'Branch:', + defaultValue: defaultBranch, + placeholder: defaultBranch, + }); + exitOnCancel(branchInput); + branch = branchInput; + } + + try { + const created = await client.org(org.uuid).createSite(siteName); + if (!created.uuid) { + console.error(text.bad('Site was created but no UUID was returned.')); + process.exitCode = 1; + return; + } + + const site = await client.site(created.uuid).connectSourceProvider({ + provider: source.provider, + repository: source.repository, + branch, + }); + + console.log(text.good(`Site "${siteName}" created successfully.`)); + const appUrl = `https://app.cloudcannon.com/${org.id}/editor#sites/${site.id}`; + console.log(`Open in CloudCannon: ${text.em(appUrl)}`); + } catch (err: unknown) { + handleAPIError(err); + process.exitCode = 1; + } + }, +}); From 7e35b61d1e88445e2a79b984f3e48cb20c5ab9c8 Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:16:19 +1200 Subject: [PATCH 02/12] Update src/sites/create.ts Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- src/sites/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sites/create.ts b/src/sites/create.ts index 2ebd19d..c71376c 100644 --- a/src/sites/create.ts +++ b/src/sites/create.ts @@ -90,7 +90,7 @@ async function promptOrg(client: CloudCannonClient, prefilled?: string): Promise try { const orgs = await client.orgs(); if (orgs.items.length === 0) { - console.error('No organisations found for this account.'); + console.error('No organizations found for this account.'); return; } From 792e59c1b02eeec423610cbd6e9a9b30fd58148d Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:16:27 +1200 Subject: [PATCH 03/12] Update src/sites/create.ts Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- src/sites/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sites/create.ts b/src/sites/create.ts index c71376c..bbe6451 100644 --- a/src/sites/create.ts +++ b/src/sites/create.ts @@ -100,7 +100,7 @@ async function promptOrg(client: CloudCannonClient, prefilled?: string): Promise })); const choice = await p.select({ - message: 'Select an organisation:', + message: 'Select an organization:', options, }); exitOnCancel(choice); From b8e226c7da850ccd5db9c0b4d6f601a3de5c6628 Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:16:34 +1200 Subject: [PATCH 04/12] Update src/sites/create.ts Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- src/sites/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sites/create.ts b/src/sites/create.ts index bbe6451..8414cb7 100644 --- a/src/sites/create.ts +++ b/src/sites/create.ts @@ -127,7 +127,7 @@ export const sitesCreateCommand = defineCommand({ }, org: { type: 'string', - description: 'The organisation name, ID, or UUID', + description: 'The organization name, ID, or UUID', valueHint: 'name|id|uuid', }, name: { From 64060ed354ae8b8d5e6d7bfd60e5d8b0b5ea78c9 Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:16:41 +1200 Subject: [PATCH 05/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ea36e4..e598a08 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ cloudcannon orgs get | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID | +| `--org ` | The organization name, ID, or UUID | --- From 78600d3abaa73009693b6a3456cede1ed1d1ad6e Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:16:49 +1200 Subject: [PATCH 06/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e598a08..208c10f 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ cloudcannon orgs sites list | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID | +| `--org ` | The organization name, ID, or UUID | | `--page ` | Page number to fetch | | `--items ` | Number of items per page | | `--sort-by ` | Field name to sort by | From 2883c663dc6eeeaa99cead3f143a41e843f2eb55 Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:16:56 +1200 Subject: [PATCH 07/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 208c10f..ee090f7 100644 --- a/README.md +++ b/README.md @@ -325,7 +325,7 @@ cloudcannon orgs sites list ### `orgs inboxes list [org]` -List all inboxes for an organisation. If you belong to only one organisation, it is selected automatically. +List all inboxes for an organization. If you belong to only one organization, it is selected automatically. ```sh cloudcannon orgs inboxes list --org my-org From c1f8b0df3cb748fe66c6782533fdaa8c4002be34 Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:17:05 +1200 Subject: [PATCH 08/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ee090f7..8fa4af0 100644 --- a/README.md +++ b/README.md @@ -367,7 +367,7 @@ cloudcannon sites create cloudcannon sites create --org my-org --name my-site https://github.com/owner/repo.git#main ``` -Run without all required fields to get interactive prompts for the missing pieces. If you belong to only one organisation, it is selected automatically — use `--org` to override. The source URL defaults to your local `git remote get-url origin` if available. After creating the site, a link to open it in CloudCannon is printed. +Run without all required fields to get interactive prompts for the missing pieces. If you belong to only one organization, it is selected automatically — use `--org` to override. The source URL defaults to your local `git remote get-url origin` if available. After creating the site, a link to open it in CloudCannon is printed. **Flags** From ed3e9292f982d431ffaef8f65154c883c55850fa Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:17:14 +1200 Subject: [PATCH 09/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fa4af0..4f7dd0f 100644 --- a/README.md +++ b/README.md @@ -373,7 +373,7 @@ Run without all required fields to get interactive prompts for the missing piece | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID | +| `--org ` | The organization name, ID, or UUID | | `--name ` | The site name | Supported git hosts: `github.com`, `gitlab.com`, `bitbucket.org`. From baeaf12de2ea0d9e666076524b6d269ac861b903 Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:17:31 +1200 Subject: [PATCH 10/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f7dd0f..f0151a9 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,7 @@ cloudcannon orgs get ### `orgs sites list [org]` -List all sites for an organisation. If you belong to only one organisation, it is selected automatically. +List all sites for an organization. If you belong to only one organization, it is selected automatically. ```sh cloudcannon orgs sites list --org my-org From 9707e393e21302e35ae9a5a00e4a6316b9d7813b Mon Sep 17 00:00:00 2001 From: Tate-CC <63823334+Tate-CC@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:17:40 +1200 Subject: [PATCH 11/12] Update README.md Co-authored-by: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0151a9..709f4b0 100644 --- a/README.md +++ b/README.md @@ -286,7 +286,7 @@ cloudcannon orgs list ### `orgs get [org]` -Get an organisation by name, ID, or UUID. If you belong to only one organisation, it is selected automatically. +Get an organization by name, ID, or UUID. If you belong to only one organization, it is selected automatically. ```sh cloudcannon orgs get --org my-org From acee52e5da68fe8913d9e8ed9ef836614d17c22c Mon Sep 17 00:00:00 2001 From: Ross Phillips <12723297+rphillips-cc@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:40:12 +1200 Subject: [PATCH 12/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 709f4b0..8e5a65e 100644 --- a/README.md +++ b/README.md @@ -336,7 +336,7 @@ cloudcannon orgs inboxes list | Flag | Description | |---|---| -| `--org ` | The organisation name, ID, or UUID | +| `--org ` | The organization name, ID, or UUID | | `--page ` | Page number to fetch | | `--items ` | Number of items per page | | `--sort-by ` | Field name to sort by |