Skip to content

Commit 0ebd2ca

Browse files
committed
ci & preview-deployments
resolved LTT-86
1 parent 9b1321b commit 0ebd2ca

18 files changed

Lines changed: 373 additions & 57 deletions

.dockerignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
node_modules
55
build
66

7-
README.md
7+
*.md
88

9-
lttle.yaml
9+
*.yaml
1010

1111
.nvmrc

.github/workflows/checks.yaml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: ci
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
prepare:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v3
11+
12+
- uses: actions/cache@v3
13+
with:
14+
path: |
15+
node_modules
16+
key: dependencies-${{ hashFiles('package-lock.json') }}
17+
restore-keys: |
18+
dependencies-${{ hashFiles('package-lock.json') }}
19+
20+
- uses: actions/setup-node@v3
21+
with:
22+
node-version: 22.18.0
23+
24+
- run: npm install --frozen-lockfile 2> >(grep -v warning 1>&2)
25+
26+
typecheck:
27+
needs: [prepare]
28+
runs-on: ubuntu-latest
29+
steps:
30+
- uses: actions/checkout@v3
31+
32+
- uses: actions/cache@v3
33+
with:
34+
path: |
35+
node_modules
36+
key: dependencies-${{ hashFiles('package-lock.json') }}
37+
restore-keys: |
38+
dependencies-${{ hashFiles('package-lock.json') }}
39+
40+
- uses: actions/setup-node@v3
41+
with:
42+
node-version: 22.18.0
43+
44+
- run: npm run typecheck
45+
46+
build:
47+
needs: [prepare]
48+
runs-on: ubuntu-latest
49+
steps:
50+
- uses: actions/checkout@v3
51+
52+
- uses: actions/cache@v3
53+
with:
54+
path: |
55+
node_modules
56+
key: dependencies-${{ hashFiles('package-lock.json') }}
57+
restore-keys: |
58+
dependencies-${{ hashFiles('package-lock.json') }}
59+
60+
- uses: actions/cache@v3
61+
with:
62+
path: |
63+
build
64+
key: build-${{ hashFiles('package-lock.json') }}-${{ github.ref }}
65+
restore-keys: |
66+
build-${{ hashFiles('package-lock.json') }}-${{ github.ref }}
67+
build-${{ hashFiles('package-lock.json') }}
68+
69+
- name: "Setting up dummy environment variables into .env.production file"
70+
run: |
71+
echo "DOCS_URL='http://example.com'" >> .env.production
72+
echo "TYPESENSE_FQDN='https://typesense.example.com'" >> .env.production
73+
echo "TYPESENSE_API_KEY='your-typesense-api-key'" >> .env.production
74+
75+
- uses: actions/setup-node@v3
76+
with:
77+
node-version: 22.18.0
78+
79+
- run: npm run build:prod

.github/workflows/ci.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
on:
2+
push:
3+
branches: ["main"]
4+
paths-ignore:
5+
- ".github/workflows/release.yml"
6+
pull_request:
7+
branches: ["main"]
8+
workflow_call:
9+
10+
jobs:
11+
preflight-checks:
12+
uses: ./.github/workflows/checks.yaml
13+
14+
deploy:
15+
needs: [preflight-checks]
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v3
19+
20+
- uses: actions/cache@v3
21+
with:
22+
path: |
23+
node_modules
24+
key: dependencies-${{ hashFiles('package-lock.json') }}
25+
restore-keys: |
26+
dependencies-${{ hashFiles('package-lock.json') }}
27+
28+
- uses: actions/cache@v3
29+
with:
30+
path: |
31+
build
32+
key: build-${{ hashFiles('package-lock.json') }}-${{ github.ref }}
33+
restore-keys: |
34+
build-${{ hashFiles('package-lock.json') }}-${{ github.ref }}
35+
build-${{ hashFiles('package-lock.json') }}
36+
37+
- name: Login to Docker Hub
38+
uses: docker/login-action@v3
39+
with:
40+
username: ${{ vars.DOCKERHUB_USERNAME }}
41+
password: ${{ secrets.DOCKERHUB_TOKEN }}
42+
43+
- name: "Installing lttle cli"
44+
run: |
45+
curl -fsSL https://raw.githubusercontent.com/lttle-cloud/ignition/refs/heads/master/get/lttle.sh | bash
46+
47+
- name: "Authenticating with eu.lttle.cloud"
48+
env:
49+
LTTLE_JWT_TOKEN: ${{ secrets.LTTLE_JWT_TOKEN }}
50+
run: |
51+
lttle login --api "http://eu.lttle.cloud:5100" "$LTTLE_JWT_TOKEN"\
52+
53+
- uses: actions/setup-node@v3
54+
with:
55+
node-version: 22.18.0
56+
- name: "Setting up environment variables into .env.production file"
57+
run: |
58+
echo "TYPESENSE_API_KEY='$TYPESENSE_API_KEY'" >> .env.production
59+
60+
- name: "Deploying the application"
61+
run: ./deploy.sh
62+
63+
- name: "Waiting for the application to be ready"
64+
run: ./wait-for-app.sh
65+
66+
- name: "Restarting the application"
67+
run: ./restart.sh

DEPLOYMENT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ For production deployment there are multiple variables needed because we use the
2323

2424
```sh
2525
DOCS_URL=https://path.to.docs.url
26-
TYPESENSE_URL=https://path.to.typesense.url
26+
TYPESENSE_FQDN=https://path.to.typesense.url
2727
TYPESENSE_API_KEY=some-api-key
2828
```
2929

deploy-docs.sh

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@
22

33
set -e
44

5-
echo "Building the lttle-docs image..."
6-
docker build -f ./docker/dockerfile . -t aifrim/lttle-docs:latest
5+
source ./deploy/utilities.bash
76

8-
echo "Pushing the images to Docker Hub..."
9-
docker push aifrim/lttle-docs:latest
7+
if [[ -f .env.production ]]; then
8+
export $(xargs < .env.production)
9+
fi
1010

11-
echo "Deploying only the nginx-docs"
12-
lttle deploy ./lttle/docs.lttle.yaml
11+
if [ -z "${GITHUB_HEAD_REF+x}" ]; then
12+
GITHUB_HEAD_REF=$(git rev-parse --abbrev-ref HEAD)
13+
export GITHUB_HEAD_REF
14+
fi
1315

14-
exec "Restarting the machine to apply changes"
15-
lttle machine restart --ns docs nginx-docs
16+
namespace="docs-"$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'main' : env.GITHUB_HEAD_REF + '-branch'");
17+
tag=$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'latest' : env.GITHUB_HEAD_REF + '-branch'")
18+
19+
docsURL="https://"$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'docs.lttle.aifrim.com' : 'docs-' + env.GITHUB_HEAD_REF + '-lttle-aifrim.eu.lttle.host'");
20+
typesenseFQDN=$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'docs-search.lttle.aifrim.com' : 'docs-search-' + env.GITHUB_HEAD_REF + '-lttle-aifrim.eu.lttle.host'")
21+
22+
deployDocs "$namespace" "$tag" "$docsURL" "$typesenseFQDN"

deploy-typesense.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
source ./deploy/utilities.bash
6+
7+
if [[ -f .env.production ]]; then
8+
export $(xargs < .env.production)
9+
fi
10+
11+
if [ -z "${GITHUB_HEAD_REF+x}" ]; then
12+
GITHUB_HEAD_REF=$(git rev-parse --abbrev-ref HEAD)
13+
export GITHUB_HEAD_REF
14+
fi
15+
16+
namespace="docs-"$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'main' : env.GITHUB_HEAD_REF + '-branch'");
17+
tag=$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'latest' : env.GITHUB_HEAD_REF + '-branch'")
18+
19+
docsURL="https://"$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'docs.lttle.aifrim.com' : 'docs-' + env.GITHUB_HEAD_REF + '-lttle-aifrim.eu.lttle.host'");
20+
typesenseFQDN=$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'docs-search.lttle.aifrim.com' : 'docs-search-' + env.GITHUB_HEAD_REF + '-lttle-aifrim.eu.lttle.host'")
21+
22+
deployTypeSense "$namespace" "$tag" "$docsURL" "$typesenseFQDN"

deploy.sh

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22

33
set -e
44

5-
echo "Building the lttle-docs image..."
6-
docker build -f ./docker/dockerfile . -t aifrim/lttle-docs:latest
5+
source ./deploy/utilities.bash
76

8-
echo "Pushing the images to Docker Hub..."
9-
docker push aifrim/lttle-docs:latest
7+
if [[ -f .env.production ]]; then
8+
export $(xargs < .env.production)
9+
fi
1010

11-
echo "Building the Typesense Scraper image..."
12-
docker build -f ./docker/typesense-scraper.dockerfile docker -t aifrim/typesense-scraper:latest
11+
if [ -z "${GITHUB_HEAD_REF+x}" ]; then
12+
GITHUB_HEAD_REF=$(git rev-parse --abbrev-ref HEAD)
13+
export GITHUB_HEAD_REF
14+
fi
1315

14-
docker push aifrim/typesense-scraper:latest
1516

16-
echo "Deploying to lttle.cloud..."
17-
lttle deploy ./lttle
17+
namespace="docs-"$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'main' : env.GITHUB_HEAD_REF + '-branch'");
18+
tag=$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'latest' : env.GITHUB_HEAD_REF + '-branch'")
1819

19-
# Restarting the machines to always make sure that new changes are picked up (e.g. env vars)
20-
# TODO: Check wether this is still the case with @laurci
21-
echo "Restarting the machines..."
22-
lttle machine restart --ns docs nginx-docs
23-
lttle machine restart --ns docs typesense-search
24-
lttle machine restart --ns docs typesense-scraper
20+
docsURL="https://"$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'docs.lttle.aifrim.com' : 'docs-' + env.GITHUB_HEAD_REF + '-lttle-aifrim.eu.lttle.host'");
21+
typesenseFQDN=$(lttle deploy --eval "env.GITHUB_HEAD_REF == 'main' ? 'docs-search.lttle.aifrim.com' : 'docs-search-' + env.GITHUB_HEAD_REF + '-lttle-aifrim.eu.lttle.host'")
22+
23+
deployDocs "$namespace" "$tag" "$docsURL" "$typesenseFQDN"
24+
deployTypeSense "$namespace" "$tag" "$docsURL"

deploy/utilities.bash

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/bin/bash
2+
3+
deployDocs() {
4+
local ns="$1"
5+
local tag="$2"
6+
local docsURL="$3"
7+
local typesenseFQDN="$4"
8+
9+
echo "Building the aifrim/lttle-docs:$tag image..."
10+
docker build --build-arg DOCS_URL="$docsURL" --build-arg TYPESENSE_FQDN="$typesenseFQDN" --build-arg TYPESENSE_API_KEY="$TYPESENSE_API_KEY" -f ./docker/dockerfile . -t aifrim/lttle-docs:$tag
11+
12+
echo "Pushing the aifrim/lttle-docs:$tag image..."
13+
docker push aifrim/lttle-docs:$tag
14+
15+
echo "Deploying only the nginx-docs"
16+
lttle deploy ./lttle/docs.lttle.yaml
17+
18+
echo "Restarting the machine in namespace $ns..."
19+
lttle machine restart --ns $ns nginx-docs
20+
}
21+
22+
deployTypeSense() {
23+
local ns="$1"
24+
local tag="$2"
25+
local docsURL="$3"
26+
27+
if [[ $ns != 'main' ]]; then
28+
echo "Backing up & patching ./docker/typesense-production.config.json"
29+
30+
# Need to patch ./docker/typesense-production.config.json to scrape preview environment url
31+
cp ./docker/typesense-scraper.production.config.json ./docker/typesense-scraper.production.config.json.bak
32+
jq --arg url "$docsURL" '.start_urls[0].url = $url' ./docker/typesense-scraper.production.config.json.bak > ./docker/typesense-scraper.production.config.json
33+
fi
34+
35+
echo "Building the aifrim/typesense-scraper:$tag image..."
36+
37+
echo "Using config";
38+
cat ./docker/typesense-scraper.production.config.json
39+
40+
docker build -f ./docker/typesense-scraper.dockerfile docker -t aifrim/typesense-scraper:$tag
41+
42+
if [[ $ns != 'main' ]]; then
43+
echo "Restoring ./docker/typesense-scraper.production.config.json"
44+
cp ./docker/typesense-scraper.production.config.json.bak ./docker/typesense-scraper.production.config.json
45+
rm ./docker/typesense-scraper.production.config.json.bak
46+
fi
47+
48+
echo "Pushing the aifrim/typesense-scraper:$tag image..."
49+
docker push aifrim/typesense-scraper:$tag
50+
51+
echo "Deploying only the typesense-search"
52+
lttle deploy ./lttle/typesense.lttle.yaml
53+
54+
restartMachines "$ns"
55+
}
56+
57+
restartMachines() {
58+
local ns="$1"
59+
60+
echo "Restarting the machine in namespace $ns..."
61+
62+
lttle machine restart --ns $ns nginx-docs
63+
lttle machine restart --ns $ns typesense-search
64+
lttle machine restart --ns $ns typesense-scraper
65+
}
66+
67+
isUp() {
68+
local url="$1"
69+
local timeout="$2"
70+
local sleep="$3"
71+
72+
START=$(date +%s)
73+
74+
while true; do
75+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$url")
76+
77+
if [ "$STATUS" -eq 200 ]; then
78+
echo "$url is up (HTTP 200)"
79+
return 0
80+
fi
81+
82+
NOW=$(date +%s)
83+
ELAPSED=$((NOW - START))
84+
85+
if [ "$ELAPSED" -ge "$timeout" ]; then
86+
echo "❌ Timeout reached ($timeout seconds). $url did not return 200."
87+
return 1
88+
fi
89+
90+
echo "$url not ready yet (status: $STATUS). Retrying in $sleep seconds..."
91+
sleep $sleep
92+
done
93+
}

docker/dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ FROM node:22.18.0-alpine3.22 AS build
33

44
WORKDIR /build
55

6+
ARG DOCS_URL
7+
ARG TYPESENSE_FQDN
8+
ARG TYPESENSE_API_KEY
9+
10+
ENV DOCS_URL=$DOCS_URL \
11+
TYPESENSE_FQDN=$TYPESENSE_FQDN \
12+
TYPESENSE_API_KEY=$TYPESENSE_API_KEY
13+
614
COPY . .
715

816
RUN npm install --frozen-lockfile

docker/typesense-scraper.config.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
{
22
"index_name": "lttle-cloud-docs",
3-
"allowed_domains": [
4-
"host.docker.internal"
5-
],
3+
"allowed_domains": ["host.docker.internal"],
64
"start_urls": [
75
{
86
"url": "http://host.docker.internal:3000/"
@@ -19,4 +17,4 @@
1917
"text": "p, li"
2018
},
2119
"nb_hits": 182
22-
}
20+
}

0 commit comments

Comments
 (0)