@ossy/cli 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,6 +9,7 @@ Unified CLI for the Ossy platform: app dev/build and CMS workflows.
9
9
  | `init [dir]` | Scaffold a new Ossy app (default: current directory) |
10
10
  | `dev` | Start dev server with watch (uses `src/*.page.jsx` or `src/pages.jsx`, `src/config.js`) |
11
11
  | `build` | Production build |
12
+ | `publish` | Queue a container deployment via `@ossy/deployment-tools` (see below) |
12
13
  | `cms upload` | Upload resource templates to your workspace |
13
14
  | `cms validate` | Validate ossy config and resource templates |
14
15
 
@@ -21,6 +22,26 @@ npx @ossy/cli build
21
22
 
22
23
  Options: `--pages`, `--config`, `--destination`. See `@ossy/app` for details.
23
24
 
25
+ ## Publish (container / website)
26
+
27
+ Publishes a site by sending a deployment request to your platform queue (same as `npx @ossy/deployment-tools deployment deploy`). Run from the **website package** directory (where `src/config.js` lives) so domain/platform can be read automatically.
28
+
29
+ ```bash
30
+ cd packages/my-website
31
+ npx @ossy/cli publish \
32
+ --username <github-username> \
33
+ --authentication <token> \
34
+ --platforms-path ../infrastructure/platforms.json \
35
+ --deployments-path ../infrastructure/deployments.json
36
+ ```
37
+
38
+ - **`--domain` / `--platform`** — Optional if `src/config.js` contains string literals `domain: '…'` and `platform: '…'` (or `targetDeploymentPlatform`).
39
+ - **`--config`** — Path to another `config.js` if not `./src/config.js`.
40
+ - If `platform` is omitted but `domain` is set (from flags or config), it is inferred from `deployments.json` when that domain appears under exactly one `targetDeploymentPlatform`.
41
+ - **`--all`** — Runs `deployment deploy-all` for the platform; requires `--platform` or `platform` in config.
42
+
43
+ Requires network access so `npx` can run `@ossy/deployment-tools`.
44
+
24
45
  ## CMS: upload
25
46
 
26
47
  Upload resource templates to your workspace so they can be used in the UI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/cli",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ossy-se/packages.git"
@@ -17,8 +17,9 @@
17
17
  "license": "MIT",
18
18
  "bin": "./src/index.js",
19
19
  "dependencies": {
20
- "@ossy/app": "^0.14.0",
21
- "arg": "^5.0.2"
20
+ "@ossy/app": "^0.15.0",
21
+ "arg": "^5.0.2",
22
+ "glob": "^10.3.10"
22
23
  },
23
24
  "publishConfig": {
24
25
  "access": "public",
@@ -28,5 +29,5 @@
28
29
  "/src",
29
30
  "README.md"
30
31
  ],
31
- "gitHead": "032e21b623b973a715d532580022f393b1f9d389"
32
+ "gitHead": "a575c008d0b4ebba15186143db5fc837bd6ac2d7"
32
33
  }
package/src/index.js CHANGED
@@ -2,11 +2,12 @@
2
2
  import { build, dev } from '@ossy/app'
3
3
  import * as Cms from './cms/cli.js'
4
4
  import * as Init from './init/cli.js'
5
+ import { publish } from './publish/cli.js'
5
6
 
6
7
  const [,, command, ...restArgs] = process.argv
7
8
 
8
9
  if (!command) {
9
- console.error('[@ossy/cli] No command provided. Usage: ossy dev | build | init | cms <subcommand>')
10
+ console.error('[@ossy/cli] No command provided. Usage: ossy dev | build | publish | init | cms <subcommand>')
10
11
  process.exit(1)
11
12
  }
12
13
 
@@ -19,6 +20,10 @@ const run = async () => {
19
20
  Init.init(restArgs)
20
21
  return
21
22
  }
23
+ if (command === 'publish') {
24
+ await publish(restArgs)
25
+ return
26
+ }
22
27
  if (command === 'dev') {
23
28
  await dev(restArgs)
24
29
  return
@@ -0,0 +1,132 @@
1
+ import { existsSync } from 'fs'
2
+ import { resolve as pathResolve } from 'path'
3
+ import { spawn } from 'child_process'
4
+ import arg from 'arg'
5
+ import { logInfo, logError } from '../log.js'
6
+ import {
7
+ readWebsiteConfigDeployFields,
8
+ resolvePlatformFromDeployments
9
+ } from './resolve-config.js'
10
+
11
+ const DEPLOYMENT_TOOLS = '@ossy/deployment-tools'
12
+
13
+ function runNpxDeploymentTools (deploymentArgs) {
14
+ const args = ['--yes', DEPLOYMENT_TOOLS, 'deployment', ...deploymentArgs]
15
+ logInfo({ message: `[@ossy/cli] publish: npx ${DEPLOYMENT_TOOLS} deployment ${deploymentArgs[0]} …` })
16
+ return new Promise((resolvePromise, reject) => {
17
+ const child = spawn('npx', args, { stdio: 'inherit', shell: true })
18
+ child.on('error', reject)
19
+ child.on('close', (code) => {
20
+ if (code === 0) resolvePromise()
21
+ else reject(new Error(`npx exited with code ${code}`))
22
+ })
23
+ })
24
+ }
25
+
26
+ /**
27
+ * Publish container deployments: default = one site (`deployment deploy`);
28
+ * `--all` = `deployment deploy-all` for the platform.
29
+ */
30
+ export async function publish (options) {
31
+ const parsedArgs = arg({
32
+ '--username': String,
33
+ '-u': '--username',
34
+ '--authentication': String,
35
+ '-a': '--authentication',
36
+ '--domain': String,
37
+ '-d': '--domain',
38
+ '--platform': String,
39
+ '-p': '--platform',
40
+ '--config': String,
41
+ '-c': '--config',
42
+ '--platforms-path': String,
43
+ '-pp': '--platforms-path',
44
+ '--deployments-path': String,
45
+ '-dp': '--deployments-path',
46
+ '--all': Boolean
47
+ }, { argv: options })
48
+
49
+ const username = parsedArgs['--username']
50
+ const authentication = parsedArgs['--authentication']
51
+ const platformsPath = parsedArgs['--platforms-path']
52
+ const deploymentsPath = parsedArgs['--deployments-path']
53
+
54
+ if (!username || !authentication) {
55
+ logError({
56
+ message: '[@ossy/cli] publish: --username (-u) and --authentication (-a) are required.'
57
+ })
58
+ process.exit(1)
59
+ }
60
+ if (!platformsPath || !deploymentsPath) {
61
+ logError({
62
+ message: '[@ossy/cli] publish: --platforms-path (-pp) and --deployments-path (-dp) are required.'
63
+ })
64
+ process.exit(1)
65
+ }
66
+
67
+ let configPath = parsedArgs['--config']
68
+ if (!configPath) {
69
+ const cwdConfig = pathResolve(process.cwd(), 'src/config.js')
70
+ if (existsSync(cwdConfig)) {
71
+ configPath = cwdConfig
72
+ }
73
+ } else if (!existsSync(pathResolve(configPath))) {
74
+ logError({ message: `[@ossy/cli] publish: --config file not found: ${configPath}` })
75
+ process.exit(1)
76
+ }
77
+
78
+ const fromConfig = configPath ? readWebsiteConfigDeployFields(configPath) : {}
79
+
80
+ if (parsedArgs['--all']) {
81
+ let targetPlatform = parsedArgs['--platform'] || fromConfig.platform
82
+ if (!targetPlatform) {
83
+ logError({
84
+ message: '[@ossy/cli] publish --all: pass --platform (-p) or set platform in src/config.js (or --config).'
85
+ })
86
+ process.exit(1)
87
+ }
88
+ logInfo({ message: `[@ossy/cli] publish --all: platform=${targetPlatform}` })
89
+ await runNpxDeploymentTools([
90
+ 'deploy-all',
91
+ '-u', username,
92
+ '-a', authentication,
93
+ '-p', targetPlatform,
94
+ '-pp', platformsPath,
95
+ '-dp', deploymentsPath
96
+ ])
97
+ return
98
+ }
99
+
100
+ let targetDomain = parsedArgs['--domain'] || fromConfig.domain
101
+ let targetPlatform = parsedArgs['--platform'] || fromConfig.platform
102
+
103
+ if (!targetPlatform && targetDomain && deploymentsPath) {
104
+ const resolved = resolvePlatformFromDeployments(deploymentsPath, targetDomain)
105
+ if (resolved && typeof resolved === 'object' && resolved.ambiguous) {
106
+ logError({
107
+ message: `[@ossy/cli] publish: domain "${targetDomain}" matches multiple platforms (${resolved.platforms.join(', ')}). Set platform in src/config.js or pass --platform (-p).`
108
+ })
109
+ process.exit(1)
110
+ }
111
+ targetPlatform = resolved
112
+ }
113
+
114
+ if (!targetDomain || !targetPlatform) {
115
+ logError({
116
+ message: '[@ossy/cli] publish: need --domain (-d) and --platform (-p), or src/config.js / --config with domain (and optional platform); platform can be inferred from deployments when domain is unique.'
117
+ })
118
+ process.exit(1)
119
+ }
120
+
121
+ logInfo({ message: `[@ossy/cli] publish: domain=${targetDomain} platform=${targetPlatform}` })
122
+
123
+ await runNpxDeploymentTools([
124
+ 'deploy',
125
+ '-u', username,
126
+ '-a', authentication,
127
+ '-d', targetDomain,
128
+ '-p', targetPlatform,
129
+ '-pp', platformsPath,
130
+ '-dp', deploymentsPath
131
+ ])
132
+ }
@@ -0,0 +1,44 @@
1
+ import { readFileSync } from 'fs'
2
+ import { resolve } from 'path'
3
+ import { globSync } from 'glob'
4
+
5
+ /**
6
+ * Reads string `domain` / `platform` from a site `src/config.js` without executing it
7
+ * (config is often ESM with package-only imports).
8
+ *
9
+ * @param {string} configPath
10
+ * @returns {{ domain?: string, platform?: string }}
11
+ */
12
+ export function readWebsiteConfigDeployFields (configPath) {
13
+ const abs = resolve(configPath)
14
+ const source = readFileSync(abs, 'utf8')
15
+
16
+ const pick = (key) => {
17
+ const m = source.match(new RegExp(`${key}\\s*:\\s*['"]([^'"]+)['"]`))
18
+ return m ? m[1] : undefined
19
+ }
20
+
21
+ const domain = pick('domain')
22
+ const platform = pick('platform') || pick('targetDeploymentPlatform')
23
+
24
+ return { domain, platform }
25
+ }
26
+
27
+ /**
28
+ * @param {string} deploymentsGlob
29
+ * @param {string} domain
30
+ * @returns {string | undefined | { ambiguous: true, platforms: string[] }}
31
+ */
32
+ export function resolvePlatformFromDeployments (deploymentsGlob, domain) {
33
+ const filePaths = globSync(deploymentsGlob, { ignore: 'node_modules/**' })
34
+ const deployments = filePaths.flatMap((p) => JSON.parse(readFileSync(p, 'utf8')))
35
+ const matches = deployments.filter((d) => d.domain === domain)
36
+ if (matches.length === 0) {
37
+ return undefined
38
+ }
39
+ const platforms = [...new Set(matches.map((d) => d.targetDeploymentPlatform))]
40
+ if (platforms.length > 1) {
41
+ return { ambiguous: true, platforms }
42
+ }
43
+ return platforms[0]
44
+ }