@grrocloud/cli 0.0.0-stage → 1.0.1
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 +415 -2
- package/bin/grro.js +17 -0
- package/install.js +64 -0
- package/package.json +14 -4
package/README.md
CHANGED
|
@@ -1,3 +1,416 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Grro Cloud CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`grro` is the command line tool for [Grro Cloud](https://usegrro.com), the
|
|
4
|
+
African-first platform for running web apps, APIs, workers and databases.
|
|
5
|
+
Deploy and watch the build, follow logs, roll back, set environment
|
|
6
|
+
variables, scale, add domains and databases, take backups, schedule jobs and
|
|
7
|
+
invite your team, from your terminal or from CI.
|
|
8
|
+
|
|
9
|
+
```console
|
|
10
|
+
$ grro deploy
|
|
11
|
+
Deploying 3f9c2a1b...
|
|
12
|
+
#1 [internal] load build definition from Dockerfile
|
|
13
|
+
#6 [build 4/6] RUN npm ci
|
|
14
|
+
#9 [build 6/6] RUN npm run build
|
|
15
|
+
#12 exporting to image
|
|
16
|
+
▸ deploying
|
|
17
|
+
▸ running
|
|
18
|
+
Live at https://shop-438824.kigali.usegrro.app
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- [Install](#install)
|
|
22
|
+
- [Quick start](#quick-start)
|
|
23
|
+
- [Examples](#examples)
|
|
24
|
+
- [Deploy from CI](#deploy-from-ci)
|
|
25
|
+
- [Coming from Heroku](#coming-from-heroku)
|
|
26
|
+
- [Settings, JSON and exit codes](#settings-json-and-exit-codes)
|
|
27
|
+
- [Troubleshooting](#troubleshooting)
|
|
28
|
+
- [Help and links](#help-and-links)
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
Pick one. Every way installs the same program and checks it against its
|
|
33
|
+
published SHA-256 checksum.
|
|
34
|
+
|
|
35
|
+
| How | Command | Works on |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| Homebrew | `brew install grro-cloud/tap/grro` | macOS, Linux |
|
|
38
|
+
| npm | `npm install -g @grrocloud/cli` | macOS, Linux, Windows (Node 16 or newer) |
|
|
39
|
+
| Install script | `curl -fsSL https://usegrro.com/cli/install.sh \| sh` | macOS, Linux |
|
|
40
|
+
| PowerShell | `irm https://usegrro.com/cli/install.ps1 \| iex` | Windows |
|
|
41
|
+
|
|
42
|
+
Check it worked:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
$ grro version
|
|
46
|
+
grro v1.0.0 (darwin/arm64)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Run it once without installing** (handy in CI or to try it):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx @grrocloud/cli version
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Download it yourself**: get the file for your computer from the
|
|
56
|
+
[latest release](https://github.com/grro-cloud/cli/releases/latest), check it
|
|
57
|
+
against `SHA256SUMS`, make it runnable and put it on your PATH.
|
|
58
|
+
|
|
59
|
+
| File | Computer |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `grro-darwin-arm64` | Mac with an Apple chip (M1, M2, M3, M4) |
|
|
62
|
+
| `grro-darwin-amd64` | Mac with an Intel chip |
|
|
63
|
+
| `grro-linux-amd64` | Linux on most PCs and servers |
|
|
64
|
+
| `grro-linux-arm64` | Linux on ARM (Raspberry Pi, ARM servers) |
|
|
65
|
+
| `grro-windows-amd64.exe` | Windows |
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
shasum -a 256 -c SHA256SUMS --ignore-missing
|
|
69
|
+
chmod +x grro-darwin-arm64
|
|
70
|
+
sudo mv grro-darwin-arm64 /usr/local/bin/grro
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Updating
|
|
74
|
+
|
|
75
|
+
| Installed with | Update with |
|
|
76
|
+
|---|---|
|
|
77
|
+
| Homebrew | `brew upgrade grro` |
|
|
78
|
+
| npm | `npm install -g @grrocloud/cli@latest` |
|
|
79
|
+
| Install script, PowerShell or a download | `grro update` |
|
|
80
|
+
|
|
81
|
+
Not sure? Run `grro update`: it updates itself, or tells you which command to
|
|
82
|
+
use.
|
|
83
|
+
|
|
84
|
+
## Quick start
|
|
85
|
+
|
|
86
|
+
**1. Sign in.** Your browser opens. Check that the code matches the one in
|
|
87
|
+
your terminal and press **Allow**.
|
|
88
|
+
|
|
89
|
+
```console
|
|
90
|
+
$ grro login
|
|
91
|
+
Your sign-in code: WXKD-4QPT
|
|
92
|
+
|
|
93
|
+
Signed in as ada@example.com until 2026-12-12.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
On a server or over SSH, run `grro login --no-browser` and open the link it
|
|
97
|
+
prints on any device.
|
|
98
|
+
|
|
99
|
+
**2. Pick a project.** List your projects, then link one to this folder so
|
|
100
|
+
you don't have to name it in every command.
|
|
101
|
+
|
|
102
|
+
```console
|
|
103
|
+
$ grro projects
|
|
104
|
+
$ grro link shop
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Or create a new one and link it in one go:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
grro projects:create shop --region kigali --link
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**3. Deploy.** The build log streams to your terminal and the command waits
|
|
114
|
+
until the new version is live.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
grro deploy --source https://github.com/you/shop # the first deploy of a new project
|
|
118
|
+
grro deploy # every deploy after that
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**4. Look at it.**
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
grro open --url # the app in your browser
|
|
125
|
+
grro logs -f # its output, live (Ctrl+C to stop)
|
|
126
|
+
grro status # is it up? traffic, errors and tips
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Examples
|
|
130
|
+
|
|
131
|
+
Every project command uses the folder's linked project. Add `-p NAME` to use
|
|
132
|
+
another one: `grro logs -p api`.
|
|
133
|
+
|
|
134
|
+
### Deploy and watch the build
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
grro deploy # build the latest commit of the project's repository
|
|
138
|
+
grro deploy --ref v1.4.0 # a branch, tag or commit
|
|
139
|
+
grro deploy --source https://github.com/you/monorepo --subpath apps/web
|
|
140
|
+
grro deploy --image ghcr.io/you/api:1.5 # deploy a ready image, no build
|
|
141
|
+
grro deploy --detach # start it and return straight away
|
|
142
|
+
grro redeploy # build the current source again
|
|
143
|
+
grro deploys # recent deployments and their status
|
|
144
|
+
grro deploys:info # the latest one in detail
|
|
145
|
+
grro deploys:cancel # stop a build that's still running
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Logs
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
grro logs # the app's latest lines
|
|
152
|
+
grro logs -f # keep following new lines
|
|
153
|
+
grro logs -n 500 # the last 500 lines
|
|
154
|
+
grro logs --build # the build log of the latest deployment
|
|
155
|
+
grro logs --build --deploy 3f9c2a1b
|
|
156
|
+
grro logs -f | grep --line-buffered "POST /checkout"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Environment variables
|
|
160
|
+
|
|
161
|
+
New variables are secret (nobody can read them back) unless you add
|
|
162
|
+
`--plain`. Setting a variable redeploys the app so it gets the new value.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
grro config # list them
|
|
166
|
+
grro config:set STRIPE_KEY=sk_live_... MAIL_FROM=hi@shop.com
|
|
167
|
+
grro config:set LOG_LEVEL=debug --plain # readable
|
|
168
|
+
grro config:set GREETING="Hello Kigali" --no-redeploy
|
|
169
|
+
grro config:get LOG_LEVEL # print a plain value
|
|
170
|
+
grro config:import .env.production # every line of a .env file
|
|
171
|
+
grro config:unset LOG_LEVEL
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Roll back
|
|
175
|
+
|
|
176
|
+
No build, so it takes seconds.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
grro rollback # back to the previous deployment that ran
|
|
180
|
+
grro rollback 3f9c2a1b # back to a specific one (from grro deploys)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Scale and settings
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
grro scale # how many instances run now
|
|
187
|
+
grro scale min=1 # always on
|
|
188
|
+
grro scale min=0 # sleep when nobody uses it, wake on the next request
|
|
189
|
+
grro scale min=1 max=5 # grow to 5 under load
|
|
190
|
+
grro settings:set health=/healthz
|
|
191
|
+
grro settings:set protocol=h2c # gRPC and HTTP/2 apps
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Custom domains
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
grro domains:add shop.com # prints the DNS records to create
|
|
198
|
+
grro domains:add www.shop.com
|
|
199
|
+
grro domains:check shop.com # check DNS and HTTPS now
|
|
200
|
+
grro domains:primary shop.com # the others redirect to it
|
|
201
|
+
grro domains:www shop.com on # www.shop.com redirects to shop.com
|
|
202
|
+
grro domains
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
HTTPS certificates are set up automatically once the DNS records are in place.
|
|
206
|
+
|
|
207
|
+
### Databases and backups
|
|
208
|
+
|
|
209
|
+
Postgres, MySQL, Redis and MongoDB. A new database is attached to your app as
|
|
210
|
+
`DATABASE_URL` (or `REDIS_URL`, `MONGODB_URL`) and backed up daily.
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
grro db:plans # sizes and prices
|
|
214
|
+
grro db:create main --engine postgres
|
|
215
|
+
grro db:create cache --engine redis --as REDIS_URL
|
|
216
|
+
grro db # the project's databases
|
|
217
|
+
grro db:info main
|
|
218
|
+
grro db:backup main # back it up now
|
|
219
|
+
grro db:backups main
|
|
220
|
+
grro db:restore 7b1e... --new main-restored # safe: restores into a new database
|
|
221
|
+
grro db:rotate main # new password, the app is updated
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Scheduled jobs
|
|
225
|
+
|
|
226
|
+
A job runs a command in a copy of your app, with the same image and
|
|
227
|
+
variables.
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
grro cron:create cleanup --schedule "0 2 * * *" --command "npm run cleanup"
|
|
231
|
+
grro cron:create report --schedule "0 8 * * 1" --command "python report.py" --tz Africa/Lagos
|
|
232
|
+
grro cron # list jobs
|
|
233
|
+
grro cron:run cleanup # run it now
|
|
234
|
+
grro cron:runs cleanup # recent runs and their output
|
|
235
|
+
grro cron:pause cleanup
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Your team
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
grro members:add ada@example.com --role developer # deploy, roll back, logs, variables
|
|
242
|
+
grro members:add sam@example.com --role viewer # deployments and logs
|
|
243
|
+
grro members:add owner@client.com --role client --weekly-report
|
|
244
|
+
grro members
|
|
245
|
+
grro teams
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Templates
|
|
249
|
+
|
|
250
|
+
Start WordPress, Next.js, an AI chat app and many more in one command.
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
grro templates # browse them
|
|
254
|
+
grro templates:info wordpress # what it asks for
|
|
255
|
+
grro templates:deploy wordpress --name blog --region kigali --link
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Billing
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
grro billing # plan, this month's usage and credit
|
|
262
|
+
grro billing:invoices
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
See every command with `grro commands`, and any command's flags and examples
|
|
266
|
+
with `grro help <command>`.
|
|
267
|
+
|
|
268
|
+
## Deploy from CI
|
|
269
|
+
|
|
270
|
+
In the dashboard, create an **API token** for the project. In your
|
|
271
|
+
repository's settings, save it as the secret `GRRO_TOKEN`, and save the
|
|
272
|
+
project's name as `GRRO_PROJECT`.
|
|
273
|
+
|
|
274
|
+
**GitHub Actions**
|
|
275
|
+
|
|
276
|
+
```yaml
|
|
277
|
+
# .github/workflows/deploy.yml
|
|
278
|
+
name: Deploy
|
|
279
|
+
on:
|
|
280
|
+
push:
|
|
281
|
+
branches: [main]
|
|
282
|
+
|
|
283
|
+
jobs:
|
|
284
|
+
deploy:
|
|
285
|
+
runs-on: ubuntu-latest
|
|
286
|
+
steps:
|
|
287
|
+
- uses: actions/checkout@v4
|
|
288
|
+
- run: npm ci && npm test
|
|
289
|
+
- run: npx @grrocloud/cli deploy --ref "$GITHUB_SHA"
|
|
290
|
+
env:
|
|
291
|
+
GRRO_TOKEN: ${{ secrets.GRRO_TOKEN }}
|
|
292
|
+
GRRO_PROJECT: ${{ secrets.GRRO_PROJECT }}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**GitLab CI**
|
|
296
|
+
|
|
297
|
+
```yaml
|
|
298
|
+
# .gitlab-ci.yml (set GRRO_TOKEN and GRRO_PROJECT as masked CI variables)
|
|
299
|
+
deploy:
|
|
300
|
+
stage: deploy
|
|
301
|
+
image: alpine:3.20
|
|
302
|
+
script:
|
|
303
|
+
- apk add --no-cache curl
|
|
304
|
+
- curl -fsSL https://usegrro.com/cli/install.sh | sh
|
|
305
|
+
- grro deploy --ref "$CI_COMMIT_SHA"
|
|
306
|
+
only: [main]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`grro deploy` waits until the deployment is live and fails the step when the
|
|
310
|
+
deployment fails, with the build log in the job output. A project token can
|
|
311
|
+
deploy and read its one project only.
|
|
312
|
+
|
|
313
|
+
If you deploy from CI, turn off push-to-deploy for that project in the
|
|
314
|
+
dashboard so each commit isn't deployed twice.
|
|
315
|
+
|
|
316
|
+
## Coming from Heroku
|
|
317
|
+
|
|
318
|
+
Most Heroku commands work as they are. `-a NAME` works like `-p NAME`.
|
|
319
|
+
|
|
320
|
+
| Heroku | grro |
|
|
321
|
+
|---|---|
|
|
322
|
+
| `heroku apps` | `grro projects` (or `grro apps`) |
|
|
323
|
+
| `heroku create web` | `grro projects:create web` (or `grro create web`) |
|
|
324
|
+
| `heroku apps:info` | `grro projects:info` (or `grro info`) |
|
|
325
|
+
| `heroku config:set KEY=value` | `grro config:set KEY=value` |
|
|
326
|
+
| `heroku config:unset KEY` | `grro config:unset KEY` |
|
|
327
|
+
| `heroku releases` | `grro deploys` (or `grro releases`) |
|
|
328
|
+
| `heroku rollback` | `grro rollback` |
|
|
329
|
+
| `heroku logs --tail` | `grro logs --tail` (or `-f`) |
|
|
330
|
+
| `heroku ps:scale web=2` | `grro scale min=2` (or `grro ps:scale min=2`) |
|
|
331
|
+
| `heroku addons:create heroku-postgresql` | `grro db:create main --engine postgres` (or `addons:create`) |
|
|
332
|
+
| `heroku pg:backups:capture` | `grro db:backup main` |
|
|
333
|
+
| `heroku access:add ada@example.com` | `grro members:add ada@example.com` (or `access:add`) |
|
|
334
|
+
| `heroku domains:add www.shop.com` | `grro domains:add www.shop.com` |
|
|
335
|
+
|
|
336
|
+
## Settings, JSON and exit codes
|
|
337
|
+
|
|
338
|
+
**Environment variables grro reads**
|
|
339
|
+
|
|
340
|
+
| Variable | What it does |
|
|
341
|
+
|---|---|
|
|
342
|
+
| `GRRO_TOKEN` | Use this token instead of the saved sign-in (CI) |
|
|
343
|
+
| `GRRO_PROJECT` | The project, when the folder isn't linked and there's no `-p` |
|
|
344
|
+
| `GRRO_CONFIG_DIR` | Keep the sign-in and settings in this folder |
|
|
345
|
+
| `GRRO_API` | API address (default `https://api.usegrro.com`) |
|
|
346
|
+
|
|
347
|
+
**JSON for scripts**: add `--json` to any command.
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
grro deploys --json | jq -r '.[0].status'
|
|
351
|
+
grro projects --json | jq -r '.[].name'
|
|
352
|
+
id=$(grro deploy --detach --json | jq -r .id)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Commands that delete something** ask you to type its name. In a script,
|
|
356
|
+
pass it with `--confirm`:
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
grro db:delete old-db --confirm old-db
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Exit codes**
|
|
363
|
+
|
|
364
|
+
| Code | Means |
|
|
365
|
+
|---|---|
|
|
366
|
+
| `0` | It worked |
|
|
367
|
+
| `1` | It failed; the message says why |
|
|
368
|
+
| `3` | Not signed in, or the sign-in or token expired: run `grro login` |
|
|
369
|
+
| `130` | You pressed Ctrl+C |
|
|
370
|
+
|
|
371
|
+
## Troubleshooting
|
|
372
|
+
|
|
373
|
+
**"you're not signed in"**, or exit code 3: run `grro login`.
|
|
374
|
+
A browser sign-in lasts 30 days. In CI, check that `GRRO_TOKEN` is set and
|
|
375
|
+
the token hasn't been revoked.
|
|
376
|
+
|
|
377
|
+
**"which project?"**: run `grro link NAME` in your app's folder, or add
|
|
378
|
+
`-p NAME` to the command. **"no project called ..."**: check the name with
|
|
379
|
+
`grro projects`.
|
|
380
|
+
|
|
381
|
+
**The deploy failed**: read the build log with `grro logs --build`. The last
|
|
382
|
+
lines usually say what went wrong (a missing file, a failing test, a wrong
|
|
383
|
+
start command). Fix it, push, and run `grro deploy` again. Your previous
|
|
384
|
+
version keeps serving traffic until a new one is live.
|
|
385
|
+
|
|
386
|
+
**The app deployed but doesn't answer**: run `grro logs` for its output and
|
|
387
|
+
`grro status` for health checks. Make sure the app listens on the `PORT`
|
|
388
|
+
environment variable, and that the health path (`grro settings`) answers 200.
|
|
389
|
+
|
|
390
|
+
**Typed a command wrong?** grro suggests the closest one:
|
|
391
|
+
|
|
392
|
+
```console
|
|
393
|
+
$ grro deplyo
|
|
394
|
+
▸ "deplyo" isn't a grro command. Did you mean deploy?
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**npm install fails with EACCES (permission denied)**: your npm global
|
|
398
|
+
folder needs administrator rights. Install with Homebrew or the install
|
|
399
|
+
script instead, or
|
|
400
|
+
[set npm up to install global packages without sudo](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally).
|
|
401
|
+
|
|
402
|
+
**npm install can't download the program** (behind a proxy or offline): use
|
|
403
|
+
the install script, or download the file from the
|
|
404
|
+
[latest release](https://github.com/grro-cloud/cli/releases/latest) yourself.
|
|
405
|
+
|
|
406
|
+
## Help and links
|
|
407
|
+
|
|
408
|
+
- `grro help`: topics and where to start
|
|
409
|
+
- `grro help deploy`: one topic or command, with examples
|
|
410
|
+
- `grro commands`: every command
|
|
411
|
+
- Full guide: [usegrro.com/docs/cli](https://usegrro.com/docs/cli)
|
|
412
|
+
- Command reference: [usegrro.com/docs/cli-reference](https://usegrro.com/docs/cli-reference)
|
|
413
|
+
- Releases and downloads: [github.com/grro-cloud/cli/releases](https://github.com/grro-cloud/cli/releases)
|
|
414
|
+
- Support: [support@usegrro.com](mailto:support@usegrro.com)
|
|
415
|
+
|
|
416
|
+
MIT License. Copyright Grro Cloud.
|
package/bin/grro.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Runs the grro program that install.js downloaded.
|
|
3
|
+
"use strict";
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const { spawnSync } = require("child_process");
|
|
7
|
+
const bin = path.join(__dirname, "..", "vendor", process.platform === "win32" ? "grro.exe" : "grro");
|
|
8
|
+
if (!fs.existsSync(bin)) {
|
|
9
|
+
console.error("grro: the program is missing. Reinstall it: npm install -g @grrocloud/cli");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const r = spawnSync(bin, process.argv.slice(2), { stdio: "inherit", env: { ...process.env, GRRO_INSTALLED_BY: "npm" } });
|
|
13
|
+
if (r.error) {
|
|
14
|
+
console.error(`grro: ${r.error.message}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
process.exit(r.status === null ? 1 : r.status);
|
package/install.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Downloads the grro program for this computer from the GitHub release when
|
|
3
|
+
// the npm package is installed, checks it against the published SHA-256
|
|
4
|
+
// checksum and keeps it in vendor/. Set GRRO_CLI_BASE to download from
|
|
5
|
+
// somewhere else.
|
|
6
|
+
//
|
|
7
|
+
// package.json "grroVersion" says which release to download. It is normally
|
|
8
|
+
// the same as "version", but can stay behind it: a package published only to
|
|
9
|
+
// update this README (1.0.1, say) still downloads the v1.0.0 program.
|
|
10
|
+
"use strict";
|
|
11
|
+
const fs = require("fs");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
const https = require("https");
|
|
14
|
+
const http = require("http");
|
|
15
|
+
const crypto = require("crypto");
|
|
16
|
+
|
|
17
|
+
const pkg = require("./package.json");
|
|
18
|
+
const version = pkg.grroVersion || pkg.version;
|
|
19
|
+
const base = (process.env.GRRO_CLI_BASE || "https://github.com/grro-cloud/cli/releases/download").replace(/\/$/, "");
|
|
20
|
+
const os = { darwin: "darwin", linux: "linux", win32: "windows" }[process.platform];
|
|
21
|
+
const arch = { x64: "amd64", arm64: "arm64" }[process.arch];
|
|
22
|
+
if (!os || !arch || (os === "windows" && arch === "arm64")) {
|
|
23
|
+
console.error(`grro: there is no build for ${process.platform}/${process.arch} yet.`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const file = `grro-${os}-${arch}${os === "windows" ? ".exe" : ""}`;
|
|
27
|
+
const dir = path.join(__dirname, "vendor");
|
|
28
|
+
const dest = path.join(dir, os === "windows" ? "grro.exe" : "grro");
|
|
29
|
+
|
|
30
|
+
function get(url, redirects = 5) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
(url.startsWith("http:") ? http : https)
|
|
33
|
+
.get(url, { headers: { "User-Agent": `grro-npm/${version}` } }, (res) => {
|
|
34
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location && redirects > 0) {
|
|
35
|
+
res.resume();
|
|
36
|
+
return resolve(get(new URL(res.headers.location, url).toString(), redirects - 1));
|
|
37
|
+
}
|
|
38
|
+
if (res.statusCode !== 200) {
|
|
39
|
+
res.resume();
|
|
40
|
+
return reject(new Error(`${url} answered ${res.statusCode}`));
|
|
41
|
+
}
|
|
42
|
+
const chunks = [];
|
|
43
|
+
res.on("data", (c) => chunks.push(c));
|
|
44
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
45
|
+
})
|
|
46
|
+
.on("error", reject);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
(async () => {
|
|
51
|
+
const root = `${base}/v${version}`;
|
|
52
|
+
const sums = (await get(`${root}/SHA256SUMS`)).toString("utf8");
|
|
53
|
+
const want = sums.split("\n").map((l) => l.trim().split(/\s+/)).find((p) => p[1] === file)?.[0];
|
|
54
|
+
if (!want) throw new Error(`no checksum for ${file} in ${root}/SHA256SUMS`);
|
|
55
|
+
const bin = await get(`${root}/${file}`);
|
|
56
|
+
const got = crypto.createHash("sha256").update(bin).digest("hex");
|
|
57
|
+
if (got !== want) throw new Error("the download doesn't match its checksum, so it was not installed");
|
|
58
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
59
|
+
fs.writeFileSync(dest, bin, { mode: 0o755 });
|
|
60
|
+
console.log(`grro ${version} installed. Run: grro login`);
|
|
61
|
+
})().catch((e) => {
|
|
62
|
+
console.error(`grro: ${e.message}. Try again, or install with: curl -fsSL https://github.com/grro-cloud/cli/releases/latest/download/install.sh | sh`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grrocloud/cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"grroVersion": "1.0.0",
|
|
5
|
+
"description": "The Grro Cloud command line tool: deploy, logs, variables, domains, databases and more from your terminal.",
|
|
6
|
+
"homepage": "https://usegrro.com/docs/cli",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"bin": { "grro": "bin/grro.js" },
|
|
9
|
+
"scripts": { "postinstall": "node install.js" },
|
|
10
|
+
"files": ["bin/grro.js", "install.js", "README.md"],
|
|
11
|
+
"os": ["darwin", "linux", "win32"],
|
|
12
|
+
"cpu": ["x64", "arm64"],
|
|
13
|
+
"engines": { "node": ">=16" },
|
|
14
|
+
"publishConfig": { "access": "public" },
|
|
15
|
+
"keywords": ["grro", "grro cloud", "paas", "deploy", "cli", "heroku"]
|
|
16
|
+
}
|