feat(web): immich-ui components #27390
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Test | |
on: | |
workflow_dispatch: | |
pull_request: | |
push: | |
branches: [main] | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: true | |
jobs: | |
pre-job: | |
runs-on: ubuntu-latest | |
outputs: | |
should_run_web: ${{ steps.found_paths.outputs.web == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_server: ${{ steps.found_paths.outputs.server == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_cli: ${{ steps.found_paths.outputs.cli == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_e2e: ${{ steps.found_paths.outputs.e2e == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_mobile: ${{ steps.found_paths.outputs.mobile == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_e2e_web: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.web == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
should_run_e2e_server_cli: ${{ steps.found_paths.outputs.e2e == 'true' || steps.found_paths.outputs.server == 'true' || steps.found_paths.outputs.cli == 'true' || steps.should_force.outputs.should_force == 'true' }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- id: found_paths | |
uses: dorny/paths-filter@v3 | |
with: | |
filters: | | |
web: | |
- 'web/**' | |
- 'i18n/**' | |
- 'open-api/typescript-sdk/**' | |
server: | |
- 'server/**' | |
cli: | |
- 'cli/**' | |
- 'open-api/typescript-sdk/**' | |
e2e: | |
- 'e2e/**' | |
mobile: | |
- 'mobile/**' | |
machine-learning: | |
- 'machine-learning/**' | |
- name: Check if we should force jobs to run | |
id: should_force | |
run: echo "should_force=${{ github.event_name == 'workflow_dispatch' }}" >> "$GITHUB_OUTPUT" | |
server-unit-tests: | |
name: Test & Lint Server | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }} | |
runs-on: ubuntu-latest | |
defaults: | |
run: | |
working-directory: ./server | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './server/.nvmrc' | |
- name: Run npm install | |
run: npm ci | |
- name: Run linter | |
run: npm run lint | |
if: ${{ !cancelled() }} | |
- name: Run formatter | |
run: npm run format | |
if: ${{ !cancelled() }} | |
- name: Run tsc | |
run: npm run check | |
if: ${{ !cancelled() }} | |
- name: Run small tests & coverage | |
run: npm run test:cov | |
if: ${{ !cancelled() }} | |
cli-unit-tests: | |
name: Unit Test CLI | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_cli == 'true' }} | |
runs-on: ubuntu-latest | |
defaults: | |
run: | |
working-directory: ./cli | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './cli/.nvmrc' | |
- name: Setup typescript-sdk | |
run: npm ci && npm run build | |
working-directory: ./open-api/typescript-sdk | |
- name: Install deps | |
run: npm ci | |
- name: Run linter | |
run: npm run lint | |
if: ${{ !cancelled() }} | |
- name: Run formatter | |
run: npm run format | |
if: ${{ !cancelled() }} | |
- name: Run tsc | |
run: npm run check | |
if: ${{ !cancelled() }} | |
- name: Run unit tests & coverage | |
run: npm run test:cov | |
if: ${{ !cancelled() }} | |
cli-unit-tests-win: | |
name: Unit Test CLI (Windows) | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_cli == 'true' }} | |
runs-on: windows-latest | |
defaults: | |
run: | |
working-directory: ./cli | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './cli/.nvmrc' | |
- name: Setup typescript-sdk | |
run: npm ci && npm run build | |
working-directory: ./open-api/typescript-sdk | |
- name: Install deps | |
run: npm ci | |
# Skip linter & formatter in Windows test. | |
- name: Run tsc | |
run: npm run check | |
if: ${{ !cancelled() }} | |
- name: Run unit tests & coverage | |
run: npm run test:cov | |
if: ${{ !cancelled() }} | |
web-unit-tests: | |
name: Test & Lint Web | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_web == 'true' }} | |
runs-on: ubuntu-latest | |
defaults: | |
run: | |
working-directory: ./web | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './web/.nvmrc' | |
- name: Run setup typescript-sdk | |
run: npm ci && npm run build | |
working-directory: ./open-api/typescript-sdk | |
- name: Run npm install | |
run: npm ci | |
- name: Run linter | |
run: npm run lint | |
if: ${{ !cancelled() }} | |
- name: Run formatter | |
run: npm run format | |
if: ${{ !cancelled() }} | |
- name: Run svelte checks | |
run: npm run check:svelte | |
if: ${{ !cancelled() }} | |
- name: Run tsc | |
run: npm run check:typescript | |
if: ${{ !cancelled() }} | |
- name: Run unit tests & coverage | |
run: npm run test:cov | |
if: ${{ !cancelled() }} | |
e2e-tests-lint: | |
name: End-to-End Lint | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_e2e == 'true' }} | |
runs-on: ubuntu-latest | |
defaults: | |
run: | |
working-directory: ./e2e | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './e2e/.nvmrc' | |
- name: Run setup typescript-sdk | |
run: npm ci && npm run build | |
working-directory: ./open-api/typescript-sdk | |
if: ${{ !cancelled() }} | |
- name: Install dependencies | |
run: npm ci | |
if: ${{ !cancelled() }} | |
- name: Run linter | |
run: npm run lint | |
if: ${{ !cancelled() }} | |
- name: Run formatter | |
run: npm run format | |
if: ${{ !cancelled() }} | |
- name: Run tsc | |
run: npm run check | |
if: ${{ !cancelled() }} | |
medium-tests-server: | |
name: Medium Tests (Server) | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }} | |
runs-on: mich | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
with: | |
submodules: 'recursive' | |
- name: Production build | |
if: ${{ !cancelled() }} | |
run: docker compose -f e2e/docker-compose.yml build | |
- name: Run medium tests | |
if: ${{ !cancelled() }} | |
run: make test-medium | |
e2e-tests-server-cli: | |
name: End-to-End Tests (Server & CLI) | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_e2e_server_cli == 'true' }} | |
runs-on: mich | |
defaults: | |
run: | |
working-directory: ./e2e | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
with: | |
submodules: 'recursive' | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './e2e/.nvmrc' | |
- name: Run setup typescript-sdk | |
run: npm ci && npm run build | |
working-directory: ./open-api/typescript-sdk | |
if: ${{ !cancelled() }} | |
- name: Run setup cli | |
run: npm ci && npm run build | |
working-directory: ./cli | |
if: ${{ !cancelled() }} | |
- name: Install dependencies | |
run: npm ci | |
if: ${{ !cancelled() }} | |
- name: Docker build | |
run: docker compose build | |
if: ${{ !cancelled() }} | |
- name: Run e2e tests (api & cli) | |
run: npm run test | |
if: ${{ !cancelled() }} | |
e2e-tests-web: | |
name: End-to-End Tests (Web) | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_e2e_web == 'true' }} | |
runs-on: mich | |
defaults: | |
run: | |
working-directory: ./e2e | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
with: | |
submodules: 'recursive' | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './e2e/.nvmrc' | |
- name: Run setup typescript-sdk | |
run: npm ci && npm run build | |
working-directory: ./open-api/typescript-sdk | |
if: ${{ !cancelled() }} | |
- name: Install dependencies | |
run: npm ci | |
if: ${{ !cancelled() }} | |
- name: Install Playwright Browsers | |
run: npx playwright install --with-deps chromium | |
if: ${{ !cancelled() }} | |
- name: Docker build | |
run: docker compose build | |
if: ${{ !cancelled() }} | |
- name: Run e2e tests (web) | |
run: npx playwright test | |
if: ${{ !cancelled() }} | |
mobile-unit-tests: | |
name: Unit Test Mobile | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_mobile == 'true' }} | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Setup Flutter SDK | |
uses: subosito/flutter-action@v2 | |
with: | |
channel: 'stable' | |
flutter-version-file: ./mobile/pubspec.yaml | |
- name: Run tests | |
working-directory: ./mobile | |
run: flutter test -j 1 | |
ml-unit-tests: | |
name: Unit Test ML | |
needs: pre-job | |
if: ${{ needs.pre-job.outputs.should_run_ml == 'true' }} | |
runs-on: ubuntu-latest | |
defaults: | |
run: | |
working-directory: ./machine-learning | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Install poetry | |
run: pipx install poetry | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: 3.11 | |
cache: 'poetry' | |
- name: Install dependencies | |
run: | | |
poetry install --with dev --with cpu | |
- name: Lint with ruff | |
run: | | |
poetry run ruff check --output-format=github app export | |
- name: Check black formatting | |
run: | | |
poetry run black --check app export | |
- name: Run mypy type checking | |
run: | | |
poetry run mypy --install-types --non-interactive --strict app/ | |
- name: Run tests and coverage | |
run: | | |
poetry run pytest app --cov=app --cov-report term-missing | |
shellcheck: | |
name: ShellCheck | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Run ShellCheck | |
uses: ludeeus/action-shellcheck@master | |
with: | |
ignore_paths: >- | |
**/open-api/** | |
**/openapi/** | |
**/node_modules/** | |
generated-api-up-to-date: | |
name: OpenAPI Clients | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './server/.nvmrc' | |
- name: Install server dependencies | |
run: npm --prefix=server ci | |
- name: Build the app | |
run: npm --prefix=server run build | |
- name: Run API generation | |
run: make open-api | |
- name: Find file changes | |
uses: tj-actions/verify-changed-files@v20 | |
id: verify-changed-files | |
with: | |
files: | | |
mobile/openapi | |
open-api/typescript-sdk | |
open-api/immich-openapi-specs.json | |
- name: Verify files have not changed | |
if: steps.verify-changed-files.outputs.files_changed == 'true' | |
run: | | |
echo "ERROR: Generated files not up to date!" | |
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}" | |
exit 1 | |
generated-typeorm-migrations-up-to-date: | |
name: TypeORM Checks | |
runs-on: ubuntu-latest | |
services: | |
postgres: | |
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 | |
env: | |
POSTGRES_PASSWORD: postgres | |
POSTGRES_USER: postgres | |
POSTGRES_DB: immich | |
options: >- | |
--health-cmd pg_isready | |
--health-interval 10s | |
--health-timeout 5s | |
--health-retries 5 | |
ports: | |
- 5432:5432 | |
defaults: | |
run: | |
working-directory: ./server | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Setup Node | |
uses: actions/setup-node@v4 | |
with: | |
node-version-file: './server/.nvmrc' | |
- name: Install server dependencies | |
run: npm ci | |
- name: Build the app | |
run: npm run build | |
- name: Run existing migrations | |
run: npm run typeorm:migrations:run | |
- name: Test npm run schema:reset command works | |
run: npm run typeorm:schema:reset | |
- name: Generate new migrations | |
continue-on-error: true | |
run: npm run typeorm:migrations:generate ./src/migrations/TestMigration | |
- name: Find file changes | |
uses: tj-actions/verify-changed-files@v20 | |
id: verify-changed-files | |
with: | |
files: | | |
server/src/migrations/ | |
- name: Verify migration files have not changed | |
if: steps.verify-changed-files.outputs.files_changed == 'true' | |
run: | | |
echo "ERROR: Generated migration files not up to date!" | |
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}" | |
exit 1 | |
- name: Run SQL generation | |
run: npm run sync:sql | |
env: | |
DB_URL: postgres://postgres:postgres@localhost:5432/immich | |
- name: Find file changes | |
uses: tj-actions/verify-changed-files@v20 | |
id: verify-changed-sql-files | |
with: | |
files: | | |
server/src/queries | |
- name: Verify SQL files have not changed | |
if: steps.verify-changed-sql-files.outputs.files_changed == 'true' | |
run: | | |
echo "ERROR: Generated SQL files not up to date!" | |
echo "Changed files: ${{ steps.verify-changed-sql-files.outputs.changed_files }}" | |
exit 1 | |
# mobile-integration-tests: | |
# name: Run mobile end-to-end integration tests | |
# runs-on: macos-latest | |
# steps: | |
# - uses: actions/checkout@v4 | |
# - uses: actions/setup-java@v3 | |
# with: | |
# distribution: 'zulu' | |
# java-version: '12.x' | |
# cache: 'gradle' | |
# - name: Cache android SDK | |
# uses: actions/cache@v3 | |
# id: android-sdk | |
# with: | |
# key: android-sdk | |
# path: | | |
# /usr/local/lib/android/ | |
# ~/.android | |
# - name: Cache Gradle | |
# uses: actions/cache@v3 | |
# with: | |
# path: | | |
# ./mobile/build/ | |
# ./mobile/android/.gradle/ | |
# key: ${{ runner.os }}-flutter-${{ hashFiles('**/*.gradle*', 'pubspec.lock') }} | |
# - name: Setup Android SDK | |
# if: steps.android-sdk.outputs.cache-hit != 'true' | |
# uses: android-actions/setup-android@v2 | |
# - name: AVD cache | |
# uses: actions/cache@v3 | |
# id: avd-cache | |
# with: | |
# path: | | |
# ~/.android/avd/* | |
# ~/.android/adb* | |
# key: avd-29 | |
# - name: create AVD and generate snapshot for caching | |
# if: steps.avd-cache.outputs.cache-hit != 'true' | |
# uses: reactivecircus/[email protected] | |
# with: | |
# working-directory: ./mobile | |
# cores: 2 | |
# api-level: 29 | |
# arch: x86_64 | |
# profile: pixel | |
# target: default | |
# force-avd-creation: false | |
# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | |
# disable-animations: false | |
# script: echo "Generated AVD snapshot for caching." | |
# - name: Setup Flutter SDK | |
# uses: subosito/flutter-action@v2 | |
# with: | |
# channel: 'stable' | |
# flutter-version: '3.7.3' | |
# cache: true | |
# - name: Run integration tests | |
# uses: Wandalen/wretry.action@master | |
# with: | |
# action: reactivecircus/[email protected] | |
# with: | | |
# working-directory: ./mobile | |
# cores: 2 | |
# api-level: 29 | |
# arch: x86_64 | |
# profile: pixel | |
# target: default | |
# force-avd-creation: false | |
# emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | |
# disable-animations: true | |
# script: | | |
# flutter pub get | |
# flutter test integration_test | |
# attempt_limit: 3 |