@ossy/cli 0.14.1 → 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 +21 -0
- package/package.json +5 -4
- package/src/index.js +6 -1
- package/src/publish/cli.js +132 -0
- package/src/publish/resolve-config.js +44 -0
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.
|
|
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.
|
|
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": "
|
|
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
|
+
}
|