diff --git a/.gitignore b/.gitignore index 01c8bbf..36345c2 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ tmp/ # Generated migration files (local testing) /migrations/ *.sql +scripts/.cache/ diff --git a/templates/django/config.json b/templates/django/config.json index e9a3ee0..3fdc5ea 100644 --- a/templates/django/config.json +++ b/templates/django/config.json @@ -42,6 +42,7 @@ "options": [ "pip", "poetry", + "uv", "pipenv" ], "type": "select", diff --git a/templates/django/template.tmpl b/templates/django/template.tmpl index 38aa0bb..9e780dd 100644 --- a/templates/django/template.tmpl +++ b/templates/django/template.tmpl @@ -9,6 +9,11 @@ RUN pip install --no-cache-dir --user -r requirements.txt {{ .wsgi_server }} RUN pip install --no-cache-dir poetry COPY pyproject.toml poetry.lock* ./ RUN poetry config virtualenvs.create false && poetry install --only main --no-root && pip install --no-cache-dir {{ .wsgi_server }} +{{ else if eq .dependency_manager "uv" }} +RUN pip install --no-cache-dir uv +COPY pyproject.toml uv.lock* ./ +RUN uv pip install --system --no-cache-dir . && \ + uv pip install --system --no-cache-dir {{ .wsgi_server }} {{ else }} RUN pip install --no-cache-dir pipenv COPY Pipfile Pipfile.lock* ./ diff --git a/templates/expressjs/config.json b/templates/expressjs/config.json index df5af99..127c297 100644 --- a/templates/expressjs/config.json +++ b/templates/expressjs/config.json @@ -35,7 +35,8 @@ "options": [ "npm", "yarn", - "pnpm" + "pnpm", + "bun" ], "type": "select", "category": "required" diff --git a/templates/expressjs/template.tmpl b/templates/expressjs/template.tmpl index 128cb61..e9698a3 100644 --- a/templates/expressjs/template.tmpl +++ b/templates/expressjs/template.tmpl @@ -1,4 +1,8 @@ +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine +{{ else }} FROM node:{{ .node_version }}-alpine +{{ end }} WORKDIR /app @@ -6,9 +10,11 @@ WORKDIR /app COPY package*.json ./ {{ else if eq .package_manager "yarn" }} COPY package.json yarn.lock* ./ -{{ else }} +{{ else if eq .package_manager "pnpm" }} COPY package.json pnpm-lock.yaml* ./ RUN npm install -g pnpm +{{ else }} +COPY package.json bun.lockb* ./ {{ end }} {{ if eq .build_mode "production" }} @@ -16,16 +22,20 @@ RUN npm install -g pnpm RUN npm install --only=production --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} RUN yarn install --production -{{ else }} +{{ else if eq .package_manager "pnpm" }} RUN pnpm install --prod +{{ else }} +RUN bun install --production {{ end }} {{ else }} {{ if eq .package_manager "npm" }} RUN npm install --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} RUN yarn install -{{ else }} +{{ else if eq .package_manager "pnpm" }} RUN pnpm install +{{ else }} +RUN bun install {{ end }} {{ end }} @@ -46,5 +56,9 @@ CMD ["pm2-runtime", "start", "{{ .entry_file }}", "--name", "express-app"] {{ else if eq .process_manager "nodemon" }} CMD ["nodemon", "{{ .entry_file }}"] {{ else }} +{{ if eq .package_manager "bun" }} +CMD ["bun", "run", "{{ .entry_file }}"] +{{ else }} CMD ["node", "{{ .entry_file }}"] +{{ end }} {{ end }} \ No newline at end of file diff --git a/templates/fastapi/config.json b/templates/fastapi/config.json index 0fd1132..172122e 100644 --- a/templates/fastapi/config.json +++ b/templates/fastapi/config.json @@ -38,6 +38,7 @@ "options": [ "pip", "poetry", + "uv", "pipenv" ], "type": "select", diff --git a/templates/fastapi/template.tmpl b/templates/fastapi/template.tmpl index 77394df..989d41b 100644 --- a/templates/fastapi/template.tmpl +++ b/templates/fastapi/template.tmpl @@ -9,6 +9,11 @@ RUN pip install --no-cache-dir --user -r requirements.txt {{ .asgi_server }} RUN pip install --no-cache-dir poetry COPY pyproject.toml poetry.lock* ./ RUN poetry config virtualenvs.create false && poetry install --only main --no-root && pip install --no-cache-dir {{ .asgi_server }} +{{ else if eq .dependency_manager "uv" }} +RUN pip install --no-cache-dir uv +COPY pyproject.toml uv.lock* ./ +RUN uv pip install --system --no-cache-dir . && \ + uv pip install --system --no-cache-dir {{ .asgi_server }} {{ else }} RUN pip install --no-cache-dir pipenv COPY Pipfile Pipfile.lock* ./ diff --git a/templates/flask/config.json b/templates/flask/config.json index fe46597..18c8f6a 100644 --- a/templates/flask/config.json +++ b/templates/flask/config.json @@ -42,6 +42,7 @@ "options": [ "pip", "poetry", + "uv", "pipenv" ], "type": "select", diff --git a/templates/flask/template.tmpl b/templates/flask/template.tmpl index 5814574..0faa871 100644 --- a/templates/flask/template.tmpl +++ b/templates/flask/template.tmpl @@ -9,6 +9,11 @@ RUN pip install --no-cache-dir -r requirements.txt {{ .wsgi_server }} RUN pip install --no-cache-dir poetry COPY pyproject.toml poetry.lock* ./ RUN poetry config virtualenvs.create false && poetry install --only main --no-root && pip install --no-cache-dir {{ .wsgi_server }} +{{ else if eq .dependency_manager "uv" }} +RUN pip install --no-cache-dir uv +COPY pyproject.toml uv.lock* ./ +RUN uv pip install --system --no-cache-dir . && \ + uv pip install --system --no-cache-dir {{ .wsgi_server }} {{ else }} RUN pip install --no-cache-dir pipenv COPY Pipfile Pipfile.lock* ./ diff --git a/templates/nestjs/config.json b/templates/nestjs/config.json index 579eb68..c7d1d25 100644 --- a/templates/nestjs/config.json +++ b/templates/nestjs/config.json @@ -35,7 +35,8 @@ "options": [ "npm", "yarn", - "pnpm" + "pnpm", + "bun" ], "type": "select", "category": "required" diff --git a/templates/nestjs/template.tmpl b/templates/nestjs/template.tmpl index 6fc1afa..aba25d9 100644 --- a/templates/nestjs/template.tmpl +++ b/templates/nestjs/template.tmpl @@ -1,4 +1,8 @@ +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine AS builder +{{ else }} FROM node:{{ .node_version }}-alpine AS builder +{{ end }} WORKDIR /app @@ -8,9 +12,12 @@ RUN npm install --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} COPY package.json yarn.lock* ./ RUN yarn install -{{ else }} +{{ else if eq .package_manager "pnpm" }} COPY package.json pnpm-lock.yaml* ./ RUN npm install -g pnpm && pnpm install +{{ else }} +COPY package.json bun.lockb* ./ +RUN bun install {{ end }} COPY . . @@ -19,11 +26,17 @@ COPY . . RUN npm run build {{ else if eq .package_manager "yarn" }} RUN yarn build -{{ else }} +{{ else if eq .package_manager "pnpm" }} RUN pnpm build +{{ else }} +RUN bun run build {{ end }} +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine +{{ else }} FROM node:{{ .node_version }}-alpine +{{ end }} WORKDIR /app @@ -33,13 +46,20 @@ RUN npm install --only=production --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} COPY package.json yarn.lock* ./ RUN yarn install --production -{{ else }} +{{ else if eq .package_manager "pnpm" }} COPY package.json pnpm-lock.yaml* ./ RUN npm install -g pnpm && pnpm install --prod +{{ else }} +COPY package.json bun.lockb* ./ +RUN bun install --production {{ end }} COPY --from=builder /app/dist ./dist EXPOSE 3000 -CMD ["node", "dist/main"] \ No newline at end of file +{{ if eq .package_manager "bun" }} +CMD ["bun", "run", "dist/main"] +{{ else }} +CMD ["node", "dist/main"] +{{ end }} \ No newline at end of file diff --git a/templates/nextjs/config.json b/templates/nextjs/config.json index fbb8f9d..7d8039e 100644 --- a/templates/nextjs/config.json +++ b/templates/nextjs/config.json @@ -35,7 +35,8 @@ "options": [ "npm", "yarn", - "pnpm" + "pnpm", + "bun" ], "type": "select", "category": "required" diff --git a/templates/nextjs/template.tmpl b/templates/nextjs/template.tmpl index c5998cb..a1aac0d 100644 --- a/templates/nextjs/template.tmpl +++ b/templates/nextjs/template.tmpl @@ -1,4 +1,8 @@ +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine AS deps +{{ else }} FROM node:{{ .node_version }}-alpine AS deps +{{ end }} WORKDIR /app @@ -8,12 +12,19 @@ RUN npm install --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} COPY package.json yarn.lock* ./ RUN yarn install -{{ else }} +{{ else if eq .package_manager "pnpm" }} COPY package.json pnpm-lock.yaml* ./ RUN npm install -g pnpm && pnpm install +{{ else }} +COPY package.json bun.lockb* ./ +RUN bun install {{ end }} +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine AS builder +{{ else }} FROM node:{{ .node_version }}-alpine AS builder +{{ end }} WORKDIR /app @@ -30,11 +41,17 @@ RUN mkdir -p public RUN npm run build {{ else if eq .package_manager "yarn" }} RUN yarn build -{{ else }} +{{ else if eq .package_manager "pnpm" }} RUN pnpm build +{{ else }} +RUN bun run build {{ end }} +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine AS runner +{{ else }} FROM node:{{ .node_version }}-alpine AS runner +{{ end }} WORKDIR /app @@ -50,7 +67,7 @@ RUN npm install -g pnpm COPY --from=deps /app/node_modules ./node_modules COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next COPY --from=builder /app/public ./public -COPY --from=builder /app/package.json ./package.json +COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json USER nextjs @@ -60,6 +77,8 @@ EXPOSE 3000 CMD ["npm", "start"] {{ else if eq .package_manager "yarn" }} CMD ["yarn", "start"] -{{ else }} +{{ else if eq .package_manager "pnpm" }} CMD ["pnpm", "start"] +{{ else }} +CMD ["bun", "--bun", "run", "start"] {{ end }} \ No newline at end of file diff --git a/templates/react/config.json b/templates/react/config.json index 199452c..ba9cc5c 100644 --- a/templates/react/config.json +++ b/templates/react/config.json @@ -37,7 +37,8 @@ "options": [ "npm", "yarn", - "pnpm" + "pnpm", + "bun" ], "type": "select", "category": "required" diff --git a/templates/react/template.tmpl b/templates/react/template.tmpl index 9138fc8..cce021d 100644 --- a/templates/react/template.tmpl +++ b/templates/react/template.tmpl @@ -1,4 +1,8 @@ +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine AS builder +{{ else }} FROM node:{{ .node_version }}-alpine AS builder +{{ end }} WORKDIR /app @@ -8,9 +12,12 @@ RUN npm install --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} COPY package.json yarn.lock* ./ RUN yarn install -{{ else }} +{{ else if eq .package_manager "pnpm" }} COPY package.json pnpm-lock.yaml* ./ RUN npm install -g pnpm && pnpm install +{{ else }} +COPY package.json bun.lockb* ./ +RUN bun install {{ end }} COPY . . @@ -19,8 +26,10 @@ COPY . . RUN npm run build {{ else if eq .package_manager "yarn" }} RUN yarn build -{{ else }} +{{ else if eq .package_manager "pnpm" }} RUN pnpm build +{{ else }} +RUN bun run build {{ end }} FROM nginx:alpine diff --git a/templates/vuejs/config.json b/templates/vuejs/config.json index ada0c88..c95321e 100644 --- a/templates/vuejs/config.json +++ b/templates/vuejs/config.json @@ -37,7 +37,8 @@ "options": [ "npm", "yarn", - "pnpm" + "pnpm", + "bun" ], "type": "select", "category": "required" diff --git a/templates/vuejs/template.tmpl b/templates/vuejs/template.tmpl index 05c7a38..2d9ecf8 100644 --- a/templates/vuejs/template.tmpl +++ b/templates/vuejs/template.tmpl @@ -1,4 +1,8 @@ +{{ if eq .package_manager "bun" }} +FROM oven/bun:1-alpine AS builder +{{ else }} FROM node:{{ .node_version }}-alpine AS builder +{{ end }} WORKDIR /app {{ if eq .package_manager "npm" }} @@ -7,9 +11,12 @@ RUN npm install --no-audit --prefer-offline {{ else if eq .package_manager "yarn" }} COPY package.json yarn.lock* ./ RUN yarn install -{{ else }} +{{ else if eq .package_manager "pnpm" }} COPY package.json pnpm-lock.yaml* ./ RUN npm install -g pnpm && pnpm install +{{ else }} +COPY package.json bun.lockb* ./ +RUN bun install {{ end }} COPY . . @@ -18,8 +25,10 @@ COPY . . RUN npm run build {{ else if eq .package_manager "yarn" }} RUN yarn build -{{ else }} +{{ else if eq .package_manager "pnpm" }} RUN pnpm build +{{ else }} +RUN bun run build {{ end }} FROM nginx:alpine diff --git a/test-projects/backend/django-uv/Dockerfile b/test-projects/backend/django-uv/Dockerfile new file mode 100644 index 0000000..47a6989 --- /dev/null +++ b/test-projects/backend/django-uv/Dockerfile @@ -0,0 +1,30 @@ +FROM python:3.12-slim AS builder + +WORKDIR /app + +RUN pip install --no-cache-dir uv +COPY pyproject.toml uv.lock* ./ +RUN uv pip install --system --no-cache-dir . && \ + uv pip install --system --no-cache-dir gunicorn + +FROM python:3.12-slim + +WORKDIR /app + +COPY --from=builder /usr/local/lib /usr/local/lib +COPY --from=builder /usr/local/bin /usr/local/bin + +COPY . . + +ENV DJANGO_SETTINGS_MODULE=config.settings +RUN python manage.py collectstatic --noinput || echo "Warning: collectstatic failed, continuing..." + +RUN addgroup --system --gid 1001 app && \ + adduser --system --uid 1001 --gid 1001 app && \ + chown -R app:app /app + +USER app + +EXPOSE 8000 + +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "config.wsgi"] diff --git a/test-projects/backend/django-uv/config/__init__.py b/test-projects/backend/django-uv/config/__init__.py new file mode 100644 index 0000000..233c831 --- /dev/null +++ b/test-projects/backend/django-uv/config/__init__.py @@ -0,0 +1 @@ +# Django configuration package diff --git a/test-projects/backend/django-uv/config/settings.py b/test-projects/backend/django-uv/config/settings.py new file mode 100644 index 0000000..55a5b2f --- /dev/null +++ b/test-projects/backend/django-uv/config/settings.py @@ -0,0 +1,58 @@ +""" +Django settings for django-uv-test project. +""" + +from pathlib import Path + +BASE_DIR = Path(__file__).resolve().parent.parent + +SECRET_KEY = 'django-insecure-test-key-for-uv-template-testing-only' + +DEBUG = True + +ALLOWED_HOSTS = ['*'] + +INSTALLED_APPS = [ + 'django.contrib.contenttypes', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.middleware.common.CommonMiddleware', +] + +ROOT_URLCONF = 'config.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + ], + }, + }, +] + +WSGI_APPLICATION = 'config.wsgi.application' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + +LANGUAGE_CODE = 'en-us' +TIME_ZONE = 'UTC' +USE_I18N = True +USE_TZ = True + +STATIC_URL = 'static/' +STATIC_ROOT = BASE_DIR / 'staticfiles' + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/test-projects/backend/django-uv/config/urls.py b/test-projects/backend/django-uv/config/urls.py new file mode 100644 index 0000000..cc845e6 --- /dev/null +++ b/test-projects/backend/django-uv/config/urls.py @@ -0,0 +1,19 @@ +""" +URL configuration for django-uv-test project. +""" +from django.http import JsonResponse +from django.urls import path + + +def hello_world(request): + return JsonResponse({ + 'message': 'Hello from Django with uv!', + 'dependency_manager': 'uv', + 'framework': 'Django' + }) + + +urlpatterns = [ + path('', hello_world), + path('health/', hello_world), +] diff --git a/test-projects/backend/django-uv/config/wsgi.py b/test-projects/backend/django-uv/config/wsgi.py new file mode 100644 index 0000000..409fc63 --- /dev/null +++ b/test-projects/backend/django-uv/config/wsgi.py @@ -0,0 +1,11 @@ +""" +WSGI config for django-uv-test project. +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + +application = get_wsgi_application() diff --git a/test-projects/backend/django-uv/manage.py b/test-projects/backend/django-uv/manage.py new file mode 100644 index 0000000..8e7ac79 --- /dev/null +++ b/test-projects/backend/django-uv/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/test-projects/backend/django-uv/pyproject.toml b/test-projects/backend/django-uv/pyproject.toml new file mode 100644 index 0000000..c77fc18 --- /dev/null +++ b/test-projects/backend/django-uv/pyproject.toml @@ -0,0 +1,8 @@ +[project] +name = "django-uv-test" +version = "0.1.0" +description = "Django test project with uv dependency manager" +requires-python = ">=3.12" +dependencies = [ + "django>=5.0,<6.0", +] diff --git a/test-projects/backend/expressjs-bun-prod-none/Dockerfile b/test-projects/backend/expressjs-bun-prod-none/Dockerfile new file mode 100644 index 0000000..847dab9 --- /dev/null +++ b/test-projects/backend/expressjs-bun-prod-none/Dockerfile @@ -0,0 +1,15 @@ +FROM oven/bun:1-alpine + +WORKDIR /app + +COPY package.json bun.lockb* ./ + +RUN bun install + +COPY . . + +ENV NODE_ENV=production + +EXPOSE 3000 + +CMD ["bun", "run", "index.js"] diff --git a/test-projects/backend/expressjs-bun-prod-none/index.js b/test-projects/backend/expressjs-bun-prod-none/index.js new file mode 100644 index 0000000..5d0b65f --- /dev/null +++ b/test-projects/backend/expressjs-bun-prod-none/index.js @@ -0,0 +1,21 @@ +import express from 'express'; + +const app = express(); +const PORT = process.env.PORT || 3000; + +app.get('/', (req, res) => { + res.json({ + message: 'Hello from Express.js with Bun!', + package_manager: 'bun', + framework: 'Express.js', + runtime: 'Bun' + }); +}); + +app.get('/health', (req, res) => { + res.json({ status: 'healthy' }); +}); + +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); +}); diff --git a/test-projects/backend/expressjs-bun-prod-none/package.json b/test-projects/backend/expressjs-bun-prod-none/package.json new file mode 100644 index 0000000..8861613 --- /dev/null +++ b/test-projects/backend/expressjs-bun-prod-none/package.json @@ -0,0 +1,12 @@ +{ + "name": "expressjs-bun-test", + "version": "0.1.0", + "type": "module", + "scripts": { + "start": "bun run index.js", + "dev": "bun run --watch index.js" + }, + "dependencies": { + "express": "^4.18.0" + } +} diff --git a/test-projects/backend/fastapi-uv/Dockerfile b/test-projects/backend/fastapi-uv/Dockerfile new file mode 100644 index 0000000..c029d09 --- /dev/null +++ b/test-projects/backend/fastapi-uv/Dockerfile @@ -0,0 +1,28 @@ +FROM python:3.12-slim AS builder + +WORKDIR /app + +RUN pip install --no-cache-dir uv +COPY pyproject.toml uv.lock* ./ +RUN uv pip install --system --no-cache-dir . && \ + uv pip install --system --no-cache-dir uvicorn + +FROM python:3.12-slim + +WORKDIR /app + +RUN addgroup --system --gid 1001 app && \ + adduser --system --uid 1001 --gid 1001 app + +COPY --from=builder /usr/local/lib /usr/local/lib +COPY --from=builder /usr/local/bin /usr/local/bin + +COPY . . + +RUN chown -R app:app /app + +USER app + +EXPOSE 8000 + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] diff --git a/test-projects/backend/fastapi-uv/main.py b/test-projects/backend/fastapi-uv/main.py new file mode 100644 index 0000000..a0cee3b --- /dev/null +++ b/test-projects/backend/fastapi-uv/main.py @@ -0,0 +1,20 @@ +""" +FastAPI test application with uv dependency manager +""" +from fastapi import FastAPI + +app = FastAPI(title="FastAPI uv Test") + + +@app.get("/") +async def root(): + return { + "message": "Hello from FastAPI with uv!", + "dependency_manager": "uv", + "framework": "FastAPI" + } + + +@app.get("/health") +async def health(): + return {"status": "healthy"} diff --git a/test-projects/backend/fastapi-uv/pyproject.toml b/test-projects/backend/fastapi-uv/pyproject.toml new file mode 100644 index 0000000..9305726 --- /dev/null +++ b/test-projects/backend/fastapi-uv/pyproject.toml @@ -0,0 +1,8 @@ +[project] +name = "fastapi-uv-test" +version = "0.1.0" +description = "FastAPI test project with uv dependency manager" +requires-python = ">=3.12" +dependencies = [ + "fastapi>=0.100.0", +] diff --git a/test-projects/backend/flask-uv/Dockerfile b/test-projects/backend/flask-uv/Dockerfile new file mode 100644 index 0000000..ad9c654 --- /dev/null +++ b/test-projects/backend/flask-uv/Dockerfile @@ -0,0 +1,20 @@ +FROM python:3.12-slim + +WORKDIR /app + +RUN pip install --no-cache-dir uv +COPY pyproject.toml uv.lock* ./ +RUN uv pip install --system --no-cache-dir . && \ + uv pip install --system --no-cache-dir gunicorn + +COPY . . + +RUN addgroup --system --gid 1001 app && \ + adduser --system --uid 1001 --gid 1001 app && \ + chown -R app:app /app + +USER app + +EXPOSE 8000 + +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "app:app"] diff --git a/test-projects/backend/flask-uv/app.py b/test-projects/backend/flask-uv/app.py new file mode 100644 index 0000000..7037f7f --- /dev/null +++ b/test-projects/backend/flask-uv/app.py @@ -0,0 +1,24 @@ +""" +Flask test application with uv dependency manager +""" +from flask import Flask, jsonify + +app = Flask(__name__) + + +@app.route('/') +def hello(): + return jsonify({ + 'message': 'Hello from Flask with uv!', + 'dependency_manager': 'uv', + 'framework': 'Flask' + }) + + +@app.route('/health') +def health(): + return jsonify({'status': 'healthy'}) + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) diff --git a/test-projects/backend/flask-uv/pyproject.toml b/test-projects/backend/flask-uv/pyproject.toml new file mode 100644 index 0000000..9ea8893 --- /dev/null +++ b/test-projects/backend/flask-uv/pyproject.toml @@ -0,0 +1,8 @@ +[project] +name = "flask-uv-test" +version = "0.1.0" +description = "Flask test project with uv dependency manager" +requires-python = ">=3.12" +dependencies = [ + "flask>=3.0.0", +] diff --git a/test-projects/backend/nestjs-bun/Dockerfile b/test-projects/backend/nestjs-bun/Dockerfile new file mode 100644 index 0000000..e5e2476 --- /dev/null +++ b/test-projects/backend/nestjs-bun/Dockerfile @@ -0,0 +1,23 @@ +FROM oven/bun:1-alpine AS builder + +WORKDIR /app + +COPY package.json bun.lockb* ./ +RUN bun install + +COPY . . + +RUN bun run build + +FROM oven/bun:1-alpine + +WORKDIR /app + +COPY package.json bun.lockb* ./ +RUN bun install --production + +COPY --from=builder /app/dist ./dist + +EXPOSE 3000 + +CMD ["bun", "run", "dist/main"] diff --git a/test-projects/backend/nestjs-bun/nest-cli.json b/test-projects/backend/nestjs-bun/nest-cli.json new file mode 100644 index 0000000..f9aa683 --- /dev/null +++ b/test-projects/backend/nestjs-bun/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/test-projects/backend/nestjs-bun/package.json b/test-projects/backend/nestjs-bun/package.json new file mode 100644 index 0000000..318511c --- /dev/null +++ b/test-projects/backend/nestjs-bun/package.json @@ -0,0 +1,23 @@ +{ + "name": "nestjs-bun-test", + "version": "0.1.0", + "scripts": { + "build": "nest build", + "start": "node dist/main", + "start:dev": "nest start --watch" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.0" + }, + "devDependencies": { + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@types/express": "^4.17.0", + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + } +} diff --git a/test-projects/backend/nestjs-bun/src/app.controller.ts b/test-projects/backend/nestjs-bun/src/app.controller.ts new file mode 100644 index 0000000..b698b3e --- /dev/null +++ b/test-projects/backend/nestjs-bun/src/app.controller.ts @@ -0,0 +1,17 @@ +import { Controller, Get } from '@nestjs/common'; +import { AppService } from './app.service'; + +@Controller() +export class AppController { + constructor(private readonly appService: AppService) {} + + @Get() + getHello() { + return this.appService.getHello(); + } + + @Get('health') + getHealth() { + return { status: 'healthy' }; + } +} diff --git a/test-projects/backend/nestjs-bun/src/app.module.ts b/test-projects/backend/nestjs-bun/src/app.module.ts new file mode 100644 index 0000000..8662803 --- /dev/null +++ b/test-projects/backend/nestjs-bun/src/app.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; + +@Module({ + imports: [], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} diff --git a/test-projects/backend/nestjs-bun/src/app.service.ts b/test-projects/backend/nestjs-bun/src/app.service.ts new file mode 100644 index 0000000..9635b05 --- /dev/null +++ b/test-projects/backend/nestjs-bun/src/app.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class AppService { + getHello() { + return { + message: 'Hello from NestJS with Bun!', + package_manager: 'bun', + framework: 'NestJS', + }; + } +} diff --git a/test-projects/backend/nestjs-bun/src/main.ts b/test-projects/backend/nestjs-bun/src/main.ts new file mode 100644 index 0000000..a913660 --- /dev/null +++ b/test-projects/backend/nestjs-bun/src/main.ts @@ -0,0 +1,9 @@ +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + await app.listen(3000); + console.log('NestJS application with Bun is running on port 3000'); +} +bootstrap(); diff --git a/test-projects/backend/nestjs-bun/tsconfig.json b/test-projects/backend/nestjs-bun/tsconfig.json new file mode 100644 index 0000000..95f5641 --- /dev/null +++ b/test-projects/backend/nestjs-bun/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false + } +} diff --git a/test-projects/frontend/nextjs-bun/Dockerfile b/test-projects/frontend/nextjs-bun/Dockerfile new file mode 100644 index 0000000..8afc383 --- /dev/null +++ b/test-projects/frontend/nextjs-bun/Dockerfile @@ -0,0 +1,37 @@ +FROM oven/bun:1-alpine AS deps + +WORKDIR /app + +COPY package.json bun.lockb* ./ +RUN bun install + +FROM oven/bun:1-alpine AS builder + +WORKDIR /app + +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +RUN mkdir -p public + +RUN bun run build + +FROM oven/bun:1-alpine AS runner + +WORKDIR /app + +ENV NODE_ENV=production + +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +COPY --from=deps /app/node_modules ./node_modules +COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json + +USER nextjs + +EXPOSE 3000 + +CMD ["bun", "--bun", "run", "start"] diff --git a/test-projects/frontend/nextjs-bun/app/layout.tsx b/test-projects/frontend/nextjs-bun/app/layout.tsx new file mode 100644 index 0000000..d295378 --- /dev/null +++ b/test-projects/frontend/nextjs-bun/app/layout.tsx @@ -0,0 +1,16 @@ +export const metadata = { + title: 'Next.js Bun Test', + description: 'Testing Next.js with Bun package manager', +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/test-projects/frontend/nextjs-bun/app/page.tsx b/test-projects/frontend/nextjs-bun/app/page.tsx new file mode 100644 index 0000000..02fc6b6 --- /dev/null +++ b/test-projects/frontend/nextjs-bun/app/page.tsx @@ -0,0 +1,9 @@ +export default function Home() { + return ( +
+

Hello from Next.js with Bun!

+

Package Manager: Bun

+

Framework: Next.js 14 (App Router)

+
+ ); +} diff --git a/test-projects/frontend/nextjs-bun/next.config.js b/test-projects/frontend/nextjs-bun/next.config.js new file mode 100644 index 0000000..658404a --- /dev/null +++ b/test-projects/frontend/nextjs-bun/next.config.js @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {}; + +module.exports = nextConfig; diff --git a/test-projects/frontend/nextjs-bun/package.json b/test-projects/frontend/nextjs-bun/package.json new file mode 100644 index 0000000..d4474d2 --- /dev/null +++ b/test-projects/frontend/nextjs-bun/package.json @@ -0,0 +1,20 @@ +{ + "name": "nextjs-bun-test", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "^14.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "@types/react": "^18.2.0", + "typescript": "^5.0.0" + } +} diff --git a/test-projects/frontend/nextjs-bun/tsconfig.json b/test-projects/frontend/nextjs-bun/tsconfig.json new file mode 100644 index 0000000..d8b9323 --- /dev/null +++ b/test-projects/frontend/nextjs-bun/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/test-projects/frontend/react-bun/Dockerfile b/test-projects/frontend/react-bun/Dockerfile new file mode 100644 index 0000000..57ba37d --- /dev/null +++ b/test-projects/frontend/react-bun/Dockerfile @@ -0,0 +1,27 @@ +FROM oven/bun:1-alpine AS builder + +WORKDIR /app + +COPY package.json bun.lockb* ./ +RUN bun install + +COPY . . + +RUN bun run build + +FROM nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html + +RUN echo 'server { \ + listen 3000; \ + location / { \ + root /usr/share/nginx/html; \ + index index.html; \ + try_files $uri $uri/ /index.html; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 3000 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/test-projects/frontend/react-bun/index.html b/test-projects/frontend/react-bun/index.html new file mode 100644 index 0000000..dd92b2c --- /dev/null +++ b/test-projects/frontend/react-bun/index.html @@ -0,0 +1,12 @@ + + + + + + React Bun Test + + +
+ + + diff --git a/test-projects/frontend/react-bun/package.json b/test-projects/frontend/react-bun/package.json new file mode 100644 index 0000000..8996202 --- /dev/null +++ b/test-projects/frontend/react-bun/package.json @@ -0,0 +1,22 @@ +{ + "name": "react-bun-test", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "@vitejs/plugin-react": "^4.2.0", + "typescript": "^5.0.0", + "vite": "^5.0.0" + } +} diff --git a/test-projects/frontend/react-bun/src/App.tsx b/test-projects/frontend/react-bun/src/App.tsx new file mode 100644 index 0000000..b7f5adf --- /dev/null +++ b/test-projects/frontend/react-bun/src/App.tsx @@ -0,0 +1,11 @@ +function App() { + return ( +
+

Hello from React with Bun!

+

Package Manager: Bun

+

Framework: React 18 + Vite

+
+ ); +} + +export default App; diff --git a/test-projects/frontend/react-bun/src/main.tsx b/test-projects/frontend/react-bun/src/main.tsx new file mode 100644 index 0000000..9707d82 --- /dev/null +++ b/test-projects/frontend/react-bun/src/main.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +); diff --git a/test-projects/frontend/react-bun/tsconfig.json b/test-projects/frontend/react-bun/tsconfig.json new file mode 100644 index 0000000..3934b8f --- /dev/null +++ b/test-projects/frontend/react-bun/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/test-projects/frontend/react-bun/tsconfig.node.json b/test-projects/frontend/react-bun/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/test-projects/frontend/react-bun/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/test-projects/frontend/react-bun/vite.config.ts b/test-projects/frontend/react-bun/vite.config.ts new file mode 100644 index 0000000..0466183 --- /dev/null +++ b/test-projects/frontend/react-bun/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], +}); diff --git a/test-projects/frontend/vuejs-bun/Dockerfile b/test-projects/frontend/vuejs-bun/Dockerfile new file mode 100644 index 0000000..57ba37d --- /dev/null +++ b/test-projects/frontend/vuejs-bun/Dockerfile @@ -0,0 +1,27 @@ +FROM oven/bun:1-alpine AS builder + +WORKDIR /app + +COPY package.json bun.lockb* ./ +RUN bun install + +COPY . . + +RUN bun run build + +FROM nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html + +RUN echo 'server { \ + listen 3000; \ + location / { \ + root /usr/share/nginx/html; \ + index index.html; \ + try_files $uri $uri/ /index.html; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 3000 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/test-projects/frontend/vuejs-bun/index.html b/test-projects/frontend/vuejs-bun/index.html new file mode 100644 index 0000000..3bdf219 --- /dev/null +++ b/test-projects/frontend/vuejs-bun/index.html @@ -0,0 +1,12 @@ + + + + + + Vue.js Bun Test + + +
+ + + diff --git a/test-projects/frontend/vuejs-bun/package.json b/test-projects/frontend/vuejs-bun/package.json new file mode 100644 index 0000000..9b97eeb --- /dev/null +++ b/test-projects/frontend/vuejs-bun/package.json @@ -0,0 +1,20 @@ +{ + "name": "vuejs-bun-test", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "vue": "^3.3.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.0", + "typescript": "^5.0.0", + "vite": "^5.0.0", + "vue-tsc": "^1.8.0" + } +} diff --git a/test-projects/frontend/vuejs-bun/src/App.vue b/test-projects/frontend/vuejs-bun/src/App.vue new file mode 100644 index 0000000..0f7d32e --- /dev/null +++ b/test-projects/frontend/vuejs-bun/src/App.vue @@ -0,0 +1,11 @@ + + + diff --git a/test-projects/frontend/vuejs-bun/src/main.ts b/test-projects/frontend/vuejs-bun/src/main.ts new file mode 100644 index 0000000..684d042 --- /dev/null +++ b/test-projects/frontend/vuejs-bun/src/main.ts @@ -0,0 +1,4 @@ +import { createApp } from 'vue'; +import App from './App.vue'; + +createApp(App).mount('#app'); diff --git a/test-projects/frontend/vuejs-bun/tsconfig.json b/test-projects/frontend/vuejs-bun/tsconfig.json new file mode 100644 index 0000000..a18b191 --- /dev/null +++ b/test-projects/frontend/vuejs-bun/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/test-projects/frontend/vuejs-bun/tsconfig.node.json b/test-projects/frontend/vuejs-bun/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/test-projects/frontend/vuejs-bun/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/test-projects/frontend/vuejs-bun/vite.config.ts b/test-projects/frontend/vuejs-bun/vite.config.ts new file mode 100644 index 0000000..1ebc4fc --- /dev/null +++ b/test-projects/frontend/vuejs-bun/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +export default defineConfig({ + plugins: [vue()], +});