ci(actions-manager): add build and release workflows
Add Gitea Actions workflows for automated CI/CD. Build workflow runs on push/PR to build, test, and push Docker images. Release workflow triggers on version tags to build multi-platform binaries, package NuGet client, create GitHub releases, and publish versioned Docker images. Also add REST API controller for AI services alongside existing gRPC endpoints.
This commit is contained in:
57
.gitea/workflows/build.yml
Normal file
57
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore GitCaddy.AI.sln
|
||||
|
||||
- name: Build
|
||||
run: dotnet build GitCaddy.AI.sln -c Release --no-restore
|
||||
|
||||
- name: Test
|
||||
run: dotnet test GitCaddy.AI.sln -c Release --no-build --verbosity normal
|
||||
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }}
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.REGISTRY_URL }}/gitcaddy/gitcaddy-ai:latest
|
||||
${{ secrets.REGISTRY_URL }}/gitcaddy/gitcaddy-ai:${{ github.sha }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
85
.gitea/workflows/release.yml
Normal file
85
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,85 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
|
||||
- name: Get version from tag
|
||||
id: version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore GitCaddy.AI.sln
|
||||
|
||||
- name: Build
|
||||
run: dotnet build GitCaddy.AI.sln -c Release --no-restore -p:Version=${{ steps.version.outputs.VERSION }}
|
||||
|
||||
- name: Publish Service
|
||||
run: |
|
||||
dotnet publish src/GitCaddy.AI.Service/GitCaddy.AI.Service.csproj -c Release -o publish/linux-x64 -r linux-x64 --self-contained -p:Version=${{ steps.version.outputs.VERSION }}
|
||||
dotnet publish src/GitCaddy.AI.Service/GitCaddy.AI.Service.csproj -c Release -o publish/win-x64 -r win-x64 --self-contained -p:Version=${{ steps.version.outputs.VERSION }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
cd publish
|
||||
tar -czf gitcaddy-ai-${{ steps.version.outputs.VERSION }}-linux-x64.tar.gz linux-x64/
|
||||
zip -r gitcaddy-ai-${{ steps.version.outputs.VERSION }}-win-x64.zip win-x64/
|
||||
|
||||
- name: Pack NuGet Client
|
||||
run: dotnet pack src/GitCaddy.AI.Client/GitCaddy.AI.Client.csproj -c Release -o nupkg -p:Version=${{ steps.version.outputs.VERSION }}
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
publish/*.tar.gz
|
||||
publish/*.zip
|
||||
nupkg/*.nupkg
|
||||
generate_release_notes: true
|
||||
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get version from tag
|
||||
id: version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }}
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.REGISTRY_URL }}/gitcaddy/gitcaddy-ai:latest
|
||||
${{ secrets.REGISTRY_URL }}/gitcaddy/gitcaddy-ai:${{ steps.version.outputs.VERSION }}
|
||||
build-args: |
|
||||
BUILD_CONFIGURATION=Release
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
464
src/GitCaddy.AI.Service/Controllers/AIController.cs
Normal file
464
src/GitCaddy.AI.Service/Controllers/AIController.cs
Normal file
@@ -0,0 +1,464 @@
|
||||
// Copyright 2026 MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: BSL-1.1
|
||||
|
||||
using GitCaddy.AI.Service.Services;
|
||||
using GitCaddy.AI.Service.Licensing;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GitCaddy.AI.Service.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// REST API controller for AI services.
|
||||
/// Provides HTTP endpoints alongside the gRPC service.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/v1")]
|
||||
public class AIController : ControllerBase
|
||||
{
|
||||
private readonly ICodeReviewService _codeReviewService;
|
||||
private readonly ICodeIntelligenceService _codeIntelligenceService;
|
||||
private readonly IIssueService _issueService;
|
||||
private readonly IDocumentationService _documentationService;
|
||||
private readonly ILicenseValidator _licenseValidator;
|
||||
private readonly ILogger<AIController> _logger;
|
||||
|
||||
public AIController(
|
||||
ICodeReviewService codeReviewService,
|
||||
ICodeIntelligenceService codeIntelligenceService,
|
||||
IIssueService issueService,
|
||||
IDocumentationService documentationService,
|
||||
ILicenseValidator licenseValidator,
|
||||
ILogger<AIController> logger)
|
||||
{
|
||||
_codeReviewService = codeReviewService;
|
||||
_codeIntelligenceService = codeIntelligenceService;
|
||||
_issueService = issueService;
|
||||
_documentationService = documentationService;
|
||||
_licenseValidator = licenseValidator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Health check endpoint
|
||||
/// </summary>
|
||||
[HttpGet("health")]
|
||||
public async Task<IActionResult> Health()
|
||||
{
|
||||
var licenseResult = await _licenseValidator.ValidateAsync();
|
||||
return Ok(new
|
||||
{
|
||||
healthy = licenseResult.IsValid,
|
||||
version = typeof(AIController).Assembly.GetName().Version?.ToString() ?? "1.0.0",
|
||||
provider_status = new Dictionary<string, string>
|
||||
{
|
||||
["default"] = "operational"
|
||||
},
|
||||
license = licenseResult.License != null ? new
|
||||
{
|
||||
tier = licenseResult.License.Tier,
|
||||
customer = licenseResult.License.Customer,
|
||||
expires_at = licenseResult.License.ExpiresAt,
|
||||
features = licenseResult.License.Features,
|
||||
seat_count = licenseResult.License.SeatCount,
|
||||
is_trial = licenseResult.License.IsTrial
|
||||
} : null
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Review a pull request
|
||||
/// </summary>
|
||||
[HttpPost("review/pull-request")]
|
||||
public async Task<IActionResult> ReviewPullRequest([FromBody] ReviewPullRequestDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.ReviewPullRequestRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
PullRequestId = request.PullRequestId,
|
||||
BaseBranch = request.BaseBranch ?? "",
|
||||
HeadBranch = request.HeadBranch ?? "",
|
||||
PrTitle = request.PRTitle ?? "",
|
||||
PrDescription = request.PRDescription ?? "",
|
||||
Options = new Proto.ReviewOptions
|
||||
{
|
||||
CheckSecurity = request.Options?.CheckSecurity ?? true,
|
||||
CheckPerformance = request.Options?.CheckPerformance ?? true,
|
||||
CheckStyle = request.Options?.CheckStyle ?? true,
|
||||
CheckTests = request.Options?.CheckTests ?? true,
|
||||
SuggestImprovements = request.Options?.SuggestImprovements ?? true,
|
||||
FocusAreas = request.Options?.FocusAreas ?? "",
|
||||
LanguageHints = request.Options?.LanguageHints ?? ""
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var file in request.Files ?? [])
|
||||
{
|
||||
protoRequest.Files.Add(new Proto.FileDiff
|
||||
{
|
||||
Path = file.Path ?? "",
|
||||
OldPath = file.OldPath ?? "",
|
||||
Status = file.Status ?? "modified",
|
||||
Patch = file.Patch ?? "",
|
||||
Content = file.Content ?? "",
|
||||
Language = file.Language ?? ""
|
||||
});
|
||||
}
|
||||
|
||||
var response = await _codeReviewService.ReviewPullRequestAsync(protoRequest, cancellationToken);
|
||||
return Ok(MapReviewResponse(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to review pull request");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triage an issue
|
||||
/// </summary>
|
||||
[HttpPost("issues/triage")]
|
||||
public async Task<IActionResult> TriageIssue([FromBody] TriageIssueDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.TriageIssueRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
IssueId = request.IssueId,
|
||||
Title = request.Title ?? "",
|
||||
Body = request.Body ?? ""
|
||||
};
|
||||
protoRequest.ExistingLabels.AddRange(request.ExistingLabels ?? []);
|
||||
protoRequest.AvailableLabels.AddRange(request.AvailableLabels ?? []);
|
||||
|
||||
var response = await _issueService.TriageIssueAsync(protoRequest, cancellationToken);
|
||||
return Ok(new
|
||||
{
|
||||
priority = response.Priority,
|
||||
category = response.Category,
|
||||
suggested_labels = response.SuggestedLabels.ToList(),
|
||||
suggested_assignees = response.SuggestedAssignees.ToList(),
|
||||
summary = response.Summary,
|
||||
is_duplicate = response.IsDuplicate,
|
||||
duplicate_of = response.DuplicateOf
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to triage issue");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suggest labels for an issue
|
||||
/// </summary>
|
||||
[HttpPost("issues/suggest-labels")]
|
||||
public async Task<IActionResult> SuggestLabels([FromBody] SuggestLabelsDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.SuggestLabelsRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
Title = request.Title ?? "",
|
||||
Body = request.Body ?? ""
|
||||
};
|
||||
protoRequest.AvailableLabels.AddRange(request.AvailableLabels ?? []);
|
||||
|
||||
var response = await _issueService.SuggestLabelsAsync(protoRequest, cancellationToken);
|
||||
return Ok(new
|
||||
{
|
||||
suggestions = response.Suggestions.Select(s => new
|
||||
{
|
||||
label = s.Label,
|
||||
confidence = s.Confidence,
|
||||
reason = s.Reason
|
||||
}).ToList()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to suggest labels");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explain code
|
||||
/// </summary>
|
||||
[HttpPost("code/explain")]
|
||||
public async Task<IActionResult> ExplainCode([FromBody] ExplainCodeDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.ExplainCodeRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
FilePath = request.FilePath ?? "",
|
||||
Code = request.Code ?? "",
|
||||
StartLine = request.StartLine,
|
||||
EndLine = request.EndLine,
|
||||
Question = request.Question ?? ""
|
||||
};
|
||||
|
||||
var response = await _codeIntelligenceService.ExplainCodeAsync(protoRequest, cancellationToken);
|
||||
return Ok(new
|
||||
{
|
||||
explanation = response.Explanation,
|
||||
key_concepts = response.KeyConcepts.ToList(),
|
||||
references = response.References.Select(r => new
|
||||
{
|
||||
description = r.Description,
|
||||
url = r.Url
|
||||
}).ToList()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to explain code");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Summarize changes
|
||||
/// </summary>
|
||||
[HttpPost("code/summarize")]
|
||||
public async Task<IActionResult> SummarizeChanges([FromBody] SummarizeChangesDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.SummarizeChangesRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
Context = request.Context ?? ""
|
||||
};
|
||||
|
||||
foreach (var file in request.Files ?? [])
|
||||
{
|
||||
protoRequest.Files.Add(new Proto.FileDiff
|
||||
{
|
||||
Path = file.Path ?? "",
|
||||
OldPath = file.OldPath ?? "",
|
||||
Status = file.Status ?? "modified",
|
||||
Patch = file.Patch ?? "",
|
||||
Content = file.Content ?? "",
|
||||
Language = file.Language ?? ""
|
||||
});
|
||||
}
|
||||
|
||||
var response = await _codeIntelligenceService.SummarizeChangesAsync(protoRequest, cancellationToken);
|
||||
return Ok(new
|
||||
{
|
||||
summary = response.Summary,
|
||||
bullet_points = response.BulletPoints.ToList(),
|
||||
impact_assessment = response.ImpactAssessment
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to summarize changes");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate documentation
|
||||
/// </summary>
|
||||
[HttpPost("docs/generate")]
|
||||
public async Task<IActionResult> GenerateDocumentation([FromBody] GenerateDocumentationDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.GenerateDocumentationRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
FilePath = request.FilePath ?? "",
|
||||
Code = request.Code ?? "",
|
||||
DocType = request.DocType ?? "function",
|
||||
Language = request.Language ?? "",
|
||||
Style = request.Style ?? "markdown"
|
||||
};
|
||||
|
||||
var response = await _documentationService.GenerateDocumentationAsync(protoRequest, cancellationToken);
|
||||
return Ok(new
|
||||
{
|
||||
documentation = response.Documentation,
|
||||
sections = response.Sections.Select(s => new
|
||||
{
|
||||
title = s.Title,
|
||||
content = s.Content
|
||||
}).ToList()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to generate documentation");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate commit message
|
||||
/// </summary>
|
||||
[HttpPost("docs/commit-message")]
|
||||
public async Task<IActionResult> GenerateCommitMessage([FromBody] GenerateCommitMessageDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var protoRequest = new Proto.GenerateCommitMessageRequest
|
||||
{
|
||||
RepoId = request.RepoId,
|
||||
Style = request.Style ?? "conventional"
|
||||
};
|
||||
|
||||
foreach (var file in request.Files ?? [])
|
||||
{
|
||||
protoRequest.Files.Add(new Proto.FileDiff
|
||||
{
|
||||
Path = file.Path ?? "",
|
||||
OldPath = file.OldPath ?? "",
|
||||
Status = file.Status ?? "modified",
|
||||
Patch = file.Patch ?? ""
|
||||
});
|
||||
}
|
||||
|
||||
var response = await _documentationService.GenerateCommitMessageAsync(protoRequest, cancellationToken);
|
||||
return Ok(new
|
||||
{
|
||||
message = response.Message,
|
||||
alternatives = response.Alternatives.ToList()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to generate commit message");
|
||||
return StatusCode(500, new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
private static object MapReviewResponse(Proto.ReviewPullRequestResponse response)
|
||||
{
|
||||
return new
|
||||
{
|
||||
summary = response.Summary,
|
||||
comments = response.Comments.Select(c => new
|
||||
{
|
||||
path = c.Path,
|
||||
line = c.Line,
|
||||
end_line = c.EndLine,
|
||||
body = c.Body,
|
||||
severity = c.Severity.ToString().ToLower().Replace("comment_severity_", ""),
|
||||
category = c.Category,
|
||||
suggested_fix = c.SuggestedFix
|
||||
}).ToList(),
|
||||
verdict = response.Verdict.ToString().ToLower().Replace("review_verdict_", ""),
|
||||
suggestions = response.Suggestions.ToList(),
|
||||
security = new
|
||||
{
|
||||
issues = response.Security?.Issues.Select(i => new
|
||||
{
|
||||
path = i.Path,
|
||||
line = i.Line,
|
||||
issue_type = i.IssueType,
|
||||
description = i.Description,
|
||||
severity = i.Severity,
|
||||
remediation = i.Remediation
|
||||
}).ToList() ?? [],
|
||||
risk_score = response.Security?.RiskScore ?? 0,
|
||||
summary = response.Security?.Summary ?? ""
|
||||
},
|
||||
estimated_review_minutes = response.EstimatedReviewMinutes
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// DTO classes for REST API
|
||||
public class ReviewPullRequestDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public long PullRequestId { get; set; }
|
||||
public string? BaseBranch { get; set; }
|
||||
public string? HeadBranch { get; set; }
|
||||
public List<FileDiffDto>? Files { get; set; }
|
||||
public string? PRTitle { get; set; }
|
||||
public string? PRDescription { get; set; }
|
||||
public ReviewOptionsDto? Options { get; set; }
|
||||
}
|
||||
|
||||
public class FileDiffDto
|
||||
{
|
||||
public string? Path { get; set; }
|
||||
public string? OldPath { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public string? Patch { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public string? Language { get; set; }
|
||||
}
|
||||
|
||||
public class ReviewOptionsDto
|
||||
{
|
||||
public bool CheckSecurity { get; set; } = true;
|
||||
public bool CheckPerformance { get; set; } = true;
|
||||
public bool CheckStyle { get; set; } = true;
|
||||
public bool CheckTests { get; set; } = true;
|
||||
public bool SuggestImprovements { get; set; } = true;
|
||||
public string? FocusAreas { get; set; }
|
||||
public string? LanguageHints { get; set; }
|
||||
}
|
||||
|
||||
public class TriageIssueDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public long IssueId { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? Body { get; set; }
|
||||
public List<string>? ExistingLabels { get; set; }
|
||||
public List<string>? AvailableLabels { get; set; }
|
||||
}
|
||||
|
||||
public class SuggestLabelsDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? Body { get; set; }
|
||||
public List<string>? AvailableLabels { get; set; }
|
||||
}
|
||||
|
||||
public class ExplainCodeDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public string? FilePath { get; set; }
|
||||
public string? Code { get; set; }
|
||||
public int StartLine { get; set; }
|
||||
public int EndLine { get; set; }
|
||||
public string? Question { get; set; }
|
||||
}
|
||||
|
||||
public class SummarizeChangesDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public List<FileDiffDto>? Files { get; set; }
|
||||
public string? Context { get; set; }
|
||||
}
|
||||
|
||||
public class GenerateDocumentationDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public string? FilePath { get; set; }
|
||||
public string? Code { get; set; }
|
||||
public string? DocType { get; set; }
|
||||
public string? Language { get; set; }
|
||||
public string? Style { get; set; }
|
||||
}
|
||||
|
||||
public class GenerateCommitMessageDto
|
||||
{
|
||||
public long RepoId { get; set; }
|
||||
public List<FileDiffDto>? Files { get; set; }
|
||||
public string? Style { get; set; }
|
||||
}
|
||||
@@ -41,6 +41,10 @@ builder.Services.AddGrpc(options =>
|
||||
options.MaxSendMessageSize = 50 * 1024 * 1024;
|
||||
});
|
||||
|
||||
// Add REST API controllers
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
|
||||
// Add health checks
|
||||
builder.Services.AddHealthChecks();
|
||||
|
||||
@@ -63,18 +67,11 @@ else
|
||||
app.MapGrpcService<GitCaddyAIServiceImpl>();
|
||||
app.MapHealthChecks("/healthz");
|
||||
|
||||
// Map REST API controllers
|
||||
app.MapControllers();
|
||||
|
||||
// HTTP endpoint for basic health check
|
||||
app.MapGet("/", () => "GitCaddy AI Service is running. Use gRPC to connect.");
|
||||
app.MapGet("/health", async (ILicenseValidator validator) =>
|
||||
{
|
||||
var result = await validator.ValidateAsync();
|
||||
return Results.Json(new
|
||||
{
|
||||
healthy = result.IsValid,
|
||||
version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "1.0.0",
|
||||
license = result.License
|
||||
});
|
||||
});
|
||||
app.MapGet("/", () => "GitCaddy AI Service is running. Use gRPC or REST API to connect.");
|
||||
|
||||
Log.Information("GitCaddy AI Service starting on {Urls}", string.Join(", ", app.Urls));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user