ci: build beta Docker images from source
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
.git
|
||||||
|
.dev
|
||||||
|
.playwright-mcp
|
||||||
|
.paseo
|
||||||
|
.tasks
|
||||||
|
.wrangler
|
||||||
|
**/.wrangler
|
||||||
|
**/.tanstack
|
||||||
|
**/node_modules
|
||||||
|
**/dist
|
||||||
|
**/build
|
||||||
|
**/.cache
|
||||||
|
**/.expo
|
||||||
|
**/test-results
|
||||||
|
**/*.tsbuildinfo
|
||||||
|
artifacts
|
||||||
|
packages/app/android
|
||||||
|
packages/desktop/release
|
||||||
|
plan.*.log
|
||||||
|
*.log
|
||||||
|
CLAUDE.local.md
|
||||||
@@ -32,6 +32,7 @@ jobs:
|
|||||||
image: ${{ steps.values.outputs.image }}
|
image: ${{ steps.values.outputs.image }}
|
||||||
install_version: ${{ steps.values.outputs.install_version }}
|
install_version: ${{ steps.values.outputs.install_version }}
|
||||||
publish: ${{ steps.values.outputs.publish }}
|
publish: ${{ steps.values.outputs.publish }}
|
||||||
|
source_build: ${{ steps.values.outputs.source_build }}
|
||||||
check_tag: ${{ steps.values.outputs.check_tag }}
|
check_tag: ${{ steps.values.outputs.check_tag }}
|
||||||
publish_tags: ${{ steps.values.outputs.publish_tags }}
|
publish_tags: ${{ steps.values.outputs.publish_tags }}
|
||||||
steps:
|
steps:
|
||||||
@@ -49,28 +50,37 @@ jobs:
|
|||||||
image="ghcr.io/${owner}/paseo"
|
image="ghcr.io/${owner}/paseo"
|
||||||
install_version="${INPUT_PASEO_VERSION:-latest}"
|
install_version="${INPUT_PASEO_VERSION:-latest}"
|
||||||
publish=false
|
publish=false
|
||||||
|
source_build=false
|
||||||
|
prerelease=false
|
||||||
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
|
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
|
||||||
install_version="${REF_NAME#v}"
|
install_version="${REF_NAME#v}"
|
||||||
if [[ "${REF_NAME}" != *-* ]]; then
|
publish=true
|
||||||
publish=true
|
if [[ "${REF_NAME}" == *-* ]]; then
|
||||||
|
prerelease=true
|
||||||
|
source_build=true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
check_tag="${image}:check-${GITHUB_SHA::12}"
|
check_tag="${image}:check-${GITHUB_SHA::12}"
|
||||||
publish_tags="${image}:${install_version}"$'\n'"${image}:latest"
|
if [[ "${prerelease}" == "true" ]]; then
|
||||||
|
publish_tags="${image}:${install_version}"
|
||||||
|
else
|
||||||
|
publish_tags="${image}:${install_version}"$'\n'"${image}:latest"
|
||||||
|
fi
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "image=${image}"
|
echo "image=${image}"
|
||||||
echo "install_version=${install_version}"
|
echo "install_version=${install_version}"
|
||||||
echo "publish=${publish}"
|
echo "publish=${publish}"
|
||||||
|
echo "source_build=${source_build}"
|
||||||
echo "check_tag=${check_tag}"
|
echo "check_tag=${check_tag}"
|
||||||
echo "publish_tags<<EOF"
|
echo "publish_tags<<EOF"
|
||||||
echo "${publish_tags}"
|
echo "${publish_tags}"
|
||||||
echo "EOF"
|
echo "EOF"
|
||||||
} >> "$GITHUB_OUTPUT"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
echo "Resolved image=${image} install_version=${install_version} publish=${publish}"
|
echo "Resolved image=${image} install_version=${install_version} publish=${publish} source_build=${source_build}"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: setup
|
needs: setup
|
||||||
@@ -86,8 +96,8 @@ jobs:
|
|||||||
|
|
||||||
- uses: docker/build-push-action@v7
|
- uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: docker/base
|
context: ${{ needs.setup.outputs.source_build == 'true' && '.' || 'docker/base' }}
|
||||||
file: docker/base/Dockerfile
|
file: ${{ needs.setup.outputs.source_build == 'true' && 'docker/base/Dockerfile.source' || 'docker/base/Dockerfile' }}
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
build-args: |
|
build-args: |
|
||||||
PASEO_VERSION=${{ needs.setup.outputs.install_version }}
|
PASEO_VERSION=${{ needs.setup.outputs.install_version }}
|
||||||
@@ -119,8 +129,8 @@ jobs:
|
|||||||
|
|
||||||
- uses: docker/build-push-action@v7
|
- uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: docker/base
|
context: ${{ needs.setup.outputs.source_build == 'true' && '.' || 'docker/base' }}
|
||||||
file: docker/base/Dockerfile
|
file: ${{ needs.setup.outputs.source_build == 'true' && 'docker/base/Dockerfile.source' || 'docker/base/Dockerfile' }}
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
build-args: |
|
build-args: |
|
||||||
PASEO_VERSION=${{ needs.setup.outputs.install_version }}
|
PASEO_VERSION=${{ needs.setup.outputs.install_version }}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
ARG NODE_IMAGE=node:22-bookworm-slim
|
||||||
|
FROM --platform=$BUILDPLATFORM ${NODE_IMAGE} AS source-pack
|
||||||
|
|
||||||
|
ARG PASEO_VERSION
|
||||||
|
|
||||||
|
ENV ONNXRUNTIME_NODE_INSTALL=skip
|
||||||
|
|
||||||
|
WORKDIR /tmp/paseo-src
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
test "$(node -p "require('./package.json').version")" = "${PASEO_VERSION}"; \
|
||||||
|
node -e 'const fs=require("node:fs"); const pkg=JSON.parse(fs.readFileSync("package.json","utf8")); delete pkg.scripts.prepare; fs.writeFileSync("package.json", `${JSON.stringify(pkg)}\n`);'; \
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
mkdir -p /tmp/paseo-packs; \
|
||||||
|
npm pack --workspace=@getpaseo/highlight --pack-destination /tmp/paseo-packs; \
|
||||||
|
npm pack --workspace=@getpaseo/relay --pack-destination /tmp/paseo-packs; \
|
||||||
|
npm pack --workspace=@getpaseo/protocol --pack-destination /tmp/paseo-packs; \
|
||||||
|
npm pack --workspace=@getpaseo/client --pack-destination /tmp/paseo-packs; \
|
||||||
|
npm pack --workspace=@getpaseo/server --pack-destination /tmp/paseo-packs; \
|
||||||
|
npm pack --workspace=@getpaseo/cli --pack-destination /tmp/paseo-packs
|
||||||
|
|
||||||
|
FROM ${NODE_IMAGE}
|
||||||
|
|
||||||
|
ENV HOME=/home/paseo \
|
||||||
|
PASEO_HOME=/home/paseo/.paseo \
|
||||||
|
PASEO_LISTEN=0.0.0.0:6767 \
|
||||||
|
PASEO_WEB_UI_ENABLED=true \
|
||||||
|
PASEO_LOG_FORMAT=json \
|
||||||
|
PASEO_LOG_LEVEL=info \
|
||||||
|
CLAUDE_CONFIG_DIR=/home/paseo/.claude \
|
||||||
|
CODEX_HOME=/home/paseo/.codex \
|
||||||
|
XDG_CONFIG_HOME=/home/paseo/.config \
|
||||||
|
XDG_DATA_HOME=/home/paseo/.local/share \
|
||||||
|
XDG_STATE_HOME=/home/paseo/.local/state \
|
||||||
|
XDG_CACHE_HOME=/home/paseo/.cache \
|
||||||
|
ONNXRUNTIME_NODE_INSTALL=skip
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
bash \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
gosu \
|
||||||
|
openssh-client \
|
||||||
|
tini; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=source-pack /tmp/paseo-packs /tmp/paseo-packs
|
||||||
|
RUN set -eux; \
|
||||||
|
npm install -g --omit=optional /tmp/paseo-packs/*.tgz; \
|
||||||
|
rm -rf /tmp/paseo-packs; \
|
||||||
|
npm cache clean --force; \
|
||||||
|
server_entry="$(npm root -g)/@getpaseo/server/dist/scripts/supervisor-entrypoint.js"; \
|
||||||
|
test -f "$server_entry"; \
|
||||||
|
printf '%s\n' "$server_entry" > /etc/paseo-server-entry; \
|
||||||
|
node --check "$server_entry"
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
existing_group="$(getent group 1000 | cut -d: -f1 || true)"; \
|
||||||
|
if [ -n "$existing_group" ] && [ "$existing_group" != "paseo" ]; then \
|
||||||
|
groupmod --new-name paseo "$existing_group"; \
|
||||||
|
elif [ -z "$existing_group" ]; then \
|
||||||
|
groupadd --gid 1000 paseo; \
|
||||||
|
fi; \
|
||||||
|
existing_user="$(getent passwd 1000 | cut -d: -f1 || true)"; \
|
||||||
|
if [ -n "$existing_user" ] && [ "$existing_user" != "paseo" ]; then \
|
||||||
|
usermod --login paseo --gid paseo --home /home/paseo --shell /bin/bash "$existing_user"; \
|
||||||
|
elif [ -z "$existing_user" ]; then \
|
||||||
|
useradd --uid 1000 --gid paseo --create-home --home-dir /home/paseo --shell /bin/bash paseo; \
|
||||||
|
fi; \
|
||||||
|
mkdir -p \
|
||||||
|
/workspace \
|
||||||
|
"$PASEO_HOME" \
|
||||||
|
"$CLAUDE_CONFIG_DIR" \
|
||||||
|
"$CODEX_HOME" \
|
||||||
|
"$XDG_CONFIG_HOME" \
|
||||||
|
"$XDG_DATA_HOME" \
|
||||||
|
"$XDG_STATE_HOME" \
|
||||||
|
"$XDG_CACHE_HOME"; \
|
||||||
|
chown -R paseo:paseo /home/paseo /workspace
|
||||||
|
|
||||||
|
COPY docker/base/rootfs/ /
|
||||||
|
RUN chmod +x /usr/local/bin/paseo-docker-entrypoint
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
EXPOSE 6767
|
||||||
|
VOLUME ["/home/paseo"]
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
|
||||||
|
CMD node -e "const listen=process.env.PASEO_LISTEN||'0.0.0.0:6767'; const m=listen.match(/:(\\d+)$/); const port=m?Number(m[1]):6767; require('http').get({hostname:'127.0.0.1',port,path:'/api/health'},r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/paseo-docker-entrypoint"]
|
||||||
+1
-1
@@ -50,7 +50,7 @@ npm run release:patch
|
|||||||
|
|
||||||
This bumps the version across all workspaces, runs checks, publishes to npm, and pushes the branch + tag. The tag push triggers `Desktop Release`, `Android APK Release`, `Docker`, and `Release Notes Sync` on GitHub Actions. EAS picks up the same tag via the EAS GitHub app and starts the iOS + Android store builds in parallel (see "Mobile builds (EAS)" below) — there is no `release-mobile.yml` in this repo.
|
This bumps the version across all workspaces, runs checks, publishes to npm, and pushes the branch + tag. The tag push triggers `Desktop Release`, `Android APK Release`, `Docker`, and `Release Notes Sync` on GitHub Actions. EAS picks up the same tag via the EAS GitHub app and starts the iOS + Android store builds in parallel (see "Mobile builds (EAS)" below) — there is no `release-mobile.yml` in this repo.
|
||||||
|
|
||||||
The Docker workflow builds images on pull requests and on `main` as non-publishing checks. Only stable `vX.Y.Z` tag pushes publish `ghcr.io/getpaseo/paseo:X.Y.Z` and `ghcr.io/getpaseo/paseo:latest`; beta tags and manual workflow dispatches build for validation only.
|
The Docker workflow builds images on pull requests and on `main` as non-publishing checks. Stable `vX.Y.Z` tag pushes publish `ghcr.io/getpaseo/paseo:X.Y.Z` and `ghcr.io/getpaseo/paseo:latest`; beta `vX.Y.Z-beta.N` tag pushes publish only `ghcr.io/getpaseo/paseo:X.Y.Z-beta.N` and never move `latest`. Beta Docker images build from the checked-out source tree so the beta flow can intentionally skip npm publishing.
|
||||||
|
|
||||||
**Releases are always patch.** "Release paseo", "release stable", "ship stable", and similar always mean a patch bump from the previous stable. Never bump minor or major to trigger a build, ever — minor and major bumps are reserved for genuinely larger product cuts and require an explicit user instruction with the word "minor" or "major". If you find yourself reaching for `release:minor` to retrigger a failed build, you are doing the wrong thing — push a retry tag instead (see "Fixing a failed release build" below).
|
**Releases are always patch.** "Release paseo", "release stable", "ship stable", and similar always mean a patch bump from the previous stable. Never bump minor or major to trigger a build, ever — minor and major bumps are reserved for genuinely larger product cuts and require an explicit user instruction with the word "minor" or "major". If you find yourself reaching for `release:minor` to retrigger a failed build, you are doing the wrong thing — push a retry tag instead (see "Fixing a failed release build" below).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user