@autofleet/cli 2.23.0 → 2.24.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.
@@ -0,0 +1,189 @@
1
+ # Dev Workflow Examples
2
+
3
+ ## Development Workflow Commands
4
+
5
+ ### Option A — Run service locally, wire to simulation
6
+
7
+ ```bash
8
+ # 1. Forward the simulation DB to localhost
9
+ autofleet forwardDb -q --cluster=expManager --variationId=<uuid>
10
+ # Opens Postico. Also prints DB_USERNAME, DB_PASSWORD, DB_NAME env vars for .env
11
+
12
+ # 2. Run service locally (uses local .env pointing at sim DB)
13
+ npm run dev
14
+
15
+ # 3. Intercept live simulation traffic locally via mirrord
16
+ autofleet mirrord -q --service=<service-name> --cluster=expManager --variationId=<uuid>
17
+ ```
18
+
19
+ ### Option B — Deploy service to simulation, run control-center locally
20
+
21
+ ```bash
22
+ # 1. Build and push Docker image, update K8s deployment in simulation
23
+ # Run from the service repo root
24
+ autofleet updateExp -q --cluster=expManager --variationId=<uuid>
25
+ # This: builds image tagged gcr.io/autofleetprod/<dir>:<branch>-<HH-MM-SS>
26
+ # pushes to GCP registry
27
+ # patches K8s deployment and waits for rollout
28
+
29
+ # 2. Set up control-center to point at the simulation API gateway
30
+ # Run from control-center repo root
31
+ autofleet localDev -q --cluster=expManager --variationId=<uuid>
32
+ # Updates .env with API_GATEWAY_MS_SERVICE_HOST
33
+ # Port-forwards control-center-ms to port 8085
34
+ #
35
+ # If localDev fails (e.g. no ingress), set .env manually:
36
+ # API_GATEWAY_MS_SERVICE_HOST=<api-gateway-loadbalancer-ip>
37
+ # CONTROL_CENTER_MS_SERVICE_HOST=<control-center-loadbalancer-ip>
38
+ # The simulation control-center IP can be used directly for CONTROL_CENTER_MS
39
+ # since Vite proxies to it. Get IPs with:
40
+ # kubectl get svc --namespace=<variationId> | grep LoadBalancer
41
+ #
42
+ # IMPORTANT: IP/host env vars must NOT include the http:// protocol prefix.
43
+ # The Vite proxy config (vite/devServerProxy.ts) adds http:// automatically.
44
+ # Setting API_GATEWAY_MS_SERVICE_HOST=http://1.2.3.4 causes double-prefix errors.
45
+
46
+ # 3. Start control-center dev server
47
+ npm run dev
48
+ ```
49
+
50
+ ### Useful cluster operations
51
+
52
+ ```bash
53
+ # Switch kubectl context to a cluster/namespace
54
+ autofleet switchCluster -q --cluster=expManager --variationId=<uuid>
55
+
56
+ # Forward a specific microservice port locally
57
+ autofleet forwardService -q --service=<service-name> --cluster=expManager --variationId=<uuid> --port=8080
58
+
59
+ # Get all microservice IPs in an environment
60
+ autofleet getIps -q --cluster=expManager --variationId=<uuid>
61
+
62
+ # Start local Docker infrastructure (Redis, RabbitMQ, Postgres)
63
+ autofleet dockerInit -q
64
+ ```
65
+
66
+ ## Debugging
67
+
68
+ ### Replaying a request with curl
69
+
70
+ Copy the `Authorization` header from DevTools → Network → Headers, then:
71
+
72
+ ```bash
73
+ curl -s -H "Authorization: Bearer <token>" "http://<api-gateway-ip>/api/v1/..."
74
+ ```
75
+
76
+ ### Intercepting the auth token via browser console
77
+
78
+ ```javascript
79
+ const origSet = XMLHttpRequest.prototype.setRequestHeader;
80
+ XMLHttpRequest.prototype.setRequestHeader = function(name, val) {
81
+ if (name === 'Authorization') window._token = val;
82
+ return origSet.call(this, name, val);
83
+ };
84
+ // trigger any API action, then: window._token
85
+ ```
86
+
87
+ ### Querying GCP logs
88
+
89
+ > **Note:** GCP logs may have a delay of up to a few minutes. If a query returns no results immediately, wait and retry.
90
+
91
+ ```bash
92
+ # Logs for a specific service in a simulation namespace
93
+ gcloud logging read \
94
+ "resource.type=k8s_container \
95
+ AND resource.labels.namespace_name=<variationId> \
96
+ AND resource.labels.container_name=<service-name>" \
97
+ --project=af-experiment-manager \
98
+ --limit=100 \
99
+ --format=json \
100
+ | jq '.[].jsonPayload'
101
+
102
+ # Filter by trace ID
103
+ gcloud logging read \
104
+ "resource.type=k8s_container \
105
+ AND resource.labels.namespace_name=<variationId> \
106
+ AND jsonPayload.traceId=\"<x-trace-id>\"" \
107
+ --project=af-experiment-manager \
108
+ --limit=50 \
109
+ --format=json
110
+ ```
111
+
112
+ ### Mirrord
113
+
114
+ ```bash
115
+ # Intercept live traffic from simulation
116
+ autofleet mirrord -q --service=<service-name> --cluster=dev1 --variationId=<uuid>
117
+
118
+ # Generate mirrord config manually (creates .mirrord/mirrord.json)
119
+ autofleet mirrordConfig -q --service=<service-name> --cluster=dev1 --variationId=<uuid>
120
+ ```
121
+
122
+ ### DB access
123
+
124
+ ```bash
125
+ # Port-forward PostgreSQL to localhost:5432
126
+ autofleet forwardDb -q --cluster=dev1 --variationId=<uuid>
127
+ # Credentials: postgres / afpass_<variationId>
128
+ # DB name: <service>_<variationId> (hyphens → underscores)
129
+ # Also auto-opens Postico
130
+ ```
131
+
132
+ ## NPM Token Setup
133
+
134
+ ```bash
135
+ # Check if already set
136
+ cat ~/.npmrc # look for _authToken=...
137
+ echo $NPM_TOKEN # check if already exported
138
+
139
+ # Export it
140
+ export NPM_TOKEN=<token>
141
+ ```
142
+
143
+ ## Common Patterns
144
+
145
+ ### Typical simulation cycle
146
+
147
+ ```bash
148
+ autofleet switchCluster -q --cluster=expManager --variationId=<sim-id>
149
+ autofleet forwardDb -q --cluster=expManager --variationId=<sim-id> # if DB access needed
150
+ autofleet mirrord -q --service=<svc> --cluster=expManager --variationId=<sim-id> # OR
151
+ autofleet updateExp -q --cluster=expManager --variationId=<sim-id> # full deploy
152
+ autofleet localDev -q --cluster=expManager --variationId=<sim-id> # if running CC locally
153
+ ```
154
+
155
+ ### Staging deployment
156
+
157
+ ```bash
158
+ # Same as simulation but with --cluster=staging (no --variationId needed)
159
+ autofleet updateExp -q --cluster=staging
160
+ ```
161
+
162
+ ## End-of-Session Testing Options
163
+
164
+ ### Option A — Deploy backend to simulation, run CC locally
165
+ ```bash
166
+ autofleet updateExp -q --cluster=expManager --variationId=<id> # from each modified service repo
167
+ autofleet localDev -q --cluster=expManager --variationId=<id> # from control-center repo
168
+ npm run dev # in control-center
169
+ ```
170
+
171
+ ### Option B — Run everything locally, wire to simulation DB/infra
172
+ ```bash
173
+ autofleet forwardDb -q --cluster=expManager --variationId=<id> # for each service needing DB
174
+ autofleet mirrord -q --service=<svc> --cluster=expManager --variationId=<id> # to intercept traffic
175
+ npm run dev # in each service + control-center
176
+ ```
177
+
178
+ ### Option C — CC locally, backend in simulation
179
+ ```bash
180
+ autofleet updateExp -q --cluster=expManager --variationId=<id> # if backend changes need deploying
181
+ autofleet localDev -q --cluster=expManager --variationId=<id> # from control-center repo
182
+ npm run dev # in control-center
183
+ ```
184
+
185
+ ### Option D — Deploy everything to simulation
186
+ ```bash
187
+ autofleet updateExp -q --cluster=expManager --variationId=<id> # for each changed service
188
+ # Then open the simulation control-center URL directly
189
+ ```
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: node-test-runner
3
+ description: Use this skill when the user wants to run tests on a Node.js microservice in Autofleet locally, including setting up Docker dependencies, initializing the test database, and running jest with the correct env vars.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Running Tests on Autofleet Node.js Services
8
+
9
+ ## Prerequisites
10
+
11
+ Local tests require Docker running with Postgres, Redis, and RabbitMQ. Use the `autofleet` CLI to spin them up:
12
+
13
+ ```sh
14
+ autofleet dockerInit -q
15
+ ```
16
+
17
+ This runs a `docker-compose up -d` with Postgres (port 5432), Redis (6379), RabbitMQ (5672), and Elasticsearch (9200).
18
+
19
+ **Known issue:** If Redis port 6379 is already allocated, the command fails but Postgres and RabbitMQ may still have started. Check with `docker ps` — if `t-postgres-1` is running, you can proceed.
20
+
21
+ Default Docker Postgres credentials:
22
+ - user: `postgres`
23
+ - password: `postgres`
24
+ - host: `127.0.0.1:5432`
25
+
26
+ ---
27
+
28
+ ## Initialize the Test Database
29
+
30
+ Services use `NODE_ENV=test` to connect to a separate test DB (e.g. `automation_ms_test`). Run this once (or after schema changes):
31
+
32
+ ```sh
33
+ DB_USERNAME=postgres DB_PASSWORD=postgres NODE_ENV=test npm run init
34
+ ```
35
+
36
+ This creates the DB and runs all Sequelize migrations against it.
37
+
38
+ > Also run without `NODE_ENV=test` if you need the development DB:
39
+ > ```sh
40
+ > DB_USERNAME=postgres DB_PASSWORD=postgres npm run init
41
+ > ```
42
+
43
+ ---
44
+
45
+ ## Running Tests
46
+
47
+ ```sh
48
+ DB_USERNAME=postgres DB_PASSWORD=postgres NODE_ENV=test node_modules/.bin/jest --forceExit
49
+ ```
50
+
51
+ To run a specific file:
52
+ ```sh
53
+ DB_USERNAME=postgres DB_PASSWORD=postgres NODE_ENV=test node_modules/.bin/jest src/path/to/file.test.ts --forceExit
54
+ ```
55
+
56
+ To filter by test name:
57
+ ```sh
58
+ DB_USERNAME=postgres DB_PASSWORD=postgres NODE_ENV=test node_modules/.bin/jest src/path/to/file.test.ts --testNamePattern="my test name" --forceExit
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Required Env Vars Summary
64
+
65
+ | Var | Value |
66
+ |-----|-------|
67
+ | `DB_USERNAME` | `postgres` |
68
+ | `DB_PASSWORD` | `postgres` |
69
+ | `NODE_ENV` | `test` |
70
+
71
+ All other DB config (host, port, DB name) falls back to defaults in `src/config/config.js`.
@@ -55,6 +55,7 @@ If the branch name contains no Jira ticket, omit this section entirely.
55
55
 
56
56
  ## Pre-PR Checklist
57
57
 
58
+ - Ask the user if they'd like to run `npm audit fix` on affected services — it fixes known dependency vulnerabilities and is better to catch before QA or code review flags them
58
59
  - Run linter (if configured)
59
60
  - Review your own changes first
60
61
  - Ensure tests pass (if running tests)
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: rabbit
3
+ description: Guides usage of the @autofleet/rabbit package — publishing to exchanges,
4
+ consuming from queues, consuming from exchanges (fanout), ConsumeOptions, error
5
+ handling with ack/nack, retries, dead-letter queues, and mocking in tests. Use
6
+ when the user wants to send or receive RabbitMQ messages, wire up a consumer,
7
+ understand retry/dead-letter behaviour, or mock rabbit in unit tests.
8
+ version: 1.0.0
9
+ userInvocable: true
10
+ ---
11
+
12
+ # @autofleet/rabbit
13
+
14
+ ## Setup
15
+
16
+ **Required env var:** `RABBITMQ_SERVICE_HOST` — set to `<host>:<port>` (e.g. `localhost:5672`).
17
+
18
+ ```typescript
19
+ import RabbitMq from '@autofleet/rabbit';
20
+
21
+ const rabbit = new RabbitMq();
22
+ // Optional: pass a logger
23
+ const rabbit = new RabbitMq({ logger });
24
+ ```
25
+
26
+ The constructor registers `SIGTERM`/`SIGINT` handlers for graceful shutdown automatically. Pass `{ dontGracefulShutdown: true }` to manage shutdown yourself.
27
+
28
+ ---
29
+
30
+ ## Publishing
31
+
32
+ ### Publish to an exchange (fanout)
33
+
34
+ ```typescript
35
+ await rabbit.publish('my-exchange', { vehicleId: 123, status: 'active' });
36
+ ```
37
+
38
+ ### Send directly to a queue
39
+
40
+ ```typescript
41
+ await rabbit.sendToQueue('my-queue', { orderId: 456 });
42
+ ```
43
+
44
+ Content is automatically JSON-serialized. Tracing headers (`x-trace-id`, `x-af-user-id`) are attached automatically from the current `@autofleet/zehut` context.
45
+
46
+ **Keep messages lean.** Publish only the minimum identifiers needed (e.g. `{ vehicleId, eventType }`) — not full entity objects. Consumers should fetch the full data themselves if needed. Large payloads increase broker memory pressure, slow down consumers, and make retries more expensive.
47
+
48
+ ---
49
+
50
+ ## Consuming
51
+
52
+ ### Consume from a queue
53
+
54
+ ```typescript
55
+ await rabbit.consume('my-queue', async (msg, ack, nack) => {
56
+ const payload = msg.content; // already parsed from JSON
57
+ try {
58
+ await processMessage(payload);
59
+ await ack();
60
+ } catch (err) {
61
+ await nack(msg); // retries up to options.retries times, then dead-letters
62
+ }
63
+ });
64
+ ```
65
+
66
+ ### Consume from an exchange (fanout)
67
+
68
+ Each consumer gets its own queue bound to the exchange:
69
+
70
+ ```typescript
71
+ await rabbit.consumeFromExchange('my-queue', 'my-exchange', async (msg, ack, nack) => {
72
+ await processMessage(msg.content);
73
+ await ack();
74
+ });
75
+ ```
76
+
77
+ ### ConsumeOptions
78
+
79
+ | Option | Default | Description |
80
+ |--------|---------|-------------|
81
+ | `retries` | `1` | Max retry attempts before dead-lettering |
82
+ | `limit` | `1` | Prefetch (concurrent messages in flight) |
83
+ | `deadMessageTtl` | 12 hours | How long dead messages are kept (ms) |
84
+ | `messageTtl` | — | Max age of a message before discard (ms) |
85
+ | `lockTimeout` | `5000` | Redis lock duration (ms), when using lock |
86
+ | `useConsumeWithLock` | `false` | Use Redis-based distributed lock per message |
87
+ | `enableRabbitTrace` | `false` | Log full rabbit trace headers |
88
+
89
+ ```typescript
90
+ await rabbit.consume('my-queue', handler, {
91
+ retries: 3,
92
+ limit: 5,
93
+ deadMessageTtl: 1000 * 60 * 60 * 24, // 24 hours
94
+ });
95
+ ```
96
+
97
+ ---
98
+
99
+ ## ack / nack
100
+
101
+ - `await ack()` — acknowledge; message is removed from the queue
102
+ - `await nack(msg)` — negative-acknowledge; retried up to `retries` times, then moved to the dead-letter queue
103
+ - `await nack(msg, { skipRetry: true })` — dead-letter immediately without retrying
104
+
105
+ ---
106
+
107
+ ## Dead-letter queues
108
+
109
+ On first consume, the package auto-creates a dead-letter queue named `<queue>-dead`. Messages land there after exhausting retries. `deadMessageTtl` controls TTL (default 12 hours).
110
+
111
+ ---
112
+
113
+ ## Mocking in tests
114
+
115
+ Import the Vitest mock class — it implements `IAfRabbitMq` with `vi.fn()` stubs for all methods:
116
+
117
+ ```typescript
118
+ import RabbitMqMock from '@autofleet/rabbit/mock/vitest';
119
+
120
+ const rabbit = new RabbitMqMock();
121
+ // rabbit.publish, rabbit.consume, rabbit.sendToQueue, etc. are vi.fn()
122
+ ```
123
+
124
+ See **examples.md → Testing** for full Vitest patterns.
125
+
126
+ ---
127
+
128
+ ## Common Issues
129
+
130
+ ### Messages not consumed after deploy
131
+ The queue or exchange may not be asserted yet — `consume`/`consumeFromExchange` assert on first call. Ensure the consumer starts before publishing.
132
+
133
+ ### `nack` loop causing infinite retries
134
+ Check `retries` in `ConsumeOptions`. Default is 1. After `retries` exhausted, messages go to the dead-letter queue — not requeued forever.
135
+
136
+ ### Message content is a Buffer instead of object
137
+ `msg.content` is pre-parsed by the package. If you see a Buffer, you're accessing the raw `amqplib` message — use `msg.content` from the `Message` type, not the underlying amqp object.
138
+
139
+ ### `RABBITMQ_SERVICE_HOST` not set
140
+ Connection silently falls back to `localhost:5672`. Always verify the env var is set in `.env` / Kubernetes config.
@@ -0,0 +1,109 @@
1
+ # Rabbit Examples
2
+
3
+ ## Basic Setup
4
+
5
+ ```typescript
6
+ import RabbitMq from '@autofleet/rabbit';
7
+ import { logger } from '@autofleet/logger';
8
+
9
+ const rabbit = new RabbitMq({ logger });
10
+ ```
11
+
12
+ ## Publish to Exchange
13
+
14
+ Publish only the minimum identifiers — consumers fetch full data themselves.
15
+
16
+ ```typescript
17
+ // Good — lean payload
18
+ await rabbit.publish('vehicle-events', { vehicleId: 123, event: 'location-updated' });
19
+
20
+ // Avoid — full entity bloats the broker
21
+ await rabbit.publish('vehicle-events', { vehicleId: 123, lat: 32.1, lng: 34.9, status: 'active', ...allOtherFields });
22
+ ```
23
+
24
+ ## Send to Queue
25
+
26
+ ```typescript
27
+ await rabbit.sendToQueue('order-processing', { orderId: 456 });
28
+ ```
29
+
30
+ ## Consume from Queue
31
+
32
+ ```typescript
33
+ await rabbit.consume('order-processing', async (msg, ack, nack) => {
34
+ const { orderId } = msg.content;
35
+ try {
36
+ await orderService.process(orderId);
37
+ await ack();
38
+ } catch (err) {
39
+ logger.error('Failed to process order', { err, orderId });
40
+ await nack(msg);
41
+ }
42
+ }, {
43
+ retries: 3,
44
+ limit: 5,
45
+ });
46
+ ```
47
+
48
+ ## Consume from Exchange (Fanout)
49
+
50
+ ```typescript
51
+ await rabbit.consumeFromExchange('my-service-vehicle-events', 'vehicle-events', async (msg, ack, nack) => {
52
+ await handleVehicleEvent(msg.content);
53
+ await ack();
54
+ });
55
+ ```
56
+
57
+ ## Skip Retry on Nack
58
+
59
+ ```typescript
60
+ await rabbit.consume('my-queue', async (msg, ack, nack) => {
61
+ if (!isValid(msg.content)) {
62
+ // Bad message — dead-letter immediately, don't retry
63
+ await nack(msg, { skipRetry: true });
64
+ return;
65
+ }
66
+ await process(msg.content);
67
+ await ack();
68
+ });
69
+ ```
70
+
71
+ ## Testing
72
+
73
+ ```typescript
74
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
75
+ import RabbitMqMock from '@autofleet/rabbit/mock/vitest';
76
+ import { MyService } from './my-service';
77
+
78
+ describe('MyService', () => {
79
+ let rabbit: RabbitMqMock;
80
+ let service: MyService;
81
+
82
+ beforeEach(() => {
83
+ rabbit = new RabbitMqMock();
84
+ service = new MyService(rabbit);
85
+ });
86
+
87
+ it('publishes an event on vehicle update', async () => {
88
+ await service.updateVehicle(123, { status: 'active' });
89
+
90
+ expect(rabbit.publish).toHaveBeenCalledWith(
91
+ 'vehicle-events',
92
+ { vehicleId: 123, status: 'active' },
93
+ );
94
+ });
95
+
96
+ it('processes a consumed message', async () => {
97
+ // Grab the callback registered via consume
98
+ await service.startConsuming();
99
+ const [[, callback]] = (rabbit.consume as ReturnType<typeof vi.fn>).mock.calls;
100
+
101
+ const ack = vi.fn().mockResolvedValue(undefined);
102
+ const nack = vi.fn().mockResolvedValue(undefined);
103
+
104
+ await callback({ content: { orderId: 1 } }, ack, nack);
105
+
106
+ expect(ack).toHaveBeenCalled();
107
+ });
108
+ });
109
+ ```
package/dist/e2e.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{C as e,c as t,i as n,l as r,n as i,x as a}from"./utils-CVjmPZwQ.js";import o from"node:path";import s from"p-retry";const c=[`identity-ms`,`vehicle-ms`,`ride-ms`,`vehicle-live-data-ms`,`pricing-ms`,`payment-ms`,`route-plan-ms`,`task-ms`,`audit-ms`,`pgweb`,`placement-ms`,`demand-prediction-ms`,`control-center-ms`,`setting-ms`,`api-gateway-ms`],l={start:`--e2eBranch=<branchName> --branches="{\\"ride-ms\\": \\"AUT-7070\\"}"`,getIpsForEnv:`--variationId=<yourVariationUuid> --cluster=<dev1/e2eManager>`},u=e=>Object.keys(l).includes(e),{positionals:d,values:f,help:p}=e({strict:!0,binName:`autofleet-e2e`,allowPositionals:!0,options:{e2eBranch:{type:`string`,default:`master`,description:`Name of e2e branch`},branches:{type:`string`,default:``,description:`"ride-ms": "AUT-7070"`},cluster:{type:`string`,short:`c`,description:`The cluster name. One of dev1, e2eManager, expManager`},variationId:{type:`string`,short:`i`,description:`The variation id`}},commands:l});d.length||(console.log(p),process.exit(0));const[m]=d;if(u(m)||n(Error(`Command ${m} does not exist`),p),m===`start`){let e=(f.branches?.replace(`{`,` `)||``).replace(/[^a-z0-9]/gi,``),t=`${o.resolve()}/bin/utils/e2e.sh`,n=`${o.resolve()}/e2e.sh`;r({newFilePath:n,filePath:t,linesToReplace:[{find:`$E2E_BRANCH_PLACE_HOLDER$`,replace:f.e2eBranch},{find:`$BRANCHES_PLACE_HOLDER$`,replace:f.branches},{find:`$NAME_PLACE_HOLDER$`,replace:e}]}),await a(`chmod`,[`+x ${n} && ${n}`]),console.log(`finished e2e`)}const{cluster:h,variationId:g}=f;h||n(Error(`cluster required`),p),g||n(Error(`variationId required`),p);let _;try{_=await i({clusterName:h,variationId:g})}catch(e){n(e)}m===`getIpsForEnv`&&(await Promise.all(c.map(e=>a(`kubectl`,[`annotate`,_,`service`,e,`cloud.google.com/load-balancer-type-`],{print:!1}))),await Promise.all(c.map(e=>a(`kubectl`,[`patch`,`svc`,_,e,`-p`,`{"spec": {"type": "LoadBalancer"}}`],{print:!1}))),console.log(`exposed services successfully. the services are now creating public ips.`),await s(async()=>{let{stdout:e}=await a(`kubectl`,[_,`get`,`services`],{print:!1}),n=t(e);if(n.some(e=>e.includes(`<pending>`)))throw Error(`Some services are still pending`);n.forEach(e=>console.log(e))},{retries:10,factor:1,maxTimeout:5e3,randomize:!0}),process.exit(0));export{};
2
+ import{C as e,c as t,i as n,l as r,n as i,x as a}from"./utils-DMSZiZ4H.js";import o from"node:path";import s from"p-retry";const c=[`identity-ms`,`vehicle-ms`,`ride-ms`,`vehicle-live-data-ms`,`pricing-ms`,`payment-ms`,`route-plan-ms`,`task-ms`,`audit-ms`,`pgweb`,`placement-ms`,`demand-prediction-ms`,`control-center-ms`,`setting-ms`,`api-gateway-ms`],l={start:`--e2eBranch=<branchName> --branches="{\\"ride-ms\\": \\"AUT-7070\\"}"`,getIpsForEnv:`--variationId=<yourVariationUuid> --cluster=<dev1/e2eManager>`},u=e=>Object.keys(l).includes(e),{positionals:d,values:f,help:p}=e({strict:!0,binName:`autofleet-e2e`,allowPositionals:!0,options:{e2eBranch:{type:`string`,default:`master`,description:`Name of e2e branch`},branches:{type:`string`,default:``,description:`"ride-ms": "AUT-7070"`},cluster:{type:`string`,short:`c`,description:`The cluster name. One of dev1, e2eManager, expManager`},variationId:{type:`string`,short:`i`,description:`The variation id`}},commands:l});d.length||(console.log(p),process.exit(0));const[m]=d;if(u(m)||n(Error(`Command ${m} does not exist`),p),m===`start`){let e=(f.branches?.replace(`{`,` `)||``).replace(/[^a-z0-9]/gi,``),t=`${o.resolve()}/bin/utils/e2e.sh`,n=`${o.resolve()}/e2e.sh`;r({newFilePath:n,filePath:t,linesToReplace:[{find:`$E2E_BRANCH_PLACE_HOLDER$`,replace:f.e2eBranch},{find:`$BRANCHES_PLACE_HOLDER$`,replace:f.branches},{find:`$NAME_PLACE_HOLDER$`,replace:e}]}),await a(`chmod`,[`+x ${n} && ${n}`]),console.log(`finished e2e`)}const{cluster:h,variationId:g}=f;h||n(Error(`cluster required`),p),g||n(Error(`variationId required`),p);let _;try{_=await i({clusterName:h,variationId:g})}catch(e){n(e)}m===`getIpsForEnv`&&(await Promise.all(c.map(e=>a(`kubectl`,[`annotate`,_,`service`,e,`cloud.google.com/load-balancer-type-`],{print:!1}))),await Promise.all(c.map(e=>a(`kubectl`,[`patch`,`svc`,_,e,`-p`,`{"spec": {"type": "LoadBalancer"}}`],{print:!1}))),console.log(`exposed services successfully. the services are now creating public ips.`),await s(async()=>{let{stdout:e}=await a(`kubectl`,[_,`get`,`services`],{print:!1}),n=t(e);if(n.some(e=>e.includes(`<pending>`)))throw Error(`Some services are still pending`);n.forEach(e=>console.log(e))},{retries:10,factor:1,maxTimeout:5e3,randomize:!0}),process.exit(0));export{};
3
3
  //# sourceMappingURL=e2e.js.map
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{C as e,_ as t,g as n,h as r,i,m as a,v as o,x as s,y as c}from"./utils-CVjmPZwQ.js";import{basename as l,sep as u}from"node:path";import{readdir as d}from"node:fs/promises";import{randomUUID as f}from"node:crypto";const p=[`premajor`,`preminor`,`prepatch`,`prerelease`],m=[`major`,`minor`,`patch`,...p],h={bumpVersion:`[${m.join(`|`)}]`,openPR:`Opens github UI for creating a PR from the current branch.`,releaseBeta:`Bumps version if needed, and publishes a beta release to NPM registry.`},g=e=>Object.keys(h).includes(e),_=async({versionType:e,packageName:t,preReleaseId:n=``})=>{let{stdout:r}=await s(`npm`,[`version`,e,`--no-git-tag-version`,`--preid`,n],{print:!1,cwd:t?`.${u}packages${u}${t}`:void 0});return await s(`git`,[`add`,`package*`],{print:!1}),await s(`git`,[`commit`,`-m`,`${e} version: ${r}`],{print:!1}),console.log(`Created commit for version bump: ${e}. Version is now ${r}`),r},v=async e=>{let t=await c(),{default:{version:n}}=await import(`${e?`${t}${u}packages${u}${e}`:t}${u}package.json`,{assert:{type:`json`},with:{type:`json`}});return n.replace(/\d+\.\d+\.\d+(?:-beta-([\w]+)?\.\d+)?/,`$1`)},{positionals:y,help:b}=e({strict:!0,binName:`git autofleet`,allowPositionals:!0,options:{},commands:h});y.length||(console.log(b),process.exit(0));const[x,S,C]=y;if(g(x)||i(Error(`Command ${x} does not exist`),b),x===`openPR`){let[e,t]=await Promise.all([c(),o()]);await s(`open`,[`https://github.com/Autofleet/${l(e)}/compare/${t}?expand=1`],{print:!1}),process.exit(0)}async function w(){let e=await c();return e.split(u).pop()===`autorepo`?e:!1}async function T({message:e,pathIfAutorepo:t}){t??=await w();let r=C;if(t){let a=(await d(`${t}${u}packages`)).filter(e=>!e.startsWith(`.`));r?a.includes(r)||i(Error(`Package name ${r} does not exist in autorepo packages`),b):r=await n({message:e,choices:a.map(e=>({name:e,value:e}))}),r||i(Error(`No package name provided, exiting...`),b)}return r}if(x===`bumpVersion`){let e=await T({message:`Which package do you want to bump?`}),t=S||await n({message:`Which version type do you want to bump?`,choices:(x===`bumpVersion`?m:p).map(e=>({name:e,value:e}))});t||i(Error(`Must explicitly define version type.\n\tVersion type can be one of: ${m.join(`, `)}`),b);let r=await o();[`main`,`master`].includes(r)&&(await a(`Are you sure you want to bump version on main branch?`)||process.exit(0)),await _({versionType:t,packageName:e}),process.exit(0)}if(x===`releaseBeta`){let e=await w(),n=await T({message:`Which package do you want to release?`,pathIfAutorepo:e});S&&!p.includes(S)&&i(Error(`Invalid version type: ${S}\n\tVersion must be a prerelease type. (${p.join(`, `)})`),b);let c=await o();[`main`,`master`].includes(c)&&i(Error(`Cannot release beta from main branch`),b);let l=n?`.${u}packages${u}${n}`:void 0,d=!(await t(n?`.${u}packages${u}${n}${u}package.json`:`package.json`)).split(`
2
+ import{C as e,_ as t,g as n,h as r,i,m as a,v as o,x as s,y as c}from"./utils-DMSZiZ4H.js";import{basename as l,sep as u}from"node:path";import{readdir as d}from"node:fs/promises";import{randomUUID as f}from"node:crypto";const p=[`premajor`,`preminor`,`prepatch`,`prerelease`],m=[`major`,`minor`,`patch`,...p],h={bumpVersion:`[${m.join(`|`)}]`,openPR:`Opens github UI for creating a PR from the current branch.`,releaseBeta:`Bumps version if needed, and publishes a beta release to NPM registry.`},g=e=>Object.keys(h).includes(e),_=async({versionType:e,packageName:t,preReleaseId:n=``})=>{let{stdout:r}=await s(`npm`,[`version`,e,`--no-git-tag-version`,`--preid`,n],{print:!1,cwd:t?`.${u}packages${u}${t}`:void 0});return await s(`git`,[`add`,`package*`],{print:!1}),await s(`git`,[`commit`,`-m`,`${e} version: ${r}`],{print:!1}),console.log(`Created commit for version bump: ${e}. Version is now ${r}`),r},v=async e=>{let t=await c(),{default:{version:n}}=await import(`${e?`${t}${u}packages${u}${e}`:t}${u}package.json`,{assert:{type:`json`},with:{type:`json`}});return n.replace(/\d+\.\d+\.\d+(?:-beta-([\w]+)?\.\d+)?/,`$1`)},{positionals:y,help:b}=e({strict:!0,binName:`git autofleet`,allowPositionals:!0,options:{},commands:h});y.length||(console.log(b),process.exit(0));const[x,S,C]=y;if(g(x)||i(Error(`Command ${x} does not exist`),b),x===`openPR`){let[e,t]=await Promise.all([c(),o()]);await s(`open`,[`https://github.com/Autofleet/${l(e)}/compare/${t}?expand=1`],{print:!1}),process.exit(0)}async function w(){let e=await c();return e.split(u).pop()===`autorepo`?e:!1}async function T({message:e,pathIfAutorepo:t}){t??=await w();let r=C;if(t){let a=(await d(`${t}${u}packages`)).filter(e=>!e.startsWith(`.`));r?a.includes(r)||i(Error(`Package name ${r} does not exist in autorepo packages`),b):r=await n({message:e,choices:a.map(e=>({name:e,value:e}))}),r||i(Error(`No package name provided, exiting...`),b)}return r}if(x===`bumpVersion`){let e=await T({message:`Which package do you want to bump?`}),t=S||await n({message:`Which version type do you want to bump?`,choices:(x===`bumpVersion`?m:p).map(e=>({name:e,value:e}))});t||i(Error(`Must explicitly define version type.\n\tVersion type can be one of: ${m.join(`, `)}`),b);let r=await o();[`main`,`master`].includes(r)&&(await a(`Are you sure you want to bump version on main branch?`)||process.exit(0)),await _({versionType:t,packageName:e}),process.exit(0)}if(x===`releaseBeta`){let e=await w(),n=await T({message:`Which package do you want to release?`,pathIfAutorepo:e});S&&!p.includes(S)&&i(Error(`Invalid version type: ${S}\n\tVersion must be a prerelease type. (${p.join(`, `)})`),b);let c=await o();[`main`,`master`].includes(c)&&i(Error(`Cannot release beta from main branch`),b);let l=n?`.${u}packages${u}${n}`:void 0,d=!(await t(n?`.${u}packages${u}${n}${u}package.json`:`package.json`)).split(`
3
3
  `).some(e=>/^\+\s*"version":\s*"\d+\.\d+\.\d+(?:-(?:[\w-]+\.)?\d+)?",/.test(e))||await a(`Version already bumped on branch. Should version be re-bumped?`),m=d&&await v(n),h=d&&await _({versionType:S||`prerelease`,preReleaseId:`beta-${m||f().split(`-`)[0]}`,packageName:n}),g=e?`pnpm`:`npm`;await s(g,[`run`,`build`],{cwd:l});let y=await r({message:`In case your token requires an OTP, please enter it:`});try{await s(g,[`publish`,`--tag`,`beta`,`--@autofleet:registry=https://registry.npmjs.org`,...y?[`--otp`,y]:[],...e?[`--no-git-checks`]:[]],{cwd:l})}catch(e){console.error(e),i(`Failed to publish beta version`)}if(h)console.log(`Published beta version with new version: ${h}`);else{let{stdout:e}=await s(g,[`info`,`.`,`version`],{print:!1,cwd:l});console.log(`Published beta version with existing version: ${e}`)}process.exit(0)}export{};
4
4
  //# sourceMappingURL=git-autofleet.js.map