diff --git a/.github/uffizzi/Dockerfile b/.github/uffizzi/Dockerfile new file mode 100644 index 000000000..ae2b8231e --- /dev/null +++ b/.github/uffizzi/Dockerfile @@ -0,0 +1,47 @@ +# Compile +FROM rust:alpine3.16 AS compiler + +RUN apk add -q --update-cache --no-cache build-base openssl-dev + +WORKDIR /meilisearch + +ARG COMMIT_SHA +ARG COMMIT_DATE +ENV COMMIT_SHA=${COMMIT_SHA} COMMIT_DATE=${COMMIT_DATE} +ENV RUSTFLAGS="-C target-feature=-crt-static" + +COPY . . +RUN set -eux; \ + apkArch="$(apk --print-arch)"; \ + if [ "$apkArch" = "aarch64" ]; then \ + export JEMALLOC_SYS_WITH_LG_PAGE=16; \ + fi && \ + cargo build --release + +# Run +FROM uffizzi/ttyd:alpine + +ENV MEILI_HTTP_ADDR 0.0.0.0:7700 +ENV MEILI_SERVER_PROVIDER docker +ENV MEILI_NO_ANALYTICS true + +RUN apk update --quiet \ + && apk add -q --no-cache libgcc tini curl + +# add meilisearch to the `/bin` so you can run it from anywhere and it's easy +# to find. +COPY --from=compiler /meilisearch/target/release/meilisearch /bin/meilisearch +# To stay compatible with the older version of the container (pre v0.27.0) we're +# going to symlink the meilisearch binary in the path to `/meilisearch` +RUN ln -s /bin/meilisearch /meilisearch + +# This directory should hold all the data related to meilisearch so we're going +# to move our PWD in there. +# We don't want to put the meilisearch binary +WORKDIR /meili_data + + +EXPOSE 7700/tcp + +ENTRYPOINT ["tini", "--"] +CMD ["ttyd", "/bin/zsh"] diff --git a/.github/uffizzi/docker-compose.uffizzi.yml b/.github/uffizzi/docker-compose.uffizzi.yml new file mode 100644 index 000000000..17f241238 --- /dev/null +++ b/.github/uffizzi/docker-compose.uffizzi.yml @@ -0,0 +1,26 @@ +version: "3" + +x-uffizzi: + ingress: + service: nginx + port: 8081 + +services: + meilisearch: + image: "${MEILISEARCH_IMAGE}" + restart: unless-stopped + ports: + - "7681:7681" + - "7700:7700" + deploy: + resources: + limits: + memory: 500M + + nginx: + image: nginx:alpine + restart: unless-stopped + ports: + - "8081:8081" + volumes: + - ./.github/uffizzi/nginx:/etc/nginx diff --git a/.github/uffizzi/nginx/nginx.conf b/.github/uffizzi/nginx/nginx.conf new file mode 100644 index 000000000..6eca6b6f0 --- /dev/null +++ b/.github/uffizzi/nginx/nginx.conf @@ -0,0 +1,28 @@ + +events { + worker_connections 4096; ## Default: 1024 +} + +http { + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + server { + listen 8081; + + location / { + proxy_pass http://localhost:7681; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + } + + location /meilisearch/ { + # rewrite /meilisearch/(.*) /$1 break; + proxy_pass http://localhost:7700/; + } + } +} + diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml new file mode 100644 index 000000000..6051b0cdd --- /dev/null +++ b/.github/workflows/uffizzi-build.yml @@ -0,0 +1,100 @@ +name: Uffizzi - Build PR Image +on: + pull_request: + types: [opened,synchronize,reopened,closed] + +jobs: + build-meilisearch: + name: Build and push `meilisearch` + runs-on: ubuntu-latest + outputs: + tags: ${{ steps.meta.outputs.tags }} + if: ${{ github.event.action != 'closed' }} + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Generate UUID image name + id: uuid + run: echo "UUID_TAG=$(uuidgen)" >> $GITHUB_ENV + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v3 + with: + images: registry.uffizzi.com/${{ env.UUID_TAG }} + tags: | + type=raw,value=60d + + - name: Build Image + uses: docker/build-push-action@v3 + with: + context: ./ + file: .github/uffizzi/Dockerfile + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + + render-compose-file: + name: Render Docker Compose File + # Pass output of this workflow to another triggered by `workflow_run` event. + runs-on: ubuntu-latest + needs: + - build-meilisearch + outputs: + compose-file-cache-key: ${{ env.COMPOSE_FILE_HASH }} + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + - name: Render Compose File + run: | + MEILISEARCH_IMAGE=$(echo ${{ needs.build-meilisearch.outputs.tags }}) + export MEILISEARCH_IMAGE + # Render simple template from environment variables. + envsubst < .github/uffizzi/docker-compose.uffizzi.yml > docker-compose.rendered.yml + cat docker-compose.rendered.yml + - name: Upload Rendered Compose File as Artifact + uses: actions/upload-artifact@v3 + with: + name: preview-spec + path: docker-compose.rendered.yml + retention-days: 2 + - name: Serialize PR Event to File + run: | + cat << EOF > event.json + ${{ toJSON(github.event) }} + + EOF + - name: Upload PR Event as Artifact + uses: actions/upload-artifact@v3 + with: + name: preview-spec + path: event.json + retention-days: 2 + + delete-preview: + name: Call for Preview Deletion + runs-on: ubuntu-latest + if: ${{ github.event.action == 'closed' }} + steps: + # If this PR is closing, we will not render a compose file nor pass it to the next workflow. + - name: Serialize PR Event to File + run: | + cat << EOF > event.json + ${{ toJSON(github.event) }} + + EOF + - name: Upload PR Event as Artifact + uses: actions/upload-artifact@v3 + with: + name: preview-spec + path: event.json + retention-days: 2 diff --git a/.github/workflows/uffizzi-preview-deploy.yml b/.github/workflows/uffizzi-preview-deploy.yml new file mode 100644 index 000000000..8b3fdde96 --- /dev/null +++ b/.github/workflows/uffizzi-preview-deploy.yml @@ -0,0 +1,103 @@ +name: Uffizzi - Deploy Preview + +on: + workflow_run: + workflows: + - "Uffizzi - Build PR Image" + types: + - completed + +jobs: + cache-compose-file: + name: Cache Compose File + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + outputs: + compose-file-cache-key: ${{ env.COMPOSE_FILE_HASH }} + pr-number: ${{ env.PR_NUMBER }} + expected-url: ${{ env.EXPECTED_URL }} + steps: + - name: 'Download artifacts' + # Fetch output (zip archive) from the workflow run that triggered this workflow. + uses: actions/github-script@v6 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "preview-spec" + })[0]; + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + let fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); + + - name: 'Unzip artifact' + run: unzip preview-spec.zip + + - name: Read Event into ENV + run: | + echo 'EVENT_JSON<> $GITHUB_ENV + cat event.json >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Hash Rendered Compose File + id: hash + # If the previous workflow was triggered by a PR close event, we will not have a compose file artifact. + if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + run: echo "COMPOSE_FILE_HASH=$(md5sum docker-compose.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV + + - name: Cache Rendered Compose File + if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + uses: actions/cache@v3 + with: + path: docker-compose.rendered.yml + key: ${{ env.COMPOSE_FILE_HASH }} + + - name: Read PR Number From Event Object + id: pr + run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV + + - name: DEBUG - Print Job Outputs + if: ${{ runner.debug }} + run: | + echo "PR number: ${{ env.PR_NUMBER }}" + echo "Compose file hash: ${{ env.COMPOSE_FILE_HASH }}" + cat event.json + + - name: Add expected URL env var + if: ${{ runner.debug }} + run: | + REPO=$(echo ${{ github.repository }} | sed 's/\./+/g') + echo "EXPECTED_URL=${{ inputs.server }}/github.com/$REPO/pull/${{ env.PR_NUMBER }}" >> $GITHUB_ENV + + deploy-uffizzi-preview: + name: Use Remote Workflow to Preview on Uffizzi + needs: + - cache-compose-file + uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@desc + with: + # If this workflow was triggered by a PR close event, cache-key will be an empty string + # and this reusable workflow will delete the preview deployment. + compose-file-cache-key: ${{ needs.cache-compose-file.outputs.compose-file-cache-key }} + compose-file-cache-path: docker-compose.rendered.yml + server: https://app.uffizzi.com + pr-number: ${{ needs.cache-compose-file.outputs.pr-number }} + description: | + The meilisearch preview environment contains a web terminal from where you can run the + `meilisearch` command. You should be able to access this instance of meilisearch running in + the preview from the link Meilisearch Endpoint link given below. + + Web Terminal Endpoint : ${{ needs.cache-compose-file.outputs.expected-url }} + Meilisearch Endpoint : ${{ needs.cache-compose-file.outputs.expected-url }}/meilisearch + permissions: + contents: read + pull-requests: write + id-token: write \ No newline at end of file