gowalk-cicd 1.0.41 → 1.0.43

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
@@ -58,11 +58,16 @@ account or domain.
58
58
 
59
59
  ## Backend deploy (Python + Postgres, Docker)
60
60
 
61
- When a repo carries a Dockerized backend a `backend/` (or `server/`) directory
62
- with a `docker-compose.yml` — the installer also vendors a backend deploy path:
61
+ When a repo carries a Dockerized backend, the installer also vendors a backend deploy path:
63
62
  `.github/actions/backend-app/` and `.github/workflows/deploy-backend.yml`. A
64
63
  mobile-only repo is unaffected (the backend path is not installed).
65
64
 
65
+ Both supported layouts keep application source under `backend/` or `server/`:
66
+
67
+ - the compose file can live beside that source as `backend/docker-compose.yml`; or
68
+ - it can live at the repository root as `docker-compose.yml` and build `./backend`
69
+ (equivalently for `server/`).
70
+
66
71
  The backend workflow runs on a GitHub-hosted runner and, on a push touching
67
72
  `backend/**`, deploys to the gowalk host (`138.197.36.107`, publicly reachable):
68
73
  it rsyncs the backend dir to `/opt/gowalk-backends/<app>/`, runs
@@ -71,7 +76,7 @@ wires an nginx vhost + Let's Encrypt cert for the API domain, and health-checks.
71
76
 
72
77
  Requirements on the consumer repo:
73
78
 
74
- - **`backend/docker-compose.yml`** that publishes the API on a **loopback host
79
+ - A supported **`docker-compose.yml`** that publishes the API on a **loopback host
75
80
  port** (`127.0.0.1:<port>:<container-port>`) so nginx can proxy it. Include a
76
81
  Postgres service (or use a per-app database) and a `/health` endpoint.
77
82
  - A **`Dockerfile`** the compose file builds; pin the base image, run non-root,
@@ -1 +1 @@
1
- 1.0.41
1
+ 1.0.43
@@ -1 +1 @@
1
- 1.0.41
1
+ 1.0.43
@@ -1 +1 @@
1
- 1.0.41
1
+ 1.0.43
@@ -28,9 +28,15 @@ inputs:
28
28
  required: false
29
29
  default: ""
30
30
  backend-dir:
31
- description: Path to the backend (holds Dockerfile + docker-compose.yml).
31
+ description: Path to the backend source directory.
32
32
  required: false
33
33
  default: "backend"
34
+ compose-file:
35
+ description: >
36
+ Compose file path. Empty defaults to <backend-dir>/docker-compose.yml;
37
+ docker-compose.yml supports a root compose file that builds ./backend or ./server.
38
+ required: false
39
+ default: ""
34
40
  health-path:
35
41
  description: HTTP path the service answers 2xx on once healthy.
36
42
  required: false
@@ -51,14 +57,33 @@ runs:
51
57
  using: composite
52
58
  steps:
53
59
  - name: Validate inputs
60
+ id: layout
54
61
  shell: bash
62
+ env:
63
+ BACKEND_DIR: ${{ inputs.backend-dir }}
64
+ COMPOSE_FILE_INPUT: ${{ inputs.compose-file }}
55
65
  run: |
56
66
  set -euo pipefail
57
- test -f "${{ inputs.backend-dir }}/docker-compose.yml" \
58
- || { echo "::error::no ${{ inputs.backend-dir }}/docker-compose.yml"; exit 1; }
67
+ COMPOSE_FILE="${COMPOSE_FILE_INPUT:-$BACKEND_DIR/docker-compose.yml}"
68
+ test -d "$BACKEND_DIR" \
69
+ || { echo "::error::no backend directory $BACKEND_DIR"; exit 1; }
70
+ test -f "$COMPOSE_FILE" \
71
+ || { echo "::error::no compose file $COMPOSE_FILE"; exit 1; }
72
+ case "$BACKEND_DIR" in
73
+ /*|../*|*/../*|*/..|.) echo "::error::backend-dir must be a safe relative path"; exit 1;;
74
+ esac
75
+ case "$COMPOSE_FILE" in
76
+ /*|../*|*/../*|*/..) echo "::error::compose-file must be a safe relative path"; exit 1;;
77
+ esac
78
+ if [ "$COMPOSE_FILE" != "$BACKEND_DIR/docker-compose.yml" ] \
79
+ && [ "$COMPOSE_FILE" != "docker-compose.yml" ]; then
80
+ echo "::error::compose-file must be docker-compose.yml or $BACKEND_DIR/docker-compose.yml"
81
+ exit 1
82
+ fi
59
83
  case "${{ inputs.app-name }}" in
60
84
  *[!a-z0-9-]*|"") echo "::error::app-name must be [a-z0-9-]"; exit 1;;
61
85
  esac
86
+ echo "compose-file=$COMPOSE_FILE" >> "$GITHUB_OUTPUT"
62
87
 
63
88
  - name: Configure SSH
64
89
  shell: bash
@@ -74,6 +99,9 @@ runs:
74
99
 
75
100
  - name: Sync backend to the host
76
101
  shell: bash
102
+ env:
103
+ BACKEND_DIR: ${{ inputs.backend-dir }}
104
+ COMPOSE_FILE: ${{ steps.layout.outputs.compose-file }}
77
105
  run: |
78
106
  set -euo pipefail
79
107
  SSH="ssh -i ~/.ssh/backend_deploy -o IdentitiesOnly=yes"
@@ -81,9 +109,19 @@ runs:
81
109
  $SSH "${{ inputs.ssh-user }}@${{ inputs.host }}" "mkdir -p '$DEST'"
82
110
  # --delete keeps the mirror true; exclude .env so server-side secrets
83
111
  # (generated DB password, etc.) survive across deploys.
84
- rsync -az --delete --exclude '.env' --exclude '.git' \
85
- -e "$SSH" "${{ inputs.backend-dir }}/" \
86
- "${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/"
112
+ if [ "$COMPOSE_FILE" = "$BACKEND_DIR/docker-compose.yml" ]; then
113
+ rsync -az --delete --exclude '.env' --exclude '.git' \
114
+ -e "$SSH" "$BACKEND_DIR/" \
115
+ "${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/"
116
+ else
117
+ $SSH "${{ inputs.ssh-user }}@${{ inputs.host }}" \
118
+ "mkdir -p '$DEST/$BACKEND_DIR'"
119
+ rsync -az --delete --exclude '.env' --exclude '.git' \
120
+ -e "$SSH" "$BACKEND_DIR/" \
121
+ "${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/$BACKEND_DIR/"
122
+ rsync -az -e "$SSH" "$COMPOSE_FILE" \
123
+ "${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/docker-compose.yml"
124
+ fi
87
125
  # ship the remote deploy script (kept out of the app checkout)
88
126
  rsync -az -e "$SSH" "${{ github.action_path }}/remote_deploy.sh" \
89
127
  "${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/.remote_deploy.sh"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gowalk-cicd",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "Zero-config GitHub Actions delivery for iOS TestFlight and Android Google Play.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/install.mjs CHANGED
@@ -44,10 +44,22 @@ const VERSION_MARKER_REL = join('.github', 'actions', 'swift-app', '.daemux-vers
44
44
  const ANDROID_VERSION_MARKER_REL = join('.github', 'actions', 'android-app', '.daemux-version');
45
45
  const BACKEND_VERSION_MARKER_REL = join('.github', 'actions', 'backend-app', '.daemux-version');
46
46
 
47
- // A repo has a backend when a backend/ or server/ dir carries a compose file.
48
- function backendDir(repoRoot) {
47
+ // A repo has a backend when backend/ or server/ either carries the compose file
48
+ // or is referenced by a root compose file. The latter is Flutter's common
49
+ // full-stack layout: docker-compose.yml stays at the repo root so it can build
50
+ // ./backend while the deploy action still syncs only backend-owned files.
51
+ function backendLayout(repoRoot) {
49
52
  for (const d of ['backend', 'server']) {
50
- if (existsSync(join(repoRoot, d, 'docker-compose.yml'))) return d;
53
+ if (existsSync(join(repoRoot, d, 'docker-compose.yml'))) {
54
+ return { backendDir: d, composeFile: join(d, 'docker-compose.yml') };
55
+ }
56
+ }
57
+ if (existsSync(join(repoRoot, 'docker-compose.yml'))) {
58
+ for (const d of ['backend', 'server']) {
59
+ if (existsSync(join(repoRoot, d, 'Dockerfile'))) {
60
+ return { backendDir: d, composeFile: 'docker-compose.yml' };
61
+ }
62
+ }
51
63
  }
52
64
  return null;
53
65
  }
@@ -235,12 +247,12 @@ export async function runInstall({ dryRun = false } = {}) {
235
247
  }
236
248
  }
237
249
 
238
- // Backend deploy path — installed only when the repo has a Dockerized
239
- // backend (backend/ or server/ with a docker-compose.yml). Mobile-only
240
- // repos are unaffected, so this is backward compatible.
241
- const bdir = backendDir(repoRoot);
242
- if (bdir) {
243
- console.log(` Backend detected (${bdir}/docker-compose.yml) — installing backend deploy`);
250
+ // Backend deploy path — installed only for a supported nested or root
251
+ // compose layout. Mobile-only repos are unaffected, so this is backward
252
+ // compatible.
253
+ const layout = backendLayout(repoRoot);
254
+ if (layout) {
255
+ console.log(` Backend detected (${layout.composeFile}) — installing backend deploy`);
244
256
  copyAction(BACKEND_ACTION_SRC, BACKEND_ACTION_DEST_REL, repoRoot, dryRun);
245
257
  if (!dryRun) writeFileSync(
246
258
  join(repoRoot, BACKEND_VERSION_MARKER_REL),
@@ -1,14 +1,15 @@
1
1
  name: Backend Deploy
2
2
 
3
3
  # Deploys the Dockerized Python+Postgres backend to the gowalk host. Installed
4
- # by gowalk-cicd only when a backend/ (or server/) dir with a docker-compose.yml
5
- # is present. Mobile deploy stays in deploy.yml — this is the backend's own path.
4
+ # by gowalk-cicd when backend/ or server/ has a compose file, or when a root
5
+ # compose file builds one of those directories. Mobile deploy stays in deploy.yml.
6
6
  on:
7
7
  push:
8
8
  branches: [main]
9
9
  paths:
10
10
  - "backend/**"
11
11
  - "server/**"
12
+ - "docker-compose.yml"
12
13
  - ".github/workflows/deploy-backend.yml"
13
14
  workflow_dispatch:
14
15
 
@@ -23,12 +24,25 @@ jobs:
23
24
  steps:
24
25
  - uses: actions/checkout@v4
25
26
 
26
- # Pick backend/ or server/, whichever holds the compose file.
27
+ # Pick the source dir and either its nested compose file or a root one.
27
28
  - id: dir
28
29
  run: |
29
- if [ -f backend/docker-compose.yml ]; then echo "path=backend" >> "$GITHUB_OUTPUT"
30
- elif [ -f server/docker-compose.yml ]; then echo "path=server" >> "$GITHUB_OUTPUT"
31
- else echo "::error::no backend/ or server/ docker-compose.yml"; exit 1; fi
30
+ if [ -f backend/docker-compose.yml ]; then
31
+ echo "path=backend" >> "$GITHUB_OUTPUT"
32
+ echo "compose=backend/docker-compose.yml" >> "$GITHUB_OUTPUT"
33
+ elif [ -f server/docker-compose.yml ]; then
34
+ echo "path=server" >> "$GITHUB_OUTPUT"
35
+ echo "compose=server/docker-compose.yml" >> "$GITHUB_OUTPUT"
36
+ elif [ -f docker-compose.yml ] && [ -f backend/Dockerfile ]; then
37
+ echo "path=backend" >> "$GITHUB_OUTPUT"
38
+ echo "compose=docker-compose.yml" >> "$GITHUB_OUTPUT"
39
+ elif [ -f docker-compose.yml ] && [ -f server/Dockerfile ]; then
40
+ echo "path=server" >> "$GITHUB_OUTPUT"
41
+ echo "compose=docker-compose.yml" >> "$GITHUB_OUTPUT"
42
+ else
43
+ echo "::error::no supported backend compose layout"
44
+ exit 1
45
+ fi
32
46
 
33
47
  - name: Deploy backend
34
48
  uses: ./.github/actions/backend-app
@@ -38,5 +52,6 @@ jobs:
38
52
  app-name: ${{ vars.BACKEND_APP_NAME || github.event.repository.name }}
39
53
  api-domain: ${{ vars.BACKEND_API_DOMAIN }}
40
54
  backend-dir: ${{ steps.dir.outputs.path }}
55
+ compose-file: ${{ steps.dir.outputs.compose }}
41
56
  health-path: ${{ vars.BACKEND_HEALTH_PATH || '/health' }}
42
57
  runtime-env: ${{ secrets.BACKEND_RUNTIME_ENV }}
@@ -415,9 +415,22 @@ jobs:
415
415
  - id: dir
416
416
  shell: bash
417
417
  run: |
418
- if [ -f backend/docker-compose.yml ]; then echo "path=backend" >> "$GITHUB_OUTPUT"
419
- elif [ -f server/docker-compose.yml ]; then echo "path=server" >> "$GITHUB_OUTPUT"
420
- else echo "path=" >> "$GITHUB_OUTPUT"; fi
418
+ if [ -f backend/docker-compose.yml ]; then
419
+ echo "path=backend" >> "$GITHUB_OUTPUT"
420
+ echo "compose=backend/docker-compose.yml" >> "$GITHUB_OUTPUT"
421
+ elif [ -f server/docker-compose.yml ]; then
422
+ echo "path=server" >> "$GITHUB_OUTPUT"
423
+ echo "compose=server/docker-compose.yml" >> "$GITHUB_OUTPUT"
424
+ elif [ -f docker-compose.yml ] && [ -f backend/Dockerfile ]; then
425
+ echo "path=backend" >> "$GITHUB_OUTPUT"
426
+ echo "compose=docker-compose.yml" >> "$GITHUB_OUTPUT"
427
+ elif [ -f docker-compose.yml ] && [ -f server/Dockerfile ]; then
428
+ echo "path=server" >> "$GITHUB_OUTPUT"
429
+ echo "compose=docker-compose.yml" >> "$GITHUB_OUTPUT"
430
+ else
431
+ echo "path=" >> "$GITHUB_OUTPUT"
432
+ echo "compose=" >> "$GITHUB_OUTPUT"
433
+ fi
421
434
  - name: Deploy backend from feature branch
422
435
  if: ${{ steps.dir.outputs.path != '' }}
423
436
  uses: ./.github/actions/backend-app
@@ -427,5 +440,6 @@ jobs:
427
440
  app-name: ${{ vars.BACKEND_APP_NAME || github.event.repository.name }}
428
441
  api-domain: ${{ vars.BACKEND_API_DOMAIN }}
429
442
  backend-dir: ${{ steps.dir.outputs.path }}
443
+ compose-file: ${{ steps.dir.outputs.compose }}
430
444
  health-path: ${{ vars.BACKEND_HEALTH_PATH || '/health' }}
431
445
  runtime-env: ${{ secrets.BACKEND_RUNTIME_ENV }}