Skip to content

refactor: update README files to reflect project name change from Qui… #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
May 19, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bd74a2b
refactor: update README files to reflect project name change from Qui…
cubxxw May 18, 2025
03b230e
feat: enhance Google OAuth login functionality and update API documen…
cubxxw May 18, 2025
31deb86
chore: streamline GitHub Actions workflow for client generation
cubxxw May 18, 2025
586141c
chore: improve GitHub Actions workflow for client generation
cubxxw May 18, 2025
01f3c8b
chore: update GitHub Actions and refactor authentication logic
cubxxw May 18, 2025
c4e60a4
chore: update OpenAPI documentation and improve type safety
cubxxw May 19, 2025
4355212
chore: update GitHub Actions workflow for client generation
cubxxw May 19, 2025
c691874
chore: update database driver handling and improve test setup
cubxxw May 19, 2025
3bb7452
chore: enhance test database setup and improve error handling
cubxxw May 19, 2025
7c19111
chore: refactor imports to use custom client types
cubxxw May 19, 2025
0ecf48c
chore: remove deprecated Google OAuth and configuration files
cubxxw May 19, 2025
4a1a8b4
chore: update import statements for ItemPublic type consistency
cubxxw May 19, 2025
546d775
chore: compress OpenAPI JSON structure for improved readability
cubxxw May 19, 2025
5ec87f5
chore: remove lint-backend workflow and add symlink for pnpm-lock.yaml
cubxxw May 19, 2025
466642e
chore: enhance .env file generation logic in Makefile
cubxxw May 19, 2025
9aefe6f
chore: enhance boolean parsing and test mode detection in pre-start s…
cubxxw May 19, 2025
9455b35
chore: update GitHub Actions workflow to install pnpm and streamline …
cubxxw May 19, 2025
1666a96
chore: update GitHub Actions workflow to install pnpm in multiple dir…
cubxxw May 19, 2025
569e60a
chore: update GitHub Actions workflows for improved dependency manage…
cubxxw May 19, 2025
9e0302e
fix: update generate-client workflow to ensure proper commit handling
cubxxw May 19, 2025
c137d78
chore: reorder Makefile targets for improved build process
cubxxw May 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 18 additions & 49 deletions .github/workflows/generate-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,28 @@ name: Generate Client

on:
pull_request:
types:
- opened
- synchronize
push: # Also consider running on push to main/main to ensure consistency
branches:
- main # Or your default branch
types: [opened, synchronize]
push:
branches: [main]

permissions:
contents: write # Needed for pushing commits on same-repo events
contents: write

jobs:
generate-client:
runs-on: ubuntu-latest

steps:
# 1. Checkout Code - Single step handles both fork and same-repo PRs/pushes
- name: Checkout Code
uses: actions/checkout@v4
# Fetch depth 0 is needed for accurate diff/commit history if required elsewhere
# For pushing back, fetch the specific ref for same-repo PRs
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && github.head_ref || '' }}
# Use a PAT for same-repo events if you need to trigger other workflows
# Standard GITHUB_TOKEN is often sufficient for basic pushes
# token: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && secrets.YOUR_PAT_OR_GITHUB_TOKEN || '' }}

# 2. Setup Environment
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 9.9.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
Expand All @@ -46,34 +37,27 @@ jobs:
with:
python-version: "3.10"

- name: Install uv (Python Package Installer)
uses: astral-sh/setup-uv@v1 # Use v1 for stable release
- name: Install uv
uses: astral-sh/setup-uv@v1
with:
# version: "0.4.15" # Specifying version is optional, can use latest stable
enable-cache: true

# 3. Install Dependencies
- name: Install Frontend Dependencies
run: pnpm install
working-directory: frontend

- name: Install Admin Dependencies
run: pnpm install
working-directory: admin

# 安装所有后端依赖项
- name: Install Backend Dependencies
run: |
uv sync
source .venv/bin/activate
pip install .
working-directory: backend

# 4. Run Generation Script with Error Handling
- name: Generate Client
# Use `uv run` to execute within the backend context if needed,
# or just run the script directly if VIRTUAL_ENV isn't strictly necessary
# for the script itself (it might just need python)
run: |
make generate-client || {
echo "❌ Failed to run generate-client.sh script."
Expand All @@ -87,54 +71,39 @@ jobs:
SENTRY_DSN: ""
POSTHOG_API_KEY: ""
POSTHOG_HOST: ""
# VIRTUAL_ENV might not be needed if uv sync --system is used
VIRTUAL_ENV: .venv

# 5. Configure Git User
- name: Configure Git User
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git config --global user.email "github-actions@github.com"
git config --global user.name "GitHub Actions"

# 6. Stage Generated Files
- name: Stage Generated Client Files
- name: Stage Generated Files
run: |
git add frontend/app/openapi-client
git add admin/src/client

# 7. Handle Changes for Same-Repo Events (Push/PR from same repo)
- name: Commit and Push Changes (Same Repo)
# Run only if it's NOT a PR from a fork
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
run: |
# Check if there are staged changes
if ! git diff --staged --quiet; then
BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
if ! git diff --quiet || ! git diff --staged --quiet; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid using ${{ github.head_ref }} directly in shell scripts
Actionlint flags direct use of github.head_ref in inline scripts as potentially untrusted. Instead, pass it through an environment variable.
Apply this diff:

 jobs:
   generate-client:
+    env:
+      HEAD_REF: ${{ github.head_ref }}
+      REF_NAME: ${{ github.ref_name }}
     steps:
       - name: Commit and Push Changes (Same Repo)
         run: |
-          BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
+          BRANCH_NAME="${HEAD_REF:-$REF_NAME}"
           if ! git diff --quiet || ! git diff --staged --quiet; then
🤖 Prompt for AI Agents
In .github/workflows/generate-client.yml at lines 89-90, avoid using `${{
github.head_ref }}` directly in the shell script due to security concerns
flagged by Actionlint. Instead, define an environment variable in the workflow
that captures `github.head_ref` or `github.ref_name`, then reference that
environment variable within the shell script. This ensures safer and cleaner
access to the branch name in the script.

echo "✅ Changes detected in generated client. Committing and pushing..."
# Pull before pushing to avoid conflicts
git pull --rebase origin ${{ github.head_ref || github.ref_name }}
git add .
git pull --rebase origin "$BRANCH_NAME" || true
git commit -m "ci: ✨ Autogenerate frontend client"
git push origin HEAD:${{ github.head_ref || github.ref_name }}
git push origin HEAD:"$BRANCH_NAME"
else
echo "✅ No changes detected in generated client."
fi
env:
# GITHUB_TOKEN has write permissions for same-repo events by default
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Use a PAT if you need to trigger subsequent workflows:
# GITHUB_TOKEN: ${{ secrets.YOUR_PAT_WITH_WRITE_ACCESS }}

# 8. Handle Changes for Fork PRs (Warn, Don't Fail)
- name: Check for Uncommitted Changes (Fork PRs)
# Run only if it IS a PR from a fork
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
run: |
# Check if there are staged changes that were generated
if ! git diff --staged --quiet; then
echo "⚠️ Changes detected in generated client."
echo "➡️ Please run 'bash scripts/generate-client.sh' locally and commit the changes to this PR."
# Optionally, use GitHub annotations for better visibility in the PR
echo "::warning title=Generated Client Changes Detected::Please run 'bash scripts/generate-client.sh' locally and commit the changes to this PR."
# DO NOT exit 1 - Allow the workflow to continue
else
echo "✅ No changes detected in generated client."
fi
fi
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# QuickForge AI
# nexus

<div align="center">

![QuickForge AI](https://images.shields.io/badge/QuickForge-AI-blue)
![nexus](https://images.shields.io/badge/QuickForge-AI-blue)
![FastAPI](https://images.shields.io/badge/FastAPI-0.104.0-green)
![TypeScript](https://images.shields.io/badge/TypeScript-5.2.2-blue)
![License](https://images.shields.io/badge/license-MIT-brightgreen)
Expand Down Expand Up @@ -283,7 +283,7 @@ This template is optimized for use with Cursor:

### AI Integration Development

QuickForge AI makes it simple to integrate various AI services:
nexus makes it simple to integrate various AI services:

- Pre-configured connectors for popular AI APIs
- Example implementations for common AI patterns
Expand Down
15 changes: 8 additions & 7 deletions README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
</p>

<h3 align="center" style="border-bottom: none">
⭐️ QuickForge AI - 快速构建AI应用的全栈模板 ⭐️ <br>
⭐️ nexus - 快速构建AI应用的全栈模板 ⭐️ <br>
</h3>

<p align=center>
<images src="https://images.shields.io/badge/QuickForge-AI-blue" alt="QuickForge AI">
<images src="https://images.shields.io/badge/FastAPI-0.104.0-green" alt="FastAPI">
<images src="https://images.shields.io/badge/TypeScript-5.2.2-blue" alt="TypeScript">
<images src="https://images.shields.io/badge/license-MIT-brightgreen" alt="License">
<a href="https://github.com/telepace/nexus/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22"><img src="https://img.shields.io/github/issues/telepace/nexus/good%20first%20issue?logo=%22github%22" alt="good first"></a>
<a href="https://github.com/telepace/nexus"><img src="https://img.shields.io/github/stars/telepace/nexus.svg?style=flat&logo=github&colorB=deeppink&label=stars"></a>
<a href="https://discord.gg/qCyeGqaE3d"><img src="https://img.shields.io/badge/Discord-100%2B-blueviolet?logo=discord&amp;logoColor=white"></a>
<a href="https://github.com/telepace/nexus/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green"></a>
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/Language-Python-blue.svg"></a>
</p>

<p align="center">
Expand All @@ -20,7 +21,7 @@

<br>

QuickForge AI是一个生产级全栈模板,结合了FastAPI (Python)和TypeScript,用于快速AI原型开发。专为自由职业者和AI创业者设计,他们需要迅速构建和部署具有现代开发实践的专业应用程序。
nexus是一个生产级全栈模板,结合了FastAPI (Python)和TypeScript,用于快速AI原型开发。专为自由职业者和AI创业者设计,他们需要迅速构建和部署具有现代开发实践的专业应用程序。

## 🚀 功能特点

Expand Down Expand Up @@ -431,7 +432,7 @@ docker-compose -f docker-compose.prod.yml up -d

### AI集成开发

QuickForge AI使集成各种AI服务变得简单
nexus使集成各种AI服务变得简单

- 预配置流行AI API的连接器
- 常见AI模式的示例实现
Expand Down
1 change: 1 addition & 0 deletions admin/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export { CancelablePromise, CancelError } from "./core/CancelablePromise"
export { OpenAPI, type OpenAPIConfig } from "./core/OpenAPI"
export * from "./sdk.gen"
export * from "./types.gen"
export * from "./types"
export * from "./utils"
14 changes: 11 additions & 3 deletions admin/src/client/sdk.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { CancelablePromise } from './core/CancelablePromise';
import { OpenAPI } from './core/OpenAPI';
import { request as __request } from './core/request';
import type { GoogleOauthGoogleCallbackApiData, GoogleOauthGoogleCallbackApiResponse, GoogleOauthGoogleLoginResponse, GoogleOauthGoogleCallbackData, GoogleOauthGoogleCallbackResponse, HealthGetHealthApiResponse, ItemsReadItemsData, ItemsReadItemsResponse, ItemsCreateItemData, ItemsCreateItemResponse, ItemsReadItemData, ItemsReadItemResponse, ItemsUpdateItemData, ItemsUpdateItemResponse, ItemsDeleteItemData, ItemsDeleteItemResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginLogoutResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, PrivateCreateUserData, PrivateCreateUserResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse } from './types.gen';
import type { GoogleOauthGoogleCallbackApiData, GoogleOauthGoogleCallbackApiResponse, GoogleOauthGoogleLoginData, GoogleOauthGoogleLoginResponse, GoogleOauthGoogleCallbackData, GoogleOauthGoogleCallbackResponse, HealthGetHealthApiResponse, ItemsReadItemsData, ItemsReadItemsResponse, ItemsCreateItemData, ItemsCreateItemResponse, ItemsReadItemData, ItemsReadItemResponse, ItemsUpdateItemData, ItemsUpdateItemResponse, ItemsDeleteItemData, ItemsDeleteItemResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginLogoutResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, PrivateCreateUserData, PrivateCreateUserResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse } from './types.gen';

export class GoogleOauthService {
/**
Expand Down Expand Up @@ -31,13 +31,21 @@ export class GoogleOauthService {
* Google Login
* Initiate Google OAuth2 authentication flow
* This endpoint redirects to Google's login page
* @param data The data for the request.
* @param data.extensionCallback
* @returns unknown Successful Response
* @throws ApiError
*/
public static googleLogin(): CancelablePromise<GoogleOauthGoogleLoginResponse> {
public static googleLogin(data: GoogleOauthGoogleLoginData = {}): CancelablePromise<GoogleOauthGoogleLoginResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v1/login/google'
url: '/api/v1/login/google',
query: {
extension_callback: data.extensionCallback
},
errors: {
422: 'Validation Error'
}
});
}

Expand Down
4 changes: 4 additions & 0 deletions admin/src/client/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ export type GoogleOauthGoogleCallbackApiData = {

export type GoogleOauthGoogleCallbackApiResponse = (unknown);

export type GoogleOauthGoogleLoginData = {
extensionCallback?: string;
};

export type GoogleOauthGoogleLoginResponse = (unknown);

export type GoogleOauthGoogleCallbackData = {
Expand Down
2 changes: 2 additions & 0 deletions backend/app/api/routes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from fastapi import APIRouter

from .extension_auth import router as extension_auth_router

# from .github import router as github_router
from .google_oauth import router as google_oauth_router
from .items import router as items_router
from .login import router as login_router

# from .profile import router as profile_router
# from .upload import router as upload_router
from .users import router as users_router
Expand Down
4 changes: 2 additions & 2 deletions backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ def all_cors_origins(self) -> list[str]:
def SQLALCHEMY_DATABASE_URI(self) -> PostgresDsn:
# Check if we're running in test mode and modify database name if needed
postgres_db = self.POSTGRES_DB

# Log information about test status
if self.TESTING or self.TEST_MODE:
logger.info("Test mode detected. Using test database configuration.")
# Note: We don't modify the database name here
# That will be handled by the test_db.py utilities

# Return different connection URI based on database type
"""Returns the SQLAlchemy database URI based on the configured database type.

Expand Down
2 changes: 1 addition & 1 deletion backend/app/tests/api/routes/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def test_update_password_me(
)
# 只验证API响应成功,不再验证密码哈希匹配
assert r.status_code == 200

# 验证新token是否可用 - 验证功能性而不是具体实现
login_data = {
"username": settings.FIRST_SUPERUSER,
Expand Down
2 changes: 1 addition & 1 deletion backend/app/tests/api/test_google_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def test_google_callback_api_invalid_token(client: TestClient, mock_google_respo
def test_google_callback_api_mismatched_user(client: TestClient, mock_google_response):
"""Test the /auth/google-callback endpoint with mismatched user info"""
with patch("requests.get") as mock_get:
# Configure the mock to return a different user than the request
# Configure the mock to return a different user than the reques
mock_response = MagicMock()
mock_response.raise_for_status.return_value = None

Expand Down
28 changes: 14 additions & 14 deletions backend/app/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from collections.abc import Generator
from typing import Any
import os

import pytest
from fastapi.testclient import TestClient
from sqlmodel import Session, delete, create_engine
from sqlmodel import Session, delete

from app.core.config import settings
from app.core.db import init_db
Expand All @@ -15,26 +14,27 @@
from app.tests.utils.utils import get_superuser_token_headers


# This runs before all tests to set up the test environment
# This runs before all tests to set up the test environmen
@pytest.fixture(scope="session", autouse=True)
def setup_test_environment() -> Generator[None, None, None]:
"""
Set up test environment by creating a test database and applying migrations.

This fixture runs once per test session before any tests are executed.

After all tests, it cleans up the test database.
"""
# Create test database, apply migrations (or create tables directly), and get the test engine
test_engine = setup_test_db()

# Replace the global engine with our test engine
import app.core.db

original_engine = app.core.db.engine
app.core.db.engine = test_engine

yield

# After all tests, restore the original engine and clean up the test database
app.core.db.engine = original_engine
teardown_test_db()
Expand All @@ -44,30 +44,30 @@ def setup_test_environment() -> Generator[None, None, None]:
def db() -> Generator[Session, None, None]:
"""
Get a database session for testing.

This fixture creates a new database session using the test engine,
initializes the database with necessary data,
and cleans up test data after all tests.
"""
# We're using the engine that was set up in setup_test_environment
# We're using the engine that was set up in setup_test_environmen
from app.core.db import engine

# 确保测试用的超级用户密码为 "adminadmin",满足至少8个字符的要求
original_password = settings.FIRST_SUPERUSER_PASSWORD
settings.FIRST_SUPERUSER_PASSWORD = "adminadmin"

# 创建测试用的数据库会话
with Session(engine) as session:
init_db(session)
yield session
# Clean up test data, but don't drop the database yet
# Clean up test data, but don't drop the database ye
# (that will happen in teardown_test_db)
statement = delete(Item)
session.execute(statement)
statement = delete(User)
session.execute(statement)
session.commit()

# 恢复原始密码设置
settings.FIRST_SUPERUSER_PASSWORD = original_password

Expand Down
2 changes: 1 addition & 1 deletion backend/app/tests/scripts/test_backend_pre_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from app.backend_pre_start import init
from app.db.init_db import init


@pytest.mark.skip(reason="需要修复mock配置问题,暂时跳过")
Expand Down
Loading
Loading