-
-
Notifications
You must be signed in to change notification settings - Fork 11
chore: Release CLI as a docker image #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
21df395
55c29e5
5e88d34
732c58e
4facf48
6e101b8
dcbecd1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,11 @@ jobs: | |
|
|
||
| - name: Build the CLI | ||
| run: npm run build | ||
|
|
||
| - name: Store version before release | ||
| id: version-before | ||
| run: echo "VERSION=$(node -p 'require("./package.json").version')" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Run npm release | ||
| run: npm run release | ||
| env: | ||
|
|
@@ -45,3 +50,28 @@ jobs: | |
| GIT_AUTHOR_EMAIL: [email protected] | ||
| GIT_COMMITTER_NAME: Tolgee Machine | ||
| GIT_COMMITTER_EMAIL: [email protected] | ||
|
|
||
| - name: Extract version after release | ||
| id: version-after | ||
| run: echo "VERSION=$(node -p 'require("./package.json").version')" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Check if version was released | ||
| id: version-check | ||
| run: | | ||
| if [ "${{ steps.version-before.outputs.VERSION }}" != "${{ steps.version-after.outputs.VERSION }}" ]; then | ||
| echo "RELEASED=true" >> "$GITHUB_OUTPUT" | ||
| echo "New version released: ${{ steps.version-before.outputs.VERSION }} -> ${{ steps.version-after.outputs.VERSION }}" | ||
| else | ||
| echo "RELEASED=false" >> "$GITHUB_OUTPUT" | ||
| echo "No new version released (version remains ${{ steps.version-before.outputs.VERSION }})" | ||
| fi | ||
|
|
||
| - name: Build and push Docker image | ||
| if: steps.version-check.outputs.RELEASED == 'true' | ||
| run: ./scripts/build-docker.sh latest linux/amd64,linux/arm64 push | ||
| env: | ||
| DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_PASSWORD }} | ||
| VERSION: ${{ steps.version-after.outputs.VERSION }} | ||
| GITHUB_SHA: ${{ github.event.workflow_run.head_sha || github.sha }} | ||
| BUILD_DATE: ${{ github.event.workflow_run.run_started_at || github.event.workflow_run.head_commit.timestamp }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Multi-stage Docker build for Tolgee CLI | ||
| # Stage 1: Build stage with dev dependencies | ||
| FROM node:24-alpine AS builder | ||
|
|
||
| # Set working directory | ||
| WORKDIR /app | ||
|
|
||
| # Copy package files first for better Docker layer caching | ||
| COPY package*.json ./ | ||
|
|
||
| # Install ALL dependencies (including dev dependencies needed for building) | ||
| RUN npm ci && npm cache clean --force | ||
|
|
||
| # Copy source files | ||
| COPY src/ ./src/ | ||
| COPY scripts/ ./scripts/ | ||
| COPY tsconfig*.json ./ | ||
|
|
||
| # Copy additional files needed for build | ||
| COPY textmate/ ./textmate/ | ||
| COPY extractor.d.ts ./ | ||
| COPY schema.json ./ | ||
|
|
||
| # Build the CLI | ||
| RUN npm run build | ||
|
|
||
| # Stage 2: Production stage with only runtime dependencies | ||
| FROM node:24-alpine AS production | ||
|
|
||
| # Set working directory | ||
| WORKDIR /app | ||
|
|
||
| # Copy package files first for better Docker layer caching | ||
| COPY package*.json ./ | ||
|
|
||
| # Install ONLY production dependencies | ||
| RUN npm ci --only=production && npm cache clean --force | ||
|
|
||
| # Copy built application files from builder stage | ||
| COPY --from=builder /app/dist/ ./dist/ | ||
| COPY --from=builder /app/textmate/ ./textmate/ | ||
| COPY --from=builder /app/extractor.d.ts ./ | ||
| COPY --from=builder /app/schema.json ./ | ||
|
|
||
| # Copy documentation files | ||
| COPY README.md ./ | ||
| COPY LICENSE ./ | ||
|
|
||
| # Make the CLI binary executable | ||
| RUN chmod +x ./dist/cli.js | ||
|
|
||
| # Create a non-root user for security | ||
| RUN addgroup -g 1001 -S tolgee && \ | ||
| adduser -S tolgee -u 1001 | ||
|
|
||
| # Switch to non-root user | ||
| USER tolgee | ||
|
|
||
| # Set the entrypoint to the CLI binary | ||
| ENTRYPOINT ["node", "./dist/cli.js"] | ||
|
|
||
| # Default command shows help | ||
| CMD ["--help"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ to get some work done. | |
|
|
||
| ## Toolchain | ||
|
|
||
| To work on this project, you will just need Node 16+ (and Docker to run tests). We use `npm` to manage dependencies, | ||
| To work on this project, you will just need Node 22+ (and Docker to run tests). We use `npm` to manage dependencies, | ||
| and [prettier](https://github.com/prettier/prettier) to lint our code. | ||
|
|
||
| ## Scripts | ||
|
|
@@ -47,6 +47,31 @@ TOLGEE_TEST_BACKEND_URL=http://localhost:8080 npm run test:e2e | |
|
|
||
| When this environment variable is set, the Docker backend will not be started, and tests will use the specified URL instead. | ||
|
|
||
| ## Building Docker Images | ||
|
|
||
| The project includes Docker support for containerized deployment. The Docker setup consists of: | ||
|
|
||
| - `Dockerfile`: Multi-stage build configuration using Node.js 22 Alpine | ||
| - `scripts/build-docker.sh`: Comprehensive build script with multi-platform support | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| - Docker installed and running | ||
| - For multi-platform builds: Docker Buildx | ||
| - For pushing images: Docker Hub credentials | ||
|
|
||
| ### Building Docker Images | ||
|
|
||
| The `scripts/build-docker.sh` script provides several build options: | ||
|
|
||
| **Basic build (current platform only):** | ||
|
|
||
| ```bash | ||
| ./scripts/build-docker.sh | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could the command be added to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, thanks for the feedback. I was thinking about writing it in JS so it's multiplatform. But I am not sure about running bash scripts via npm run... AFAIK, it can break on Windows... I don't think it's something devs would use often and if they search for it it's in the docs... 🤷♂️ |
||
| ``` | ||
|
|
||
| More information about possible build options is documented in the `build-docker.sh`. | ||
|
|
||
JanCizmar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ## Code & internals overview | ||
|
|
||
| ### Command parsing | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Build Docker image for Tolgee CLI | ||
| # Usage: | ||
| # ./scripts/build-docker.sh [tag] [platform] [push] | ||
| # | ||
| # Examples: | ||
| # ./scripts/build-docker.sh # Build for current platform with default tag | ||
| # ./scripts/build-docker.sh latest # Build for current platform with specific tag | ||
| # ./scripts/build-docker.sh latest linux/arm64 # Build for specific single platform (available locally) | ||
| # ./scripts/build-docker.sh latest linux/amd64,linux/arm64 # Multi-platform build (NOT available locally) | ||
| # ./scripts/build-docker.sh latest linux/amd64,linux/arm64 push # Multi-platform build and push | ||
| # | ||
| # Environment variables for push: | ||
| # DOCKERHUB_USERNAME - Docker Hub username | ||
| # DOCKERHUB_TOKEN - Docker Hub token/password | ||
| # VERSION - Version for additional tagging (optional) | ||
| # | ||
| # Note: Multi-platform builds are stored in buildx cache and not available locally. | ||
| # To run the image locally after a multi-platform build, either: | ||
| # 1. Build for your current platform only (e.g., linux/arm64 on Apple Silicon) | ||
| # 2. Push the multi-platform image to a registry and pull it | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # Default values | ||
| TAG=${1:-"dev"} | ||
| PLATFORM=${2:-""} | ||
| PUSH=${3:-""} | ||
| IMAGE_NAME="tolgee/cli" | ||
|
|
||
| # Colors for output | ||
| RED='\033[0;31m' | ||
| GREEN='\033[0;32m' | ||
| YELLOW='\033[1;33m' | ||
| NC='\033[0m' # No Color | ||
|
|
||
| echo -e "${GREEN}Building Tolgee CLI Docker image...${NC}" | ||
| echo "Tag: ${TAG}" | ||
| echo "Image: ${IMAGE_NAME}:${TAG}" | ||
|
|
||
| # Check if Docker is running | ||
| if ! docker info > /dev/null 2>&1; then | ||
| echo -e "${RED}Error: Docker is not running. Please start Docker and try again.${NC}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Docker login if push is requested | ||
| if [ "$PUSH" = "push" ]; then | ||
| if [ -z "${DOCKERHUB_USERNAME:-}" ] || [ -z "${DOCKERHUB_TOKEN:-}" ]; then | ||
| echo -e "${RED}Error: DOCKERHUB_USERNAME and DOCKERHUB_TOKEN environment variables are required for push.${NC}" | ||
| exit 1 | ||
| fi | ||
| echo -e "${GREEN}Logging in to Docker Hub...${NC}" | ||
| echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin | ||
| fi | ||
|
|
||
| # Ensure we have the built files | ||
| if [ ! -d "dist" ]; then | ||
| echo -e "${YELLOW}Warning: dist directory not found. Building the CLI first...${NC}" | ||
| npm run build | ||
| fi | ||
|
|
||
| # Prepare tags | ||
| TAGS=( -t "${IMAGE_NAME}:${TAG}" ) | ||
| if [ -n "${VERSION:-}" ] && [ "$TAG" = "latest" ]; then | ||
| TAGS+=( -t "${IMAGE_NAME}:${VERSION}" ) | ||
| fi | ||
|
|
||
| # Prepare labels | ||
| LABELS=() | ||
| if [ "$PUSH" = "push" ]; then | ||
| LABELS+=( --label "org.opencontainers.image.title=Tolgee CLI" ) | ||
| LABELS+=( --label "org.opencontainers.image.description=A tool to interact with the Tolgee Platform through CLI" ) | ||
| LABELS+=( --label "org.opencontainers.image.url=https://github.com/tolgee/tolgee-cli" ) | ||
| LABELS+=( --label "org.opencontainers.image.source=https://github.com/tolgee/tolgee-cli" ) | ||
| LABELS+=( --label "org.opencontainers.image.licenses=MIT" ) | ||
| if [ -n "${VERSION:-}" ]; then | ||
| LABELS+=( --label "org.opencontainers.image.version=${VERSION}" ) | ||
| fi | ||
| if [ -n "${GITHUB_SHA:-}" ]; then | ||
| LABELS+=( --label "org.opencontainers.image.revision=${GITHUB_SHA}" ) | ||
| fi | ||
| if [ -n "${BUILD_DATE:-}" ]; then | ||
| LABELS+=( --label "org.opencontainers.image.created=${BUILD_DATE}" ) | ||
| fi | ||
| fi | ||
|
|
||
| # Build command | ||
| BUILD_CMD=( docker build ) | ||
| BUILD_CMD+=( "${TAGS[@]}" ) | ||
| if [ ${#LABELS[@]} -gt 0 ]; then | ||
| BUILD_CMD+=( "${LABELS[@]}" ) | ||
| fi | ||
|
|
||
| if [ -n "$PLATFORM" ]; then | ||
| echo "Platform(s): ${PLATFORM}" | ||
| # For multi-platform builds, we need buildx | ||
| BUILD_CMD=( docker buildx build --platform "${PLATFORM}" ) | ||
| BUILD_CMD+=( "${TAGS[@]}" ) | ||
| if [ ${#LABELS[@]} -gt 0 ]; then | ||
| BUILD_CMD+=( "${LABELS[@]}" ) | ||
| fi | ||
|
|
||
| # Check if buildx is available | ||
| if ! docker buildx version > /dev/null 2>&1; then | ||
| echo -e "${RED}Error: Docker buildx is required for multi-platform builds.${NC}" | ||
| echo "Please install Docker buildx or build for single platform." | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Create builder if it doesn't exist | ||
| if ! docker buildx inspect tolgee-builder > /dev/null 2>&1; then | ||
| echo -e "${YELLOW}Creating multi-platform builder...${NC}" | ||
| docker buildx create --name tolgee-builder --use | ||
| else | ||
| docker buildx use tolgee-builder | ||
| fi | ||
|
|
||
| # Check if this is a single platform build that can be loaded locally | ||
| PLATFORM_COUNT=$(echo "$PLATFORM" | tr ',' '\n' | wc -l) | ||
| if [ "$PLATFORM_COUNT" -eq 1 ] && [ "$PUSH" != "push" ]; then | ||
| # Single platform - we can load it to local Docker daemon | ||
| BUILD_CMD+=( --load ) | ||
| echo -e "${GREEN}Single platform build - image will be available locally after build.${NC}" | ||
| elif [ "$PUSH" = "push" ]; then | ||
| # Push mode - add push flag | ||
| BUILD_CMD+=( --push ) | ||
| echo -e "${GREEN}Build and push mode enabled.${NC}" | ||
| else | ||
| # Multi-platform build - cannot load to local Docker daemon | ||
| echo -e "${YELLOW}Multi-platform build - image will NOT be available locally.${NC}" | ||
| echo -e "${YELLOW}To run locally, build for your current platform only or push to a registry.${NC}" | ||
| fi | ||
| elif [ "$PUSH" = "push" ]; then | ||
| # Regular build with push - we need to build and then push | ||
| echo -e "${GREEN}Build and push mode enabled for single architecture.${NC}" | ||
| fi | ||
|
|
||
| BUILD_CMD+=( . ) | ||
|
|
||
| echo -e "${GREEN}Running:${NC} ${BUILD_CMD[*]}" | ||
| "${BUILD_CMD[@]}" | ||
|
|
||
| if [ "$PUSH" = "push" ] && [ -z "$PLATFORM" ]; then | ||
| # For regular builds, we need to push separately | ||
| echo -e "${GREEN}Pushing images to registry...${NC}" | ||
| docker push ${IMAGE_NAME}:${TAG} | ||
| if [ -n "${VERSION:-}" ] && [ "$TAG" = "latest" ]; then | ||
| docker push ${IMAGE_NAME}:${VERSION} | ||
| fi | ||
| fi | ||
|
|
||
| if [ "$PUSH" = "push" ]; then | ||
| echo -e "${GREEN}✓ Docker image built and pushed successfully!${NC}" | ||
| else | ||
| echo -e "${GREEN}✓ Docker image built successfully!${NC}" | ||
| fi | ||
|
|
||
| # Show appropriate run instruction based on build type | ||
| if [ -n "$PLATFORM" ]; then | ||
| PLATFORM_COUNT=$(echo "$PLATFORM" | tr ',' '\n' | wc -l) | ||
| if [ "$PLATFORM_COUNT" -eq 1 ]; then | ||
| # Single platform - image is available locally | ||
| echo -e "${GREEN}Run with: docker run --rm ${IMAGE_NAME}:${TAG}${NC}" | ||
| else | ||
| # Multi-platform - image is NOT available locally | ||
| echo -e "${YELLOW}Multi-platform build completed. Image is not available locally.${NC}" | ||
| echo -e "${YELLOW}To run locally: build for your platform only or pull from registry after push.${NC}" | ||
| fi | ||
| else | ||
| # Default build for current platform - always available locally | ||
| echo -e "${GREEN}Run with: docker run --rm ${IMAGE_NAME}:${TAG}${NC}" | ||
| fi | ||
|
|
||
| # Show image info | ||
| echo -e "\n${YELLOW}Image information:${NC}" | ||
| if [ -n "$PLATFORM" ]; then | ||
| PLATFORM_COUNT=$(echo "$PLATFORM" | tr ',' '\n' | wc -l) | ||
| if [ "$PLATFORM_COUNT" -eq 1 ]; then | ||
| echo "Single-platform image built and loaded locally." | ||
| docker images ${IMAGE_NAME}:${TAG} | ||
| else | ||
| echo "Multi-platform image built. Use 'docker buildx imagetools inspect ${IMAGE_NAME}:${TAG}' to see details." | ||
| echo "Note: Multi-platform images are not available locally. Build for your current platform to run locally." | ||
| fi | ||
| else | ||
| docker images ${IMAGE_NAME}:${TAG} | ||
| fi |
Uh oh!
There was an error while loading. Please reload this page.