name: CI on: push: branches: - main - dev - "feat/**" - "fix/**" pull_request: branches: [ "main", "dev" ] env: CARGO_TERM_COLOR: always RUSTFLAGS: "-Dwarnings" DATABASE_URL: "postgres://postgres:postgres@localhost/oxicloud_test" jobs: # Detect which parts of the codebase changed changes: runs-on: ubuntu-latest outputs: frontend: ${{ steps.filter.outputs.frontend }} backend: ${{ steps.filter.outputs.backend }} steps: - uses: actions/checkout@v4 - uses: dorny/paths-filter@v3 id: filter with: filters: | frontend: - 'static/**' - 'biome.json' - '.grit' - '.stylelintrc.json' - 'jsconfig.json' # Audit scripts that gate frontend correctness — touch # them and the frontend job must re-run. - 'tools/check-missing-translations.py' - 'tools/check-icons.py' backend: - 'src/**' - 'Cargo.toml' - 'Cargo.lock' - 'tests/**' frontend-check: name: Frontend — CSS and JS checks (format, lint, css-rules, types) needs: changes if: needs.changes.outputs.frontend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Biome uses: biomejs/setup-biome@v2 - name: Run Biome check run: biome ci static/ - name: Setup Node uses: actions/setup-node@v4 with: node-version: 25 # because we are not using package.json - name: Install Stylelint, TypeScript and plugins run: | npm install --global \ stylelint@17 \ postcss@8 \ stylelint-value-no-unknown-custom-properties@6 \ typescript - name: Run Stylelint run: npx stylelint "static/css/**/*.{css,scss}" - name: Run TypeScript check run: tsc -p jsconfig.json --noEmit - name: Check locale files are at parity with en.json # Python 3 stdlib only — no setup step needed. # `--check-only` keeps the CI log terse; failures still surface # via exit code (the script returns 1 when any non-English # locale is missing a key present in en.json). Mirrors the # `--check-only` flag on `tools/check-icons.py` below. # Run locally without --check-only to see the missing keys. run: python3 tools/check-missing-translations.py --check-only - name: Check FA icons referenced in static/ are registered # `--check-only` skips the Font-Awesome clone and the icons.js # patch — it just scans `fas fa-` references and diffs # them against OxiIcons. Exit 1 if any used icon is absent # from the registry. Run locally without --check-only to # auto-add missing entries from a checked-out Font-Awesome # source. run: python3 tools/check-icons.py --check-only rust-fmt: name: Rustfmt needs: changes if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt - run: cargo fmt --all --check rust-clippy: name: Clippy needs: changes if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: clippy - uses: Swatinem/rust-cache@v2 - run: cargo clippy --all-targets --all-features -- -D warnings rust-test: name: Server Unit and Functionnal Tests needs: changes if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest services: postgres: image: postgres:16-alpine env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: oxicloud_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U postgres" --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Initialize test database # Applies every migration + seeds the integration-test admin row. # Same script used by `just test-integration` locally. run: bash tests/common/init-test-schema.sh env: PGHOST: localhost PGPORT: "5432" PGUSER: postgres PGPASSWORD: postgres PGDATABASE: oxicloud_test - name: Run tests run: cargo test --all-features --workspace env: DATABASE_URL: "postgres://postgres:postgres@localhost/oxicloud_test" - name: Run integration tests run: cargo test --all-features --workspace --tests env: DATABASE_URL: "postgres://postgres:postgres@localhost/oxicloud_test" RUSTFLAGS: "-Dwarnings --cfg integration_tests" rust-audit: name: Security Audit needs: changes if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: rustsec/audit-check@v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} build: name: Build runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo build --release # build.rs runs the deconflict pass and js_bundle_validate() — any # duplicate declaration or parse error in the JS bundle fails here. - name: Validate JS bundle (node --check) # belt-and-suspenders: node --check parses the bundle without executing it. # Catches SyntaxErrors that OXC's parse check inside build.rs would also # catch, but gives a human-readable error line in the CI log. run: node --check static-dist/js/app.*.js - uses: actions/upload-artifact@v4 with: name: oxicloud-release path: target/release/oxicloud retention-days: 1 api-test: name: API & Webdav tests needs: build if: github.event_name == 'pull_request' timeout-minutes: 30 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: name: oxicloud-release path: target/release/ - name: Set execute bit on pre-built binary run: chmod +x target/release/oxicloud - name: Install Hurl and b3sum env: HURL_MAJOR: "8" run: | HURL_VERSION=$(curl -fsSL -H "Authorization: Bearer ${{ github.token }}" \ https://api.github.com/repos/Orange-OpenSource/hurl/releases \ | jq -r "map(select(.tag_name | startswith(\"${HURL_MAJOR}.\"))) | first | .tag_name") curl -fLO "https://github.com/Orange-OpenSource/hurl/releases/download/${HURL_VERSION}/hurl_${HURL_VERSION}_amd64.deb" sudo apt-get install -y "./hurl_${HURL_VERSION}_amd64.deb" b3sum - name: Run Hurl API tests run: bash tests/api/run.sh env: BUILD_TARGET: release - name: Run Webdav tests run: bash tests/webdav/run.sh env: BUILD_TARGET: release - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} with: name: hurl-report path: tests/api/storage/ retention-days: 7 front-test: name: Frontend end-to-end tests (via Playwright) # ensure that api tests are ok before needs: api-test if: github.event_name == 'pull_request' timeout-minutes: 60 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: name: oxicloud-release path: target/release/ - name: Set execute bit on pre-built binary run: chmod +x target/release/oxicloud - uses: actions/setup-node@v4 with: node-version: lts/* - name: Install Node dependencies working-directory: tests/e2e run: npm ci - name: Install Playwright browsers working-directory: tests/e2e run: npx playwright install --with-deps - name: Run Playwright tests (spawns DB via pretest hook) working-directory: tests/e2e run: npm test env: BUILD_TARGET: release - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} with: name: playwright-report path: tests/e2e/playwright-report/ retention-days: 30