diff --git a/Makefile b/Makefile
index 773edb95bf..932debe011 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,6 @@ LOGIN_DEPENDENCIES_TAG ?= "zitadel-login-dependencies:local"
LOGIN_IMAGE_TAG ?= "zitadel-login:local"
CORE_MOCK_TAG ?= "zitadel-core-mock:local"
LOGIN_INTEGRATION_TESTSUITE_TAG ?= "zitadel-login-integration-testsuite:local"
-CORE_MOCK_CONTAINER_NAME ?= zitadel-mock-grpc-server
-LOGIN_CONTAINER_NAME ?= zitadel-login
XDG_CACHE_HOME ?= $(HOME)/.cache
export CACHE_DIR ?= $(XDG_CACHE_HOME)/zitadel-make
@@ -12,21 +10,18 @@ export CACHE_DIR ?= $(XDG_CACHE_HOME)/zitadel-make
help:
@echo "Makefile for the login service"
@echo "Available targets:"
- @echo " help - Show this help message"
- @echo " login - Start the login service"
- @echo " login-lint - Run linting and formatting checks"
- @echo " login-lint-force - Force run linting and formatting checks"
- @echo " login-unit - Run unit tests"
- @echo " login-unit-force - Force run unit tests"
- @echo " login-integration - Run integration tests"
- @echo " login-integration-force - Force run integration tests"
- @echo " login-standalone - Build the docker image for production login containers"
- @echo " login-quality - Run all quality checks (login-lint, unit, integration)"
- @echo " login-ci - Run all CI tasks. Run it with the -j flag to parallelize. make -j ci"
- @echo " show-cache-keys - Show all cache keys with image ids and exit codes"
- @echo " clean-cache-keys - Remove all cache keys"
- @echo " core-mock - Start the core mock server"
- @echo " core-mock-stop - Stop the core mock server"
+ @echo " help - Show this help message."
+ @echo " login-lint - Run linting and formatting checks. FORCE=true prevents skipping."
+ @echo " login-lint-force - Force run linting and formatting checks."
+ @echo " login-unit - Run unit tests. FORCE=true prevents skipping."
+ @echo " login-unit-force - Force run unit tests."
+ @echo " login-integration - Run integration tests. FORCE=true prevents skipping."
+ @echo " login-integration-force - Force run integration tests."
+ @echo " login-standalone-build - Build the docker image for production login containers."
+ @echo " login-quality - Run all quality checks (login-lint, unit, integration)."
+ @echo " login-ci - Run all CI tasks. Run it with the -j flag to parallelize: make -j ci."
+ @echo " show-cache-keys - Show all cache keys with image ids and exit codes."
+ @echo " clean-cache-keys - Remove all cache keys."
.PHONY: login-lint-force
@@ -47,13 +42,12 @@ login-unit:
./scripts/run_or_skip.sh login-unit-force $(LOGIN_DEPENDENCIES_TAG)
.PHONY: login-integration-force
-login-integration-force: login core-mock login-integration-testsuite
- docker run --rm $(LOGIN_INTEGRATION_TESTSUITE_TAG)
- $(MAKE) core-mock-stop
+login-integration-force: login-standalone-build core-mock-build login-integration-testsuite-build
+ docker compose --file ./apps/login-integration-testsuite/docker-compose.yaml run --rm integration-testsuite
.PHONY: login-integration
login-integration:
- ./scripts/run_or_skip.sh login-integration-force '$(LOGIN_DEPENDENCIES_TAG);$(CORE_MOCK_TAG);$(LOGIN_INTEGRATION_TESTSUITE_TAG)'
+ ./scripts/run_or_skip.sh login-integration-force '$(LOGIN_IMAGE_TAG);$(LOGIN_INTEGRATION_TESTSUITE_TAG);$(CORE_MOCK_TAG)'
.PHONY: login-quality
login-quality: core-mock-build login-quality-after-build
@@ -62,37 +56,22 @@ login-quality-after-build: login-lint login-unit login-integration
.PHONY: login-ci
login-ci: core-mock-build login-ci-after-build
-login-ci-after-build: login-quality-after-build login-standalone
+login-ci-after-build: login-quality-after-build login-standalone-build
@:
login-dependencies:
docker buildx bake login-dependencies --set login-dependencies.tags=$(LOGIN_DEPENDENCIES_TAG);
-.PHONY: login-standalone
-login-standalone:
+.PHONY: login-standalone-build
+login-standalone-build:
docker buildx bake login-standalone --set login-standalone.tags=$(LOGIN_IMAGE_TAG);
-.PHONY: login
-login: login-standalone login-stop
- docker run --detach --rm --name $(LOGIN_CONTAINER_NAME) --publish 3000:3000 $(LOGIN_IMAGE_TAG)
-
-login-stop:
- docker rm --force $(LOGIN_CONTAINER_NAME) 2>/dev/null || true
-
core-mock-build:
docker buildx bake core-mock --set core-mock.tags=$(CORE_MOCK_TAG);
-login-integration-testsuite: login-dependencies
+login-integration-testsuite-build: login-dependencies
docker buildx bake login-integration-testsuite --set login-integration-testsuite.tags=$(LOGIN_INTEGRATION_TESTSUITE_TAG)
-.PHONY: core-mock
-core-mock: core-mock-build core-mock-stop
- docker run --detach --rm --name $(CORE_MOCK_CONTAINER_NAME) --publish 22221:22221 --publish 22222:22222 $(CORE_MOCK_TAG)
-
-.PHONY: core-mock-stop
-core-mock-stop:
- docker rm --force $(CORE_MOCK_CONTAINER_NAME) 2>/dev/null || true
-
.PHONY: clean-cache-keys
clean-cache-keys:
@echo "Removing cache directory: $(CACHE_DIR)"
diff --git a/apps/core-mock/Dockerfile b/apps/core-mock/Dockerfile
index fff98a50c7..c9c77e5afd 100644
--- a/apps/core-mock/Dockerfile
+++ b/apps/core-mock/Dockerfile
@@ -6,4 +6,4 @@ COPY mocked-services.cfg .
COPY initial-stubs initial-stubs
COPY --from=protos . .
-ENTRYPOINT [ "sh", "-c", "grpc-mock -v 1 -protos $(tr '\n' ',' < ./mocked-services.cfg) -stub-dir ./initial-stubs" ]
+ENTRYPOINT [ "sh", "-c", "grpc-mock -v 1 -proto $(tr '\n' ',' < ./mocked-services.cfg) -stub-dir ./initial-stubs" ]
diff --git a/apps/login-integration-testsuite/cypress.config.ts b/apps/login-integration-testsuite/cypress.config.ts
index 855eda22e1..080cb31bc6 100644
--- a/apps/login-integration-testsuite/cypress.config.ts
+++ b/apps/login-integration-testsuite/cypress.config.ts
@@ -2,9 +2,11 @@ import { defineConfig } from "cypress";
export default defineConfig({
reporter: "list",
+
e2e: {
- baseUrl: "http://localhost:3000",
+ baseUrl: process.env.LOGIN_BASE_URL || "http://localhost:3000",
specPattern: "integration/**/*.cy.{js,jsx,ts,tsx}",
+ supportFile: "support/e2e.{js,jsx,ts,tsx}",
setupNodeEvents(on, config) {
// implement node event listeners here
},
diff --git a/apps/login-integration-testsuite/docker-compose.yaml b/apps/login-integration-testsuite/docker-compose.yaml
new file mode 100644
index 0000000000..96d3fc9b59
--- /dev/null
+++ b/apps/login-integration-testsuite/docker-compose.yaml
@@ -0,0 +1,31 @@
+services:
+ core-mock:
+ image: ${CORE_MOCK_TAG:-zitadel-core-mock:local}
+ container_name: core-mock
+ ports:
+ - 22220:22220
+ - 22222:22222
+
+ login:
+ image: ${LOGIN_IMAGE_TAG:-zitadel-login:local}
+ container_name: login
+ ports:
+ - 3000:3000
+ environment:
+ - ZITADEL_API_URL=http://core-mock:22222
+ - ZITADEL_SERVICE_USER_TOKEN="yolo"
+ - EMAIL_VERIFICATION=true
+ - DEBUG=true
+ - NEXT_PUBLIC_BASE_PATH=""
+
+ integration-testsuite:
+ image: ${LOGIN_INTEGRATION_TESTSUITE_TAG:-zitadel-login-integration-testsuite:local}
+ container_name: integration-testsuite
+ environment:
+ - LOGIN_BASE_URL=http://login:3000
+ - CYPRESS_CORE_MOCK_STUBS_URL=http://core-mock:22220/v1/stubs
+ depends_on:
+ login:
+ condition: service_started
+ core-mock:
+ condition: service_started
diff --git a/apps/login-integration-testsuite/integration/invite.cy.ts b/apps/login-integration-testsuite/integration/invite.cy.ts
index 3014f5a2e5..7765dae827 100644
--- a/apps/login-integration-testsuite/integration/invite.cy.ts
+++ b/apps/login-integration-testsuite/integration/invite.cy.ts
@@ -1,4 +1,4 @@
-import { stub } from "../support/mock";
+import { stub } from "../support/e2e";
describe("verify invite", () => {
beforeEach(() => {
diff --git a/apps/login-integration-testsuite/integration/login.cy.ts b/apps/login-integration-testsuite/integration/login.cy.ts
index 3e74c0f7fe..46710a4d37 100644
--- a/apps/login-integration-testsuite/integration/login.cy.ts
+++ b/apps/login-integration-testsuite/integration/login.cy.ts
@@ -1,4 +1,4 @@
-import { stub } from "../support/mock";
+import { stub } from "../support/e2e";
describe("login", () => {
beforeEach(() => {
diff --git a/apps/login-integration-testsuite/integration/register-idp.cy.ts b/apps/login-integration-testsuite/integration/register-idp.cy.ts
index 6b320f1775..73a0c32e00 100644
--- a/apps/login-integration-testsuite/integration/register-idp.cy.ts
+++ b/apps/login-integration-testsuite/integration/register-idp.cy.ts
@@ -1,4 +1,4 @@
-import { stub } from "../support/mock";
+import { stub } from "../support/e2e";
const IDP_URL = "https://example.com/idp/url";
diff --git a/apps/login-integration-testsuite/integration/register.cy.ts b/apps/login-integration-testsuite/integration/register.cy.ts
index 262302c4c3..0fbb9fd447 100644
--- a/apps/login-integration-testsuite/integration/register.cy.ts
+++ b/apps/login-integration-testsuite/integration/register.cy.ts
@@ -1,4 +1,4 @@
-import { stub } from "../support/mock";
+import { stub } from "../support/e2e";
describe("register", () => {
beforeEach(() => {
diff --git a/apps/login-integration-testsuite/integration/verify.cy.ts b/apps/login-integration-testsuite/integration/verify.cy.ts
index 464bf02e59..5d19b2f8ad 100644
--- a/apps/login-integration-testsuite/integration/verify.cy.ts
+++ b/apps/login-integration-testsuite/integration/verify.cy.ts
@@ -1,4 +1,4 @@
-import { stub } from "../support/mock";
+import { stub } from "../support/e2e";
describe("verify email", () => {
beforeEach(() => {
diff --git a/apps/login-integration-testsuite/support/commands.ts b/apps/login-integration-testsuite/support/commands.ts
deleted file mode 100644
index 95857aea4c..0000000000
--- a/apps/login-integration-testsuite/support/commands.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-///
-// ***********************************************
-// This example commands.ts shows you how to
-// create various custom commands and overwrite
-// existing commands.
-//
-// For more comprehensive examples of custom
-// commands please read more here:
-// https://on.cypress.io/custom-commands
-// ***********************************************
-//
-//
-// -- This is a parent command --
-// Cypress.Commands.add('login', (email, password) => { ... })
-//
-//
-// -- This is a child command --
-// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
-//
-//
-// -- This is a dual command --
-// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
-//
-//
-// -- This will overwrite an existing command --
-// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
-//
-// declare global {
-// namespace Cypress {
-// interface Chainable {
-// login(email: string, password: string): Chainable
-// drag(subject: string, options?: Partial): Chainable
-// dismiss(subject: string, options?: Partial): Chainable
-// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
-// }
-// }
-// }
diff --git a/apps/login-integration-testsuite/support/e2e.ts b/apps/login-integration-testsuite/support/e2e.ts
index 6a173d6fcb..e9f1f34030 100644
--- a/apps/login-integration-testsuite/support/e2e.ts
+++ b/apps/login-integration-testsuite/support/e2e.ts
@@ -1,20 +1,29 @@
-// ***********************************************************
-// This example support/e2e.ts is processed and
-// loaded automatically before your test files.
-//
-// This is a great place to put global configuration and
-// behavior that modifies Cypress.
-//
-// You can change the location of this file or turn off
-// automatically serving support files with the
-// 'supportFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/configuration
-// ***********************************************************
+const url = Cypress.env('CORE_MOCK_STUBS_URL') || "http://localhost:22220/v1/stubs"
-// Import commands.js using ES2015 syntax:
-import "./commands";
+function removeStub(service: string, method: string) {
+ return cy.request({
+ url,
+ method: "DELETE",
+ qs: {
+ service,
+ method,
+ },
+ });
+}
-// Alternatively you can use CommonJS syntax:
-// require('./commands')
+export function stub(service: string, method: string, out?: any) {
+ removeStub(service, method);
+ return cy.request({
+ url,
+ method: "POST",
+ body: {
+ stubs: [
+ {
+ service,
+ method,
+ out,
+ },
+ ],
+ },
+ });
+}
diff --git a/apps/login-integration-testsuite/support/mock.ts b/apps/login-integration-testsuite/support/mock.ts
deleted file mode 100644
index 84c33b8c2d..0000000000
--- a/apps/login-integration-testsuite/support/mock.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-function removeStub(service: string, method: string) {
- return cy.request({
- url: "http://localhost:22220/v1/stubs",
- method: "DELETE",
- qs: {
- service,
- method,
- },
- });
-}
-
-export function stub(service: string, method: string, out?: any) {
- removeStub(service, method);
- return cy.request({
- url: "http://localhost:22220/v1/stubs",
- method: "POST",
- body: {
- stubs: [
- {
- service,
- method,
- out,
- },
- ],
- },
- });
-}
diff --git a/apps/login-integration-testsuite/tsconfig.json b/apps/login-integration-testsuite/tsconfig.json
index 830efdd0ba..18edb199ac 100644
--- a/apps/login-integration-testsuite/tsconfig.json
+++ b/apps/login-integration-testsuite/tsconfig.json
@@ -1,5 +1,4 @@
{
- "extends": "../tsconfig.json",
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
diff --git a/docker-bake.hcl b/docker-bake.hcl
index 2bc70b681d..f91e1a2c6f 100644
--- a/docker-bake.hcl
+++ b/docker-bake.hcl
@@ -46,6 +46,9 @@ target "core-mock" {
target "login-integration-testsuite" {
dockerfile = "dockerfiles/login-integration-testsuite.Dockerfile"
+ contexts = {
+ login-base = "target:login-base"
+ }
}
# We run integration and acceptance tests against the next standalone server for docker.
diff --git a/dockerfiles/login-base.Dockerfile b/dockerfiles/login-base.Dockerfile
index 5039b4b7f9..2362b39c0c 100644
--- a/dockerfiles/login-base.Dockerfile
+++ b/dockerfiles/login-base.Dockerfile
@@ -3,4 +3,4 @@ ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
RUN apk add --no-cache libc6-compat bash git
-WORKDIR /app
+WORKDIR /build
diff --git a/dockerfiles/login-integration-testsuite.Dockerfile b/dockerfiles/login-integration-testsuite.Dockerfile
index c32cf2d7f2..e0b53e6af9 100644
--- a/dockerfiles/login-integration-testsuite.Dockerfile
+++ b/dockerfiles/login-integration-testsuite.Dockerfile
@@ -1,15 +1,16 @@
-FROM cypress/factory AS login-integration-testsuite
-ENV PNPM_HOME="/pnpm"
-ENV PATH="$PNPM_HOME:$PATH"
-RUN corepack enable
-WORKDIR /opt/app
+FROM login-base AS integration-dependencies
COPY \
pnpm-lock.yaml \
pnpm-workspace.yaml \
./
COPY ./apps/login-integration-testsuite/package.json ./apps/login-integration-testsuite/package.json
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
- pnpm install --frozen-lockfile
-RUN pnpm exec cypress install
-COPY ./apps/login-integration-testsuite/ .
-CMD ["pnpm", "exec", "cypress", "run"]
+ pnpm install --no-frozen-lockfile --filter=login-integration-testsuite
+
+FROM cypress/factory AS login-integration-testsuite
+WORKDIR /opt/app
+COPY --from=integration-dependencies /build/apps/login-integration-testsuite .
+RUN npm install cypress
+RUN npx cypress install
+COPY ./apps/login-integration-testsuite .
+CMD ["npx", "cypress", "run"]
diff --git a/dockerfiles/login-standalone.Dockerfile b/dockerfiles/login-standalone.Dockerfile
index 05a6c1846a..0e758dac04 100644
--- a/dockerfiles/login-standalone.Dockerfile
+++ b/dockerfiles/login-standalone.Dockerfile
@@ -3,20 +3,20 @@ RUN pnpm install turbo --global
COPY . .
RUN turbo prune @zitadel/login --docker
FROM login-base AS installer
-COPY --from=prune-for-docker /app/out/json/ .
+COPY --from=prune-for-docker /build/out/json/ .
RUN pnpm install --frozen-lockfile
-COPY --from=prune-for-docker /app/out/full/ .
+COPY --from=prune-for-docker /build/out/full/ .
RUN NEXT_PUBLIC_BASE_PATH=/ui/v2/login NEXT_OUTPUT_MODE=standalone pnpm exec turbo run build
FROM login-platform AS login-standalone
-WORKDIR /app
+WORKDIR /runtime
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# If /.env-file/.env is mounted into the container, its variables are made available to the server before it starts up.
RUN mkdir -p /.env-file && touch /.env-file/.env && chown -R nextjs:nodejs /.env-file
-COPY --chown=nextjs:nodejs --from=installer /app/apps/login/.next/standalone ./
-COPY --chown=nextjs:nodejs --from=installer /app/apps/login/.next/static ./apps/login/.next/static
-COPY --chown=nextjs:nodejs --from=installer /app/apps/login/public ./apps/login/public
+COPY --chown=nextjs:nodejs --from=installer /build/apps/login/.next/standalone ./
+COPY --chown=nextjs:nodejs --from=installer /build/apps/login/.next/static ./apps/login/.next/static
+COPY --chown=nextjs:nodejs --from=installer /build/apps/login/public ./apps/login/public
USER nextjs
ENV HOSTNAME="0.0.0.0"
CMD ["/bin/sh", "-c", " set -o allexport && . /.env-file/.env && set +o allexport && node apps/login/server.js"]
diff --git a/dockerfiles/typescript-proto-client.Dockerfile b/dockerfiles/typescript-proto-client.Dockerfile
index d73b2559e5..2cf47e632f 100644
--- a/dockerfiles/typescript-proto-client.Dockerfile
+++ b/dockerfiles/typescript-proto-client.Dockerfile
@@ -3,4 +3,4 @@ COPY packages/zitadel-proto packages/zitadel-proto
RUN pnpm generate
FROM scratch
-COPY --from=zitadel-proto /app/packages/zitadel-proto /
+COPY --from=zitadel-proto /build/packages/zitadel-proto /
diff --git a/scripts/run_or_skip.sh b/scripts/run_or_skip.sh
index ad238039e9..20c45d2ec2 100755
--- a/scripts/run_or_skip.sh
+++ b/scripts/run_or_skip.sh
@@ -12,6 +12,7 @@ fi
MAKE_TARGET=$1
IMAGES=$2
+FORCE=${FORCE:-false}
DIGEST_FILE="$CACHE_DIR/$MAKE_TARGET.digests"
mkdir -p "$CACHE_DIR"
@@ -31,14 +32,18 @@ OLD_DIGEST=$(cat "$DIGEST_FILE" 2>/dev/null || echo "")
OLD_STATUS=$(echo "$OLD_DIGEST" | cut -d ';' -f1)
OLD_IDS=$(echo "$OLD_DIGEST" | cut -d ';' -f2-9)
if [[ "$OLD_IDS" == "$(get_image_ids)" ]]; then
- echo "Skipping $MAKE_TARGET – all images unchanged, returning cached status $OLD_STATUS"
- exit $OLD_STATUS
-else
- echo "Running $MAKE_TARGET..."
- set +e
- make $MAKE_TARGET
- STATUS=$?
- set -e
- echo "${STATUS};$(get_image_ids)" > $DIGEST_FILE
- exit $STATUS
+ if [[ "$FORCE" == "true" ]]; then
+ echo "\$FORCE=$FORCE - Running $MAKE_TARGET despite unchanged images."
+ else
+ echo "Skipping $MAKE_TARGET – all images unchanged, returning cached status $OLD_STATUS"
+ exit $OLD_STATUS
+ fi
fi
+
+echo "Running $MAKE_TARGET..."
+set +e
+make -j $MAKE_TARGET
+STATUS=$?
+set -e
+echo "${STATUS};$(get_image_ids)" > $DIGEST_FILE
+exit $STATUS