diff --git a/.github/actions/init-pnpm/action.yaml b/.github/actions/init-pnpm/action.yaml index accf3f61..a6538bd5 100644 --- a/.github/actions/init-pnpm/action.yaml +++ b/.github/actions/init-pnpm/action.yaml @@ -5,6 +5,9 @@ inputs: description: 'Node.js version' required: true default: 24.x + install-filter: + description: 'Filter for pnpm install (e.g., --filter=packages/*)' + required: false runs: using: composite steps: @@ -24,7 +27,21 @@ runs: cache: 'pnpm' - name: Install TS Project dependencies shell: bash - run: pnpm install + env: + INSTALL_FILTER: ${{ inputs.install-filter }} + run: | + if [ -n "$INSTALL_FILTER" ]; then + pnpm install --filter="$INSTALL_FILTER" --frozen-lockfile + else + pnpm install --frozen-lockfile + fi - name: build shell: bash - run: pnpm run build + env: + INSTALL_FILTER: ${{ inputs.install-filter }} + run: | + if [ -n "$INSTALL_FILTER" ]; then + pnpm exec turbo run build --filter="$INSTALL_FILTER" + else + pnpm exec turbo run build --affected + fi diff --git a/.github/workflows/build-and-push.yaml b/.github/workflows/build-and-push.yaml index 210c6602..3decec17 100644 --- a/.github/workflows/build-and-push.yaml +++ b/.github/workflows/build-and-push.yaml @@ -1,103 +1,122 @@ name: Build and Push Service Images on: + push: + tags: + - 'v*' workflow_dispatch: - inputs: - version: - description: 'Docker Image Version (e.g., v1.2.0)' - required: true - type: string - services: - description: 'Services to build (comma-separated, e.g., "auth,payment") or "all"' - required: true - default: 'all' - type: string jobs: - # JOB 1: Parse the inputs and determine which services to build setup: runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - - name: Checkout code - uses: actions/checkout@v5 + - name: Check out TS Project Git repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - - name: Generate Service Matrix + - name: Init nodejs + uses: ./.github/actions/init-pnpm + with: + install-filter: '.' + - name: Generate build matrix id: set-matrix + shell: bash run: | - INPUT_SERVICES="${{ github.event.inputs.services }}" - - if [ "$INPUT_SERVICES" == "all" ]; then - # Scans the services directory and creates a JSON array of folder names - # Requires jq installed (standard on runner) - echo "Scanning packages for all services..." - MATRIX_JSON=$(ls -d packages/*/ | xargs -n 1 basename | jq -R -s -c 'split("\n")[:-1]') - else - # Splits comma-separated string into JSON array - echo "Parsing specific services: $INPUT_SERVICES" - MATRIX_JSON=$(echo "$INPUT_SERVICES" | jq -R -c 'split(",") | map(sub("^\\s+";"") | sub("\\s+$";""))') - fi + MATRIX_JSON=$(node scripts/generate-matrix.mjs) + echo "matrix=$MATRIX_JSON" >> "$GITHUB_OUTPUT" - echo "Target Services: $MATRIX_JSON" - echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - - # JOB 2: Build and Push in Parallel - build-and-push: + build-and-push-docker: needs: setup runs-on: ubuntu-latest strategy: - fail-fast: false matrix: - service: ${{ fromJson(needs.setup.outputs.matrix) }} + include: ${{ fromJson(needs.setup.outputs.matrix) }} permissions: contents: read - packages: write steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: '24' - # cache: 'npm' # Uncomment if you want caching - - # Login to Registry (Default: GitHub Container Registry) + - name: Check out TS Project Git repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + - uses: docker/setup-buildx-action@v4 + id: setup-buildx - name: Log in to the Container registry - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ${{ secrets.ACR_URL }} username: ${{ secrets.ACR_PUSH_USER }} password: ${{ secrets.ACR_PUSH_TOKEN }} - # For Docker Hub, use secrets.DOCKER_USERNAME and secrets.DOCKER_PASSWORD - - # Step to install dependencies. - # In a monorepo, you usually install at root to link workspaces. - - name: Install Dependencies - run: npm ci + - name: Init nodejs + uses: ./.github/actions/init-pnpm + with: + install-filter: './apps/*' + - name: Create new lockfile for the service + shell: bash + run: pnpm exec turbo prune ${{ matrix.service }} --docker + - name: cache pnpm store + uses: actions/cache@v5 + with: + path: cache-mount + + key: ${{ runner.os }}-pnpm-store-${{ matrix.service }}-${{ hashFiles('out/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store-${{ matrix.service }}- + ${{ runner.os }}-pnpm-store- + - name: Restore docker cache + uses: reproducible-containers/buildkit-cache-dance@v3 + with: + builder: ${{ steps.setup-buildx.outputs.name }} + cache-dir: cache-mount + dockerfile: ${{ matrix.dockerfile }} + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + tags: ${{ secrets.ACR_URL }}/infra/${{ matrix.service }}:${{ matrix.version }} + cache-from: type=gha + cache-to: type=gha,mode=max + file: ${{ matrix.dockerfile }} + push: true + + build-and-push-helm: + needs: setup + runs-on: ubuntu-latest - # The core requirement: Run the npm script - - name: Build Docker Image (npm script) - working-directory: packages/${{ matrix.service }} - run: npm run build:docker + permissions: + contents: read - # Retag and Push - - name: Tag and Push Image + steps: + - name: Check out TS Project Git repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + - name: Init nodejs + uses: ./.github/actions/init-pnpm + with: + install-filter: '.' + - name: Log in to the Container registry + uses: docker/login-action@v4 + with: + registry: ${{ secrets.ACR_URL }} + username: ${{ secrets.ACR_PUSH_USER }} + password: ${{ secrets.ACR_PUSH_TOKEN }} + - name: Get version from manifest + id: get_version + shell: bash run: | - SERVICE_NAME="${{ matrix.service }}" - VERSION="${{ github.event.inputs.version }}" - - # The full target path (e.g., ghcr.io/user/repo/service:v1.0.0) - # We lowercase the repo name because docker requires lowercase - IMAGE_ID=$(echo "${{ secrets.ACR_URL }}/infra/$SERVICE_NAME" | tr '[:upper:]' '[:lower:]') - - echo "Pushing image to: $IMAGE_ID:$VERSION" - - # 1. Tag the locally built image (assuming local name is simply the service name) - docker tag $SERVICE_NAME:latest $IMAGE_ID:$VERSION - - # 2. Push to registry - docker push $IMAGE_ID:$VERSION + VERSION=$(cat .release-please-manifest.json | jq -r '.["."]') + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: build dependencies + shell: bash + run: pnpm --filter "./apps/*" -rc --parallel exec 'helm dependency build ./helm || true' + - name: Push Chart to ACR + uses: appany/helm-oci-chart-releaser@v0.5.0 + with: + name: ${{ github.event.repository.name }} + repository: helm/infra + tag: ${{ steps.get_version.outputs.version }} + path: ./helm + registry: ${{ secrets.ACR_URL }} + registry_username: ${{ secrets.ACR_PUSH_USER }} + registry_password: ${{ secrets.ACR_PUSH_TOKEN }} + update_dependencies: 'true' # Defaults to false diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index bf851f00..9e06ba19 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -3,7 +3,8 @@ name: pull_request on: [pull_request, workflow_dispatch] env: - DB_HOST: localhost + TURBO_SCM_BASE: origin/${{ github.base_ref}} + NODE_CONFIG_ENV: test jobs: eslint: @@ -12,63 +13,37 @@ jobs: strategy: matrix: - node: [22.x, 24.x] + node: [24.x] steps: - name: Check out TS Project Git repository - uses: actions/checkout@v3 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + with: + fetch-depth: 0 # Fetch all history for all branches and tags + filter: 'blob:none' # Fetch only the commit history and tree, not file contents - - name: Set up Node.js - uses: actions/setup-node@v3 + - name: Init nodejs + uses: ./.github/actions/init-pnpm with: node-version: ${{ matrix.node }} - cache: npm - - - name: Install TS Project dependencies - run: npm ci - - - name: build packages - run: npx lerna run build - - name: Run TS Project linters - run: npm run lint + - name: Run linters + run: pnpm exec turbo run lint --affected openapi-lint: name: Run OpenAPI lint Check runs-on: ubuntu-latest - - strategy: - matrix: - package: [auth-manager] - steps: - name: Check out TS Project Git repository - uses: actions/checkout@v3 - - - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 with: - node-version: ${{ matrix.node }} - cache: npm - - - name: Install TS Project dependencies - run: npm ci - - - name: build packages - run: npx lerna run build + fetch-depth: 0 # Fetch all history for all branches and tags + filter: 'blob:none' # Fetch only the commit history and tree, not file contents - - name: OpenAPI Lint Checks - run: npx @redocly/cli lint --format=github-actions ./packages/${{ matrix.package }}/openapi3.yaml - - security: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Run Snyk to check for vulnerabilities - uses: snyk/actions/node@master - continue-on-error: true - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + - name: Init nodejs + uses: ./.github/actions/init-pnpm + - name: Run openapi linters + run: pnpm exec turbo run lint:openapi --affected tests: name: Run Tests @@ -76,66 +51,37 @@ jobs: strategy: matrix: - node: [22.x, 24.x] - package: [auth-manager, '@map-colonies/auth-bundler', 'auth-cron'] - - services: - # Label used to access the service container - minio: - image: acrarolibotnonprod.azurecr.io/minio:RELEASE.2025-09-07T16-13-09Z-cpuv1 - credentials: - username: ${{ secrets.ACR_PUSH_USER }} - password: ${{ secrets.ACR_PUSH_TOKEN }} - ports: - - 9000:9000 - - 9001:9001 - env: - MINIO_ROOT_USER: minioadmin - MINIO_ROOT_PASSWORD: minioadmin - options: >- - --health-cmd "curl -f http://localhost:9000/minio/health/live || exit 1" - --health-interval 30s - --health-timeout 10s - --health-retries 10 - --health-start-period 30s - postgres: - # Docker Hub image - image: postgres:14 - # Provide the password for postgres - env: - POSTGRES_PASSWORD: 1234 - POSTGRES_USER: postgres - POSTGRES_DB: postgres - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 + node: [24.x] steps: - - name: Check out Git repository - uses: actions/checkout@v3 + - name: Check out TS Project Git repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + with: + fetch-depth: 0 # Fetch all history for all branches and tags + filter: 'blob:none' # Fetch only the commit history and tree, not file contents - - name: Set up Node.js - uses: actions/setup-node@v3 + - name: Init nodejs + uses: ./.github/actions/init-pnpm with: node-version: ${{ matrix.node }} - cache: npm - - name: Install TS Project dependencies - run: npm ci + - name: Run tests + run: pnpm exec turbo run test --affected - - name: build packages - run: npx lerna run build + knip: + name: Run knip to detect unused dependencies + runs-on: ubuntu-latest + steps: + - name: Check out TS Project Git repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - - name: Run tests - run: npx lerna run test --scope ${{ matrix.package }} + - name: Fetch base branch for turbo + run: git fetch origin ${{ github.base_ref }} --depth=1 - - uses: actions/upload-artifact@v4 - continue-on-error: true + - name: Init nodejs + uses: ./.github/actions/init-pnpm with: - name: Test Reporters for ${{ matrix.package }} Node-${{ matrix.node }} - path: reports/** + install-filter: '*' + + - name: Run knip + run: pnpm run knip diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml new file mode 100644 index 00000000..eceeb5fa --- /dev/null +++ b/.github/workflows/release-please.yaml @@ -0,0 +1,18 @@ +on: + push: + branches: + - master +permissions: + contents: write + pull-requests: write +name: release-please +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v5 + with: + # this assumes that you have created a personal access token + # (PAT) and configured it as a GitHub action secret named + # `MY_RELEASE_PLEASE_TOKEN` (this secret name is not important). + token: ${{ secrets.GH_PAT }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index 7eecb62c..00000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: Release the repo - -on: - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - inputs: - versionOverride: - description: Choose a different version bump than indicated by conventional commit messages - required: true - default: '' - type: choice - options: - - '' - - 'major' - - 'minor' - - 'patch' - - 'premajor' - - 'preminor' - - 'prepatch' - - 'prerelease' - -jobs: - release: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - name: Install TS Project dependencies - run: npm ci - - name: Config git user - run: | - git config --global user.name "${{ github.actor }}" - git config --global user.email "${{ github.actor }}@users.noreply.github.com" - - name: release - run: > - npx lerna version --conventional-commits --yes --create-release github --message "chore: release" ${{ inputs.versionOverride }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml index f3c6af5d..8aca8325 100644 --- a/.github/workflows/typedoc.yml +++ b/.github/workflows/typedoc.yml @@ -9,7 +9,7 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages + # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write @@ -30,25 +30,18 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - name: Install TS Project dependencies - run: npm ci - - name: build packages - run: npx lerna run build + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + - name: Init nodejs + uses: ./.github/actions/init-pnpm - name: build docs - run: npx typedoc + run: pnpm exec typedoc - name: Setup Pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 with: # Upload docs directory path: './docs' - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..7e1c146f --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,11 @@ +{ + "packages/auth-bundler": "12.0.0", + "packages/auth-core": "12.0.0", + "packages/test-utils": "12.0.0", + "apps/auth-cron": "12.0.0", + "apps/auth-manager": "12.0.0", + "apps/token-kiosk": "12.0.0", + "apps/auth-ui": "12.0.0", + "apps/kiosk-ui": "12.0.0", + ".": "12.0.0" +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 3026ee9a..9121c9f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,8 @@ { "file": "node_modules/@map-colonies/infra-copilot-instructions/instructions/commit.md" } - ] + ], + "[github-actions-workflow]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } diff --git a/apps/auth-cron/helm/Chart.yaml b/apps/auth-cron/helm/Chart.yaml index 8dd3b16d..b8ad4498 100644 --- a/apps/auth-cron/helm/Chart.yaml +++ b/apps/auth-cron/helm/Chart.yaml @@ -3,7 +3,6 @@ name: auth-cron description: A Helm chart for auth-cron service type: application version: 1.12.0 -appVersion: 1.12.0 dependencies: - name: mclabels version: 1.0.1 diff --git a/apps/auth-cron/helm/templates/_helpers.tpl b/apps/auth-cron/helm/templates/_helpers.tpl index 3d45fdb0..1dc0abbd 100644 --- a/apps/auth-cron/helm/templates/_helpers.tpl +++ b/apps/auth-cron/helm/templates/_helpers.tpl @@ -32,8 +32,8 @@ Common labels {{- define "auth-cron.labels" -}} helm.sh/chart: {{ include "auth-cron.chart" . }} {{ include "auth-cron.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- if .Chart.Version }} +app.kubernetes.io/version: {{ .Chart.Version | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{ include "mclabels.labels" . }} @@ -43,7 +43,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} Returns the tag of the chart. */}} {{- define "auth-cron.tag" -}} -{{- default (printf "v%s" .Chart.AppVersion) .Values.image.tag }} +{{- default (printf "v%s" .Chart.Version) .Values.image.tag }} {{- end }} {{/* diff --git a/apps/auth-cron/package.json b/apps/auth-cron/package.json index b99b0462..ec695741 100644 --- a/apps/auth-cron/package.json +++ b/apps/auth-cron/package.json @@ -2,6 +2,7 @@ "name": "auth-cron", "version": "1.11.0", "description": "Server for generating and uploading Open Policy Agent bundles", + "dockerfile": "docker/backend.Dockerfile", "author": "MapColonies", "homepage": "https://github.com/MapColonies/opa-la#readme", "license": "MIT", @@ -61,6 +62,7 @@ "@vitest/coverage-v8": "catalog:", "@vitest/ui": "catalog:", "@map-colonies/vitest-utils": "catalog:", - "@map-colonies/eslint-config": "catalog:" + "@map-colonies/eslint-config": "catalog:", + "@map-colonies/tsconfig": "catalog:" } } diff --git a/apps/auth-cron/tests/configurations/vitest.globalSetup.mts b/apps/auth-cron/tests/configurations/vitest.globalSetup.mts index e18a5bb2..237574ce 100644 --- a/apps/auth-cron/tests/configurations/vitest.globalSetup.mts +++ b/apps/auth-cron/tests/configurations/vitest.globalSetup.mts @@ -1,6 +1,14 @@ import path from 'node:path'; import type { TestProject } from 'vitest/node'; -import { createMinioContainer, createS3Client, createAndProvideTempDir, removeTempDir, mergeTestConfig, ensureBucketExists } from 'test-utils'; +import { + createMinioContainer, + MINIO_PORT, + createS3Client, + createAndProvideTempDir, + removeTempDir, + mergeTestConfig, + ensureBucketExists, +} from 'test-utils'; import { getConfig, initConfig } from '@src/config.js'; export async function setup(project: TestProject): Promise { @@ -14,7 +22,7 @@ export async function setup(project: TestProject): Promise { password: cronOptions?.s3.secretAccessKey as string, }); - const endpoint = `http://${container.getHost()}:${container.getPort()}`; + const endpoint = `http://${container.getHost()}:${container.getMappedPort(MINIO_PORT)}`; await mergeTestConfig(path.join(__dirname, '../../config'), { 'cron.np.s3.endpoint': endpoint, 'cron.prod.s3.endpoint': endpoint }); diff --git a/apps/auth-manager/helm/Chart.yaml b/apps/auth-manager/helm/Chart.yaml index 7ed9daad..e4e2fbc0 100644 --- a/apps/auth-manager/helm/Chart.yaml +++ b/apps/auth-manager/helm/Chart.yaml @@ -3,7 +3,6 @@ name: auth-manager description: A Helm chart for auth-manager service type: application version: 1.12.0 -appVersion: 1.12.0 dependencies: - name: mclabels version: 1.0.1 diff --git a/apps/auth-manager/helm/templates/_helpers.tpl b/apps/auth-manager/helm/templates/_helpers.tpl index 8986add0..52440571 100644 --- a/apps/auth-manager/helm/templates/_helpers.tpl +++ b/apps/auth-manager/helm/templates/_helpers.tpl @@ -32,8 +32,8 @@ Common labels {{- define "auth-manager.labels" -}} helm.sh/chart: {{ include "auth-manager.chart" . }} {{ include "auth-manager.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- if .Chart.Version }} +app.kubernetes.io/version: {{ .Chart.Version | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{ include "mclabels.labels" . }} @@ -43,7 +43,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} Returns the tag of the chart. */}} {{- define "auth-manager.tag" -}} -{{- default (printf "v%s" .Chart.AppVersion) .Values.image.tag }} +{{- default (printf "v%s" .Chart.Version) .Values.image.tag }} {{- end }} {{/* diff --git a/apps/auth-manager/package.json b/apps/auth-manager/package.json index e4c7b085..f37e920e 100644 --- a/apps/auth-manager/package.json +++ b/apps/auth-manager/package.json @@ -2,6 +2,7 @@ "name": "auth-manager", "version": "1.12.0", "description": "API server for managing all the authentication data", + "dockerfile": "docker/backend.Dockerfile", "author": "MapColonies", "type": "commonjs", "homepage": "https://github.com/MapColonies/opa-la#readme", diff --git a/apps/auth-manager/tests/configurations/vitest.globalSetup.mts b/apps/auth-manager/tests/configurations/vitest.globalSetup.mts index fb8082ff..8ca46e44 100644 --- a/apps/auth-manager/tests/configurations/vitest.globalSetup.mts +++ b/apps/auth-manager/tests/configurations/vitest.globalSetup.mts @@ -1,8 +1,7 @@ import 'reflect-metadata'; import path from 'node:path'; import { initConnection } from '@map-colonies/auth-core'; -import { createPostgresContainer, resetAndMigrate, mergeTestConfig } from 'test-utils'; - +import { createPostgresContainer, resetAndMigrate, mergeTestConfig, PG_PORT } from 'test-utils'; import { getConfig, initConfig } from '@src/common/config.js'; export async function setup(): Promise { @@ -15,8 +14,10 @@ export async function setup(): Promise { password: dataSourceOptions.password, }); - const connection = await initConnection({ ...dataSourceOptions }); - await mergeTestConfig(path.join(__dirname, '../../config'), { port: container.getPort() }); + const port = container.getMappedPort(PG_PORT); + + const connection = await initConnection({ ...dataSourceOptions, port }); + await mergeTestConfig(path.join(__dirname, '../../config'), { 'db.port': port }); await resetAndMigrate(connection, dataSourceOptions.schema); } diff --git a/apps/token-kiosk/helm/Chart.yaml b/apps/token-kiosk/helm/Chart.yaml index b69e9ba0..0d8129a8 100644 --- a/apps/token-kiosk/helm/Chart.yaml +++ b/apps/token-kiosk/helm/Chart.yaml @@ -3,7 +3,6 @@ name: token-kiosk description: A Helm chart for token-kiosk service type: application version: 1.12.0 -appVersion: 1.12.0 dependencies: - name: mclabels version: 1.0.1 diff --git a/apps/token-kiosk/helm/templates/_helpers.tpl b/apps/token-kiosk/helm/templates/_helpers.tpl index ca4a0689..e35cb240 100644 --- a/apps/token-kiosk/helm/templates/_helpers.tpl +++ b/apps/token-kiosk/helm/templates/_helpers.tpl @@ -36,8 +36,8 @@ Common labels {{- define "token-kiosk.labels" -}} helm.sh/chart: {{ include "token-kiosk.chart" . }} {{ include "token-kiosk.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- if .Chart.Version }} +app.kubernetes.io/version: {{ .Chart.Version | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{ include "mclabels.labels" . }} @@ -47,7 +47,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} Returns the tag of the chart. */}} {{- define "token-kiosk.tag" -}} -{{- default (printf "v%s" .Chart.AppVersion) .Values.image.tag }} +{{- default (printf "v%s" .Chart.Version) .Values.image.tag }} {{- end }} {{/* diff --git a/apps/token-kiosk/package.json b/apps/token-kiosk/package.json index a3684d64..8f68348b 100644 --- a/apps/token-kiosk/package.json +++ b/apps/token-kiosk/package.json @@ -2,6 +2,7 @@ "name": "token-kiosk", "version": "1.12.0", "description": "UI for requesting temporary access tokens for Map Colonies services", + "dockerfile": "docker/backend.Dockerfile", "main": "./src/index.ts", "scripts": { "test": "vitest run", diff --git a/apps/token-kiosk/tests/configurations/vitest.globalSetup.mts b/apps/token-kiosk/tests/configurations/vitest.globalSetup.mts index f2af3427..c4cd9995 100644 --- a/apps/token-kiosk/tests/configurations/vitest.globalSetup.mts +++ b/apps/token-kiosk/tests/configurations/vitest.globalSetup.mts @@ -1,5 +1,5 @@ import path from 'node:path'; -import { createPostgresContainer, mergeTestConfig } from 'test-utils'; +import { createPostgresContainer, mergeTestConfig, PG_PORT } from 'test-utils'; import { initConnection, createConnectionOptions, createDrizzle, runMigrations } from '@src/db/createConnection.js'; import { getConfig, initConfig } from '@src/common/config.js'; @@ -13,9 +13,10 @@ export async function setup(): Promise { password: config.password, }); - await mergeTestConfig(path.join(__dirname, '../../config'), { 'db.port': container.getPort() }); + const port = container.getMappedPort(PG_PORT); + await mergeTestConfig(path.join(__dirname, '../../config'), { 'db.port': port }); - const pool = await initConnection(createConnectionOptions({ ...config, port: container.getPort() })); + const pool = await initConnection(createConnectionOptions({ ...config, port })); const drizzle = createDrizzle(pool); await runMigrations(drizzle); await pool.end(); diff --git a/helm/.helmignore b/helm/.helmignore index 361e7716..e44282c3 100644 --- a/helm/.helmignore +++ b/helm/.helmignore @@ -23,3 +23,4 @@ *.tmproj .vscode/ Chart.lock +*.tgz diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 66d29f61..9d635bed 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -7,20 +7,15 @@ dependencies: - name: opa repository: file://charts/opa condition: opa.enabled - version: 1.12.0 - name: auth-cron repository: file://../packages/auth-cron/helm - version: 1.12.0 condition: auth-cron.enabled - name: auth-manager repository: file://../packages/auth-manager/helm - version: 1.12.0 condition: auth-manager.enabled - name: auth-ui repository: file://../packages/auth-ui/helm - version: 1.12.0 condition: auth-ui.enabled - name: token-kiosk repository: file://../packages/token-kiosk/helm - version: 1.12.0 condition: token-kiosk.enabled diff --git a/knip.config.ts b/knip.config.ts index 5f990c85..4bd27949 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -9,8 +9,8 @@ const config: KnipConfig = { interface: true, type: true, }, - ignoreBinaries: ['lerna'], - ignoreFiles: ['example/**'], + ignoreBinaries: ['helm'], + ignoreFiles: ['example/**', 'scripts/generate-matrix.mjs'], ignoreDependencies: ['@map-colonies/infra-copilot-instructions', '@vitest/eslint-plugin'], workspaces: { 'packages/auth-core': { diff --git a/package.json b/package.json index 4d690b50..f4ec0610 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "prelint:fix": "pnpm run format:fix", "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", + "lint:openapi": "turbo run lint:openapi", "build": "turbo run build", "check-dist": "turbo run check-dist", "knip": "knip", @@ -24,7 +25,6 @@ "@commitlint/config-pnpm-scopes": "^20.4.3", "@map-colonies/infra-copilot-instructions": "^1.1.0", "@map-colonies/prettier-config": "^0.0.1", - "@map-colonies/tsconfig": "^2.0.0", "@redocly/cli": "^1.34.2", "cross-env": "^7.0.3", "eslint": "catalog:", diff --git a/packages/auth-bundler/package.json b/packages/auth-bundler/package.json index d219009c..7d5229d3 100644 --- a/packages/auth-bundler/package.json +++ b/packages/auth-bundler/package.json @@ -47,6 +47,7 @@ "devDependencies": { "@map-colonies/config": "catalog:", "@map-colonies/schemas": "catalog:", + "@map-colonies/tsconfig": "catalog:", "@map-colonies/eslint-config": "catalog:", "test-utils": "workspace:^", "@types/node": "catalog:", diff --git a/packages/auth-bundler/tests/configurations/vitest.globalSetup.mts b/packages/auth-bundler/tests/configurations/vitest.globalSetup.mts index 8567dc4e..1f7e9d0d 100644 --- a/packages/auth-bundler/tests/configurations/vitest.globalSetup.mts +++ b/packages/auth-bundler/tests/configurations/vitest.globalSetup.mts @@ -1,7 +1,7 @@ import path from 'node:path'; import { initConnection } from '@map-colonies/auth-core'; import type { TestProject } from 'vitest/node'; -import { createPostgresContainer, createAndProvideTempDir, removeTempDir, resetAndMigrate, mergeTestConfig } from 'test-utils'; +import { createPostgresContainer, PG_PORT, createAndProvideTempDir, removeTempDir, resetAndMigrate, mergeTestConfig } from 'test-utils'; import { getConfig, initConfig } from '../helpers/config.js'; export async function setup(project: TestProject): Promise { @@ -16,9 +16,11 @@ export async function setup(project: TestProject): Promise { password: dataSourceOptions.password, }); - await mergeTestConfig(path.join(__dirname, '../../config'), { port: container.getPort() }); + const port = container.getMappedPort(PG_PORT); - const connection = await initConnection({ ...dataSourceOptions, port: container.getPort() }); + await mergeTestConfig(path.join(__dirname, '../../config'), { port }); + + const connection = await initConnection({ ...dataSourceOptions, port }); await resetAndMigrate(connection, dataSourceOptions.schema); } diff --git a/packages/test-utils/src/containers.ts b/packages/test-utils/src/containers.ts index cb1051fa..4e191f85 100644 --- a/packages/test-utils/src/containers.ts +++ b/packages/test-utils/src/containers.ts @@ -4,6 +4,8 @@ import { MinioContainer, type StartedMinioContainer } from '@testcontainers/mini const POSTGRES_IMAGE = 'postgres:15'; const MINIO_IMAGE = 'minio/minio:latest'; +export const PG_PORT = 5432; + export async function createPostgresContainer(options: { username: string; database: string; @@ -18,6 +20,8 @@ export async function createPostgresContainer(options: { return container.withUsername(options.username).withDatabase(options.database).withPassword(options.password).start(); } +export const MINIO_PORT = 9000; + export async function createMinioContainer(options: { username: string; password: string }): Promise { const container = new MinioContainer(MINIO_IMAGE); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c444a0af..fcae60e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,9 +80,6 @@ importers: '@map-colonies/prettier-config': specifier: ^0.0.1 version: 0.0.1 - '@map-colonies/tsconfig': - specifier: ^2.0.0 - version: 2.0.0 '@redocly/cli': specifier: ^1.34.2 version: 1.34.11(ajv@8.18.0)(encoding@0.1.13) @@ -180,6 +177,9 @@ importers: '@map-colonies/eslint-config': specifier: 'catalog:' version: 8.1.0(@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@vitest/eslint-plugin@1.6.15(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)(vitest@4.1.4))(eslint-plugin-jest@28.14.0(@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@24.12.0)(typescript@5.9.3)))(typescript@5.9.3))(eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(globals@15.15.0)(typescript@5.9.3) + '@map-colonies/tsconfig': + specifier: 'catalog:' + version: 2.0.0 '@map-colonies/vitest-utils': specifier: 'catalog:' version: 0.2.0(jest-extended@7.0.0(jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@24.12.0)(typescript@5.9.3)))(typescript@5.9.3))(jest-openapi@0.14.2)(vitest@4.1.4) @@ -818,6 +818,9 @@ importers: '@map-colonies/schemas': specifier: 'catalog:' version: 1.19.0 + '@map-colonies/tsconfig': + specifier: 'catalog:' + version: 2.0.0 '@map-colonies/vitest-utils': specifier: 'catalog:' version: 0.2.0(jest-extended@7.0.0(jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@24.12.0)(typescript@5.9.3)))(typescript@5.9.3))(jest-openapi@0.14.2)(vitest@4.1.4) diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..311a30c7 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,140 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "changelog-sections": [ + { + "section": "🎉 Features", + "type": "feat" + }, + { + "section": "🐛 Bug Fixes", + "type": "fix" + }, + { + "section": "⚡ Performance Improvements", + "type": "perf" + }, + { "type": "helm", "section": "Helm Changes", "hidden": false }, + { + "section": "🔗 Dependencies", + "type": "deps" + }, + { + "section": "📝 Documentation", + "type": "docs" + }, + { + "section": "🏗️ Build System", + "type": "build", + "hidden": true + }, + { + "section": "🤖 Continuous Integration", + "type": "ci", + "hidden": true + }, + { + "section": "🔧 Miscellaneous Chores", + "type": "chore", + "hidden": true + }, + { + "section": "⏪ Reverts", + "type": "revert" + }, + { + "section": "✅ Tests", + "type": "test", + "hidden": true + }, + { + "section": "💄 Style", + "type": "style", + "hidden": true + }, + { + "section": "♻️ Code Refactoring", + "type": "refactor", + "hidden": true + } + ], + "draft-pull-request": false, + "include-v-in-tag": true, + "separate-pull-requests": false, + "pull-request-title-pattern": "chore(global): release${component} ${version}", + "plugins": [ + { + "type": "linked-versions", + "groupName": "all", + "components": ["auth-bundler", "auth-core", "test-utils", "auth-cron", "auth-manager", "token-kiosk", "auth-ui", "kiosk-ui", "root"] + } + ], + "packages": { + "packages/auth-bundler": { + "release-type": "node", + "component": "auth-bundler", + "skip-changelog": true + }, + "packages/auth-core": { + "release-type": "node", + "component": "auth-core", + "skip-changelog": true + }, + "packages/test-utils": { + "release-type": "node", + "component": "test-utils", + "skip-changelog": true + }, + "apps/auth-cron": { + "release-type": "node", + "component": "auth-cron", + "skip-changelog": true + }, + "apps/auth-manager": { + "release-type": "node", + "component": "auth-manager", + "skip-changelog": true, + "extra-files": [ + { + "type": "yaml", + "path": "openapi3.yaml", + "jsonpath": "$.info.version" + } + ] + }, + "apps/token-kiosk": { + "release-type": "node", + "component": "token-kiosk", + "skip-changelog": true, + "extra-files": [ + { + "type": "yaml", + "path": "openapi3.yaml", + "jsonpath": "$.info.version" + } + ] + }, + "apps/auth-ui": { + "release-type": "node", + "component": "auth-ui", + "skip-changelog": true + }, + "apps/kiosk-ui": { + "release-type": "node", + "component": "kiosk-ui", + "skip-changelog": true + }, + ".": { + "release-type": "node", + "component": "root", + "skip-changelog": true, + "extra-files": [ + { + "type": "yaml", + "glob": true, + "path": "**/Chart.yaml", + "jsonpath": "$.version" + } + ] + } + } +} diff --git a/scripts/generate-matrix.mjs b/scripts/generate-matrix.mjs new file mode 100644 index 00000000..29219b80 --- /dev/null +++ b/scripts/generate-matrix.mjs @@ -0,0 +1,24 @@ +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; + +// 1. Get the dynamic list from Turbo +const output = execSync('pnpm exec turbo ls --output=json --filter="./apps/*"').toString(); +const { packages } = JSON.parse(output); +// 2. Map over the packages to extract your custom metadata +const matrix = packages.items + .map((pkg) => { + const pkgJsonPath = path.join(pkg.path, 'package.json'); + const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')); + + return { + service: pkg.name, + // Provide a safe fallback just in case someone forgets to add it + dockerfile: pkgJson.dockerfile, + version: pkgJson.version, + }; + }) + .filter((item) => item.dockerfile); // Filter out packages that don't have a dockerfile field + +// 3. Output the raw JSON string (GitHub Actions needs it printed to stdout) +console.log(JSON.stringify(matrix)); diff --git a/turbo.json b/turbo.json index da617dfd..aaac7a3a 100644 --- a/turbo.json +++ b/turbo.json @@ -17,6 +17,9 @@ "lint:fix": { "dependsOn": [] }, + "lint:openapi": { + "dependsOn": [] + }, "test": { "dependsOn": [] },