rise-deploy 0.16.4

A simple and powerful CLI for deploying containerized applications
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
name: CI

on:
  pull_request:
    branches:
      - develop
  push:
    branches:
      - develop
    tags:
      - "v*"

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}

permissions:
  contents: read

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: niklasrosenstein/rise
  BUILDER_IMAGE_NAME: niklasrosenstein/rise-builder
  CHART_REGISTRY: ghcr.io/niklasrosenstein/rise
  RUST_VERSION: "1.91.1"

jobs:
  prepare:
    name: Prepare CI metadata
    runs-on: ubuntu-latest
    outputs:
      ci_version: ${{ steps.meta.outputs.ci_version }}
      image_tag: ${{ steps.meta.outputs.image_tag }}
      short_sha: ${{ steps.meta.outputs.short_sha }}
      is_trusted_pr: ${{ steps.meta.outputs.is_trusted_pr }}
      should_publish: ${{ steps.meta.outputs.should_publish }}
    steps:
      - name: Compute metadata
        id: meta
        shell: bash
        run: |
          set -euo pipefail

          short_sha="${GITHUB_SHA::7}"
          if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then
            pr_number="${{ github.event.pull_request.number }}"
            ci_version="0.0.0-pr.${pr_number}+${short_sha}"
            image_tag="pr-${pr_number}-${short_sha}"
            is_trusted_pr="false"
            if [[ "${{ github.event.pull_request.head.repo.full_name }}" == "${{ github.repository }}" ]]; then
              is_trusted_pr="true"
            fi
          elif [[ "${GITHUB_REF}" == refs/heads/develop ]]; then
            ci_version="0.0.0-develop.${GITHUB_RUN_NUMBER}+${short_sha}"
            image_tag="develop-${short_sha}"
            is_trusted_pr="false"
          elif [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
            version="${GITHUB_REF#refs/tags/v}"
            ci_version="${version}"
            image_tag="${version}"
            is_trusted_pr="false"
          else
            ci_version="0.0.0-dev.${GITHUB_RUN_NUMBER}+${short_sha}"
            image_tag="dev-${short_sha}"
            is_trusted_pr="false"
          fi

          should_publish="false"
          if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
            should_publish="true"
          elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" && "${is_trusted_pr}" == "true" ]]; then
            should_publish="true"
          fi

          echo "ci_version=${ci_version}" >> "$GITHUB_OUTPUT"
          echo "image_tag=${image_tag}" >> "$GITHUB_OUTPUT"
          echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT"
          echo "is_trusted_pr=${is_trusted_pr}" >> "$GITHUB_OUTPUT"
          echo "should_publish=${should_publish}" >> "$GITHUB_OUTPUT"

          echo "CI Version: ${ci_version}"
          echo "Image Tag: ${image_tag}"
          echo "Short SHA: ${short_sha}"
          echo "Is Trusted PR: ${is_trusted_pr}"
          echo "Should Publish: ${should_publish}"

  rust-quality:
    name: Rust quality checks
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: ${{ env.RUST_VERSION }}
          components: rustfmt, clippy

      - name: Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          experimental: true

      - name: Install mise tools
        run: mise use -g cargo:sqlx-cli cargo:cargo-all-features

      - name: Verify backend config schema is up to date
        run: mise config:schema:check

      - name: Check formatting
        run: cargo fmt --all -- --check

      - name: Run Clippy (all feature combinations)
        run: cargo all-features clippy --all-targets -- -D warnings
        env:
          SQLX_OFFLINE: true

      - name: Verify SQLX offline query data
        run: mise run sqlx:check

  unit-tests-linux:
    name: Linux tests
    runs-on: ubuntu-latest
    needs: prepare
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: rise_test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          experimental: true

      - name: Install mise tools
        run: mise use -g cargo:sqlx-cli

      - name: Run database migrations
        run: |
          sqlx database create
          sqlx migrate run
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/rise_test

      - name: Run tests
        run: cargo test --all-features
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/rise_test

  helm-lint:
    name: Helm lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          experimental: true

      - name: Install mise tools
        run: mise use -g helm

      - name: Set up chart-testing
        uses: helm/chart-testing-action@v2.6.1

      - name: Run chart-testing (lint)
        run: ct lint --target-branch ${{ github.event.repository.default_branch }} --charts helm/rise --validate-maintainers=false

      - name: Install kubeconform
        run: |
          set -euo pipefail
          curl -sSLo /tmp/kubeconform.tar.gz https://github.com/yannh/kubeconform/releases/download/v0.7.0/kubeconform-linux-amd64.tar.gz
          tar -xzf /tmp/kubeconform.tar.gz -C /tmp kubeconform
          sudo install -m 0755 /tmp/kubeconform /usr/local/bin/kubeconform

      - name: Validate Helm templates with kubeconform
        run: |
          helm template rise helm/rise | kubeconform -strict -summary
          helm template rise helm/rise -f helm/rise/values-ci.yaml | kubeconform -strict -summary

  package-image:
    name: Build and publish image
    runs-on: ubuntu-latest
    needs:
      - prepare
      - rust-quality
      - unit-tests-linux
      - helm-lint
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        if: needs.prepare.outputs.should_publish == 'true'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and optionally push image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          target: rise
          push: ${{ needs.prepare.outputs.should_publish == 'true' }}
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ needs.prepare.outputs.short_sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64
          provenance: false

      - name: Build and optionally push builder image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          target: rise-builder
          push: ${{ needs.prepare.outputs.should_publish == 'true' }}
          tags: |
            ${{ env.REGISTRY }}/${{ env.BUILDER_IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }}
            ${{ env.REGISTRY }}/${{ env.BUILDER_IMAGE_NAME }}:sha-${{ needs.prepare.outputs.short_sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64
          provenance: false

  package-helm:
    name: Package and publish Helm chart
    runs-on: ubuntu-latest
    needs:
      - prepare
      - package-image
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          experimental: true

      - name: Install mise tools
        run: mise use -g helm

      - name: Patch chart version and appVersion for CI package
        shell: bash
        run: |
          set -euo pipefail
          ci_version="${{ needs.prepare.outputs.ci_version }}"
          image_tag="${{ needs.prepare.outputs.image_tag }}"
          sed -i "s/^version: .*/version: ${ci_version}/" helm/rise/Chart.yaml
          sed -i "s/^appVersion: .*/appVersion: \"${image_tag}\"/" helm/rise/Chart.yaml
          cat helm/rise/Chart.yaml

      - name: Package chart
        run: |
          mkdir -p .helm-packages
          helm package helm/rise -d .helm-packages

      - name: Upload chart artifact
        uses: actions/upload-artifact@v4
        with:
          name: helm-chart-${{ needs.prepare.outputs.image_tag }}
          path: .helm-packages/*.tgz

      - name: Login to GHCR for Helm OCI push
        if: needs.prepare.outputs.should_publish == 'true'
        run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ${{ env.REGISTRY }} -u "${{ github.actor }}" --password-stdin

      - name: Push chart to OCI registry
        if: needs.prepare.outputs.should_publish == 'true'
        run: |
          chart_file=$(ls .helm-packages/*.tgz)
          helm push "$chart_file" "oci://${{ env.CHART_REGISTRY }}"

  publish-crates:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    needs:
      - rust-quality
      - unit-tests-linux
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Verify version matches tag
        run: |
          TAG_VERSION=${GITHUB_REF#refs/tags/v}
          CARGO_VERSION=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[0].version')
          echo "Tag version: $TAG_VERSION"
          echo "Cargo version: $CARGO_VERSION"
          if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
            echo "::error::Tag version ($TAG_VERSION) doesn't match Cargo version ($CARGO_VERSION)"
            exit 1
          fi

      - name: Authenticate with crates.io
        uses: rust-lang/crates-io-auth-action@v1
        id: auth

      - name: Publish to crates.io
        run: cargo publish --features cli
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

  e2e-build:
    name: E2E build tests
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Rust cache
        uses: Swatinem/rust-cache@v2

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          experimental: true

      - name: Install mise tools
        run: mise use -g pack railpack buildkit

      - name: Build Rise CLI
        run: cargo build --release --features cli

      - name: Run e2e build tests (no proxy)
        run: RISE_BIN=./target/release/rise bash tests/e2e-build/run.sh --no-proxy

      - name: Run e2e build tests (with proxy)
        run: RISE_BIN=./target/release/rise bash tests/e2e-build/run.sh --only-proxy

  e2e-minikube:
    name: Minikube end-to-end smoke tests
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
    needs:
      - prepare
      - package-image
      - package-helm
    permissions:
      contents: read
      packages: read
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          cache: true
          experimental: true

      - name: Install mise tools
        run: mise use -g minikube kubectl helm

      - name: Start Minikube and run smoke tests
        env:
          RISE_IMAGE_REPOSITORY: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          RISE_IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }}
        run: bash scripts/ci/e2e-minikube.sh