-
Notifications
You must be signed in to change notification settings - Fork 0
Crone : ci cd pipline #16
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
Changes from all commits
af190d8
d98cd21
2a72546
002b1b9
27ef7ce
177c826
bd2036f
a80e5c9
a0be4df
2cb8122
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,39 @@ | ||||||||||||||||||||||||||||||||||
# =========================================== | ||||||||||||||||||||||||||||||||||
# ProjectVG API Server - Environment Variables Template | ||||||||||||||||||||||||||||||||||
# =========================================== | ||||||||||||||||||||||||||||||||||
# Copy this file to .env and fill in your actual values | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# Database Configuration | ||||||||||||||||||||||||||||||||||
DB_CONNECTION_STRING=Server=host.docker.internal,1433;Database=ProjectVG;User Id=sa;Password=YOUR_DB_PASSWORD;TrustServerCertificate=true;MultipleActiveResultSets=true | ||||||||||||||||||||||||||||||||||
DB_PASSWORD=YOUR_DB_PASSWORD | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# Redis Configuration | ||||||||||||||||||||||||||||||||||
REDIS_CONNECTION_STRING=host.docker.internal:6380 | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# External Services | ||||||||||||||||||||||||||||||||||
LLM_BASE_URL=http://host.docker.internal:7908 | ||||||||||||||||||||||||||||||||||
MEMORY_BASE_URL=http://host.docker.internal:7912 | ||||||||||||||||||||||||||||||||||
TTS_BASE_URL=https://supertoneapi.com | ||||||||||||||||||||||||||||||||||
TTS_API_KEY=YOUR_TTS_API_KEY | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# JWT Configuration (IMPORTANT: Use a secure random key in production) | ||||||||||||||||||||||||||||||||||
JWT_SECRET_KEY=YOUR_JWT_SECRET_KEY_MINIMUM_32_CHARACTERS | ||||||||||||||||||||||||||||||||||
JWT_ACCESS_TOKEN_LIFETIME_MINUTES=15 | ||||||||||||||||||||||||||||||||||
JWT_REFRESH_TOKEN_LIFETIME_DAYS=30 | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# OAuth2 Configuration | ||||||||||||||||||||||||||||||||||
OAUTH2_ENABLED=true | ||||||||||||||||||||||||||||||||||
GOOGLE_OAUTH_ENABLED=true | ||||||||||||||||||||||||||||||||||
GOOGLE_OAUTH_CLIENT_ID=YOUR_GOOGLE_CLIENT_ID | ||||||||||||||||||||||||||||||||||
GOOGLE_OAUTH_CLIENT_SECRET=YOUR_GOOGLE_CLIENT_SECRET | ||||||||||||||||||||||||||||||||||
GOOGLE_OAUTH_REDIRECT_URI=http://localhost:7900/auth/oauth2/callback | ||||||||||||||||||||||||||||||||||
GOOGLE_OAUTH_AUTO_CREATE_USER=true | ||||||||||||||||||||||||||||||||||
GOOGLE_OAUTH_DEFAULT_ROLE=User | ||||||||||||||||||||||||||||||||||
Comment on lines
+24
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OAuth Redirect URI 포트 불일치로 콜백 실패 가능 docker-compose.yml은 호스트 7910→컨테이너 7900으로 포워딩합니다. 현재 GOOGLE_OAUTH_REDIRECT_URI는 7900을 가리켜 로컬 실행 시 OAuth 콜백이 실패할 수 있습니다. 7910으로 맞춰주세요. -GOOGLE_OAUTH_REDIRECT_URI=http://localhost:7900/auth/oauth2/callback
+GOOGLE_OAUTH_REDIRECT_URI=http://localhost:7910/auth/oauth2/callback 📝 Committable suggestion
Suggested change
🧰 Tools🪛 dotenv-linter (3.3.0)[warning] 26-26: [UnorderedKey] The GOOGLE_OAUTH_ENABLED key should go before the OAUTH2_ENABLED key (UnorderedKey) [warning] 27-27: [UnorderedKey] The GOOGLE_OAUTH_CLIENT_ID key should go before the GOOGLE_OAUTH_ENABLED key (UnorderedKey) [warning] 28-28: [UnorderedKey] The GOOGLE_OAUTH_CLIENT_SECRET key should go before the GOOGLE_OAUTH_ENABLED key (UnorderedKey) [warning] 29-29: [UnorderedKey] The GOOGLE_OAUTH_REDIRECT_URI key should go before the OAUTH2_ENABLED key (UnorderedKey) [warning] 30-30: [UnorderedKey] The GOOGLE_OAUTH_AUTO_CREATE_USER key should go before the GOOGLE_OAUTH_CLIENT_ID key (UnorderedKey) [warning] 31-31: [UnorderedKey] The GOOGLE_OAUTH_DEFAULT_ROLE key should go before the GOOGLE_OAUTH_ENABLED key (UnorderedKey) 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# Application Configuration | ||||||||||||||||||||||||||||||||||
ASPNETCORE_ENVIRONMENT=Production | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
# Container Resource Limits | ||||||||||||||||||||||||||||||||||
API_CPU_LIMIT=1.0 | ||||||||||||||||||||||||||||||||||
API_MEMORY_LIMIT=1g | ||||||||||||||||||||||||||||||||||
API_PORT=7910 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Set default behavior to automatically normalize line endings. | ||
* text=auto | ||
|
||
# Set file types that should always have CRLF line endings on checkout. | ||
*.sln text eol=crlf | ||
*.csproj text eol=crlf | ||
*.config text eol=crlf | ||
|
||
# Set file types that should always have LF line endings on checkout. | ||
*.sh text eol=lf | ||
*.bash text eol=lf | ||
*.yml text eol=lf | ||
*.yaml text eol=lf | ||
|
||
# Ensure that shell scripts are executable | ||
*.sh text eol=lf | ||
deploy.sh text eol=lf | ||
deploy-dev.sh text eol=lf | ||
|
||
# PowerShell scripts | ||
*.ps1 text eol=crlf | ||
|
||
# Docker files | ||
Dockerfile text eol=lf | ||
*.dockerfile text eol=lf | ||
docker-compose*.yml text eol=lf | ||
|
||
# Markdown files | ||
*.md text eol=lf | ||
|
||
# JSON files | ||
*.json text eol=lf |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
name: Develop | ||
|
||
on: | ||
pull_request: | ||
branches: [develop] | ||
paths-ignore: | ||
- '**.md' | ||
- 'docs/**' | ||
- 'scripts/**' | ||
|
||
env: | ||
DOTNET_VERSION: '8.0.x' | ||
|
||
jobs: | ||
build-and-test: | ||
name: Build & Test | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup .NET | ||
uses: actions/setup-dotnet@v4 | ||
with: | ||
dotnet-version: ${{ env.DOTNET_VERSION }} | ||
|
||
- name: Cache NuGet | ||
uses: actions/cache@v4 | ||
with: | ||
path: ~/.nuget/packages | ||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} | ||
restore-keys: | | ||
${{ runner.os }}-nuget- | ||
|
||
- name: Restore | ||
run: | | ||
echo "복원 중..." | ||
start_time=$(date +%s) | ||
dotnet restore ProjectVG.sln | ||
end_time=$(date +%s) | ||
duration=$((end_time - start_time)) | ||
echo "복원 완료 (${duration}초)" | ||
|
||
- name: Build | ||
run: | | ||
echo "🔨 빌드 중..." | ||
start_time=$(date +%s) | ||
dotnet build ProjectVG.sln --no-restore --configuration Release | ||
end_time=$(date +%s) | ||
duration=$((end_time - start_time)) | ||
echo "빌드 완료 (${duration}초)" | ||
|
||
- name: Test | ||
run: | | ||
echo "테스트 중..." | ||
start_time=$(date +%s) | ||
dotnet test --no-build --configuration Release --verbosity normal | ||
end_time=$(date +%s) | ||
duration=$((end_time - start_time)) | ||
echo "테스트 완료 (${duration}초)" | ||
|
||
- name: Success Status | ||
if: success() | ||
run: | | ||
echo "✅ 빌드 및 테스트 성공" | ||
|
||
- name: Build Status | ||
if: failure() | ||
run: | | ||
echo "❌ 빌드 실패" | ||
exit 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
name: Release | ||
|
||
on: | ||
push: | ||
branches: [release] | ||
paths-ignore: | ||
- '**.md' | ||
- 'docs/**' | ||
- 'scripts/**' | ||
|
||
env: | ||
DOTNET_VERSION: '8.0.x' | ||
DOCKER_IMAGE_NAME: ghcr.io/projectvg/projectvgapi | ||
ACTOR: projectvg | ||
|
||
permissions: | ||
contents: read | ||
packages: write | ||
|
||
jobs: | ||
build: | ||
name: Build & Push | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup .NET | ||
uses: actions/setup-dotnet@v4 | ||
with: | ||
dotnet-version: ${{ env.DOTNET_VERSION }} | ||
|
||
- name: Cache NuGet | ||
uses: actions/cache@v4 | ||
with: | ||
path: ~/.nuget/packages | ||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} | ||
restore-keys: | | ||
${{ runner.os }}-nuget- | ||
|
||
- name: Restore | ||
run: | | ||
echo "복원 중..." | ||
dotnet restore ProjectVG.sln | ||
echo "복원 완료" | ||
|
||
- name: Build | ||
run: | | ||
echo "🔨 빌드 중..." | ||
dotnet build ProjectVG.sln --no-restore --configuration Release | ||
echo "빌드 완료" | ||
|
||
- name: Test | ||
run: | | ||
echo "테스트 중..." | ||
dotnet test --no-build --configuration Release --verbosity normal | ||
echo "테스트 완료" | ||
|
||
- name: Login GHCR | ||
uses: docker/login-action@v3 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ env.ACTOR }} | ||
password: ${{ secrets.GHCR_TOKEN }} | ||
|
||
- name: Build & Push Image | ||
run: | | ||
docker build -t ${{ env.DOCKER_IMAGE_NAME }}:latest -f ProjectVG.Api/Dockerfile . | ||
docker push ${{ env.DOCKER_IMAGE_NAME }}:latest | ||
|
||
- name: Build Success Status | ||
if: success() | ||
run: | | ||
echo "✅ 빌드 및 이미지 푸시 완료" | ||
echo "이미지: ${{ env.DOCKER_IMAGE_NAME }}:latest" | ||
|
||
- name: Build Failure Status | ||
if: failure() | ||
run: | | ||
echo "❌ 빌드 또는 이미지 푸시 실패" | ||
exit 1 | ||
|
||
deploy: | ||
name: Deploy | ||
needs: build | ||
runs-on: [self-hosted, deploy-runner] | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Login GHCR | ||
run: echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ env.ACTOR }} --password-stdin | ||
|
||
- name: Add Config Files | ||
run: | | ||
echo "${{ secrets.PROD_APPLICATION_ENV }}" | base64 --decode > .env | ||
|
||
- name: Make Script Executable | ||
run: chmod +x deploy/deploy.sh | ||
|
||
- name: Deploy | ||
run: ./deploy/deploy.sh | ||
|
||
- name: Cleanup | ||
run: | | ||
docker image prune -f | ||
docker builder prune -f | ||
|
||
- name: Deploy Success Status | ||
if: success() | ||
run: | | ||
echo "✅ 배포 완료" | ||
echo "이미지: ${{ env.DOCKER_IMAGE_NAME }}:latest" | ||
|
||
- name: Deploy Failure Status | ||
if: failure() | ||
run: | | ||
echo "❌ 배포 실패" | ||
exit 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,7 +133,7 @@ public async Task GetConversationHistoryAsync_WithExistingMessages_ShouldReturnI | |
var message3 = await _conversationService.AddMessageAsync(userId, characterId, ChatRole.User, "Third message", DateTime.UtcNow); | ||
|
||
// Act | ||
var history = await _conversationService.GetConversationHistoryAsync(userId, characterId, 10); | ||
var history = await _conversationService.GetConversationHistoryAsync(userId, characterId, 1, 10); | ||
|
||
// Assert | ||
var historyList = history.ToList(); | ||
|
@@ -160,7 +160,7 @@ public async Task GetConversationHistoryAsync_WithCountLimit_ShouldRespectLimit( | |
} | ||
|
||
// Act - Request only 3 messages | ||
var history = await _conversationService.GetConversationHistoryAsync(userId, characterId, 3); | ||
var history = await _conversationService.GetConversationHistoryAsync(userId, characterId, 1, 3); | ||
|
||
// Assert | ||
var historyList = history.ToList(); | ||
|
@@ -215,7 +215,7 @@ public async Task GetConversationHistoryAsync_WithInvalidCount_ShouldThrowValida | |
|
||
// Act & Assert | ||
await Assert.ThrowsAsync<ValidationException>( | ||
() => _conversationService.GetConversationHistoryAsync(userId, characterId, count)); | ||
() => _conversationService.GetConversationHistoryAsync(userId, characterId, 1, count)); | ||
} | ||
|
||
[Fact] | ||
|
@@ -225,8 +225,8 @@ public async Task GetConversationHistoryAsync_WithMultipleUserCharacterPairs_Sho | |
await _fixture.ClearDatabaseAsync(); | ||
var user1 = await CreateUserAsync("user1", "[email protected]"); | ||
var user2 = await CreateUserAsync("user2", "[email protected]"); | ||
var char1 = await CreateCharacterAsync("Character1"); | ||
var char2 = await CreateCharacterAsync("Character2"); | ||
var char1 = await CreateCharacterAsync("Character1", user1.Id); | ||
var char2 = await CreateCharacterAsync("Character2", user1.Id); | ||
|
||
// Add messages for different user-character combinations | ||
await _conversationService.AddMessageAsync(user1.Id, char1.Id, ChatRole.User, "User1-Char1 Message", DateTime.UtcNow); | ||
|
@@ -291,8 +291,8 @@ public async Task ClearConversationAsync_ShouldOnlyAffectSpecificUserCharacterPa | |
await _fixture.ClearDatabaseAsync(); | ||
var user1 = await CreateUserAsync("user1", "[email protected]"); | ||
var user2 = await CreateUserAsync("user2", "[email protected]"); | ||
var char1 = await CreateCharacterAsync("Character1"); | ||
var char2 = await CreateCharacterAsync("Character2"); | ||
var char1 = await CreateCharacterAsync("Character1", user1.Id); | ||
var char2 = await CreateCharacterAsync("Character2", user1.Id); | ||
|
||
// Add messages for different combinations | ||
await _conversationService.AddMessageAsync(user1.Id, char1.Id, ChatRole.User, "User1-Char1", DateTime.UtcNow); | ||
|
@@ -429,8 +429,8 @@ public async Task MultipleConversationsSimultaneously_ShouldIsolateCorrectly() | |
await _fixture.ClearDatabaseAsync(); | ||
var user1 = await CreateUserAsync("user1", "[email protected]"); | ||
var user2 = await CreateUserAsync("user2", "[email protected]"); | ||
var character1 = await CreateCharacterAsync("Character1"); | ||
var character2 = await CreateCharacterAsync("Character2"); | ||
var character1 = await CreateCharacterAsync("Character1", user1.Id); | ||
var character2 = await CreateCharacterAsync("Character2", user1.Id); | ||
|
||
// Create conversations for different user-character pairs | ||
// User1 with Character1 | ||
|
@@ -473,7 +473,7 @@ public async Task MultipleConversationsSimultaneously_ShouldIsolateCorrectly() | |
private async Task<(Guid userId, Guid characterId)> CreateUserAndCharacterAsync() | ||
{ | ||
var user = await CreateUserAsync(); | ||
var character = await CreateCharacterAsync(); | ||
var character = await CreateCharacterAsync("TestCharacter", user.Id); | ||
return (user.Id, character.Id); | ||
} | ||
|
||
|
@@ -486,9 +486,9 @@ public async Task MultipleConversationsSimultaneously_ShouldIsolateCorrectly() | |
} | ||
|
||
private async Task<ProjectVG.Application.Models.Character.CharacterDto> CreateCharacterAsync( | ||
string name = "TestCharacter") | ||
string name = "TestCharacter", Guid? userId = null) | ||
{ | ||
var createCommand = TestDataBuilder.CreateCreateCharacterWithFieldsCommand(name); | ||
var createCommand = TestDataBuilder.CreateCreateCharacterWithFieldsCommand(name, userId: userId); | ||
return await _characterService.CreateCharacterWithFieldsAsync(createCommand); | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.