kin: auto-commit after pipeline
This commit is contained in:
parent
94591ab7ae
commit
3d9b5766ab
10 changed files with 250 additions and 30 deletions
12
web/api.py
12
web/api.py
|
|
@ -9,6 +9,7 @@ import mimetypes
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
# Ensure project root on sys.path
|
||||
|
|
@ -27,6 +28,7 @@ from agents.bootstrap import (
|
|||
detect_tech_stack, detect_modules, extract_decisions_from_claude_md,
|
||||
find_vault_root, scan_obsidian, save_to_db,
|
||||
)
|
||||
from core.deploy import VALID_RUNTIMES, deploy_with_dependents
|
||||
|
||||
DB_PATH = Path.home() / ".kin" / "kin.db"
|
||||
|
||||
|
|
@ -226,9 +228,6 @@ class ProjectCreate(BaseModel):
|
|||
return self
|
||||
|
||||
|
||||
VALID_DEPLOY_RUNTIMES = {"docker", "node", "python", "static"}
|
||||
|
||||
|
||||
class ProjectPatch(BaseModel):
|
||||
execution_mode: str | None = None
|
||||
autocommit_enabled: bool | None = None
|
||||
|
|
@ -266,8 +265,8 @@ def patch_project(project_id: str, body: ProjectPatch):
|
|||
raise HTTPException(400, f"Invalid execution_mode '{body.execution_mode}'. Must be one of: {', '.join(VALID_EXECUTION_MODES)}")
|
||||
if body.project_type is not None and body.project_type not in VALID_PROJECT_TYPES:
|
||||
raise HTTPException(400, f"Invalid project_type '{body.project_type}'. Must be one of: {', '.join(VALID_PROJECT_TYPES)}")
|
||||
if body.deploy_runtime is not None and body.deploy_runtime != "" and body.deploy_runtime not in VALID_DEPLOY_RUNTIMES:
|
||||
raise HTTPException(400, f"Invalid deploy_runtime '{body.deploy_runtime}'. Must be one of: {', '.join(sorted(VALID_DEPLOY_RUNTIMES))}")
|
||||
if body.deploy_runtime is not None and body.deploy_runtime != "" and body.deploy_runtime not in VALID_RUNTIMES:
|
||||
raise HTTPException(400, f"Invalid deploy_runtime '{body.deploy_runtime}'. Must be one of: {', '.join(sorted(VALID_RUNTIMES))}")
|
||||
conn = get_conn()
|
||||
p = models.get_project(conn, project_id)
|
||||
if not p:
|
||||
|
|
@ -352,9 +351,6 @@ def deploy_project(project_id: str):
|
|||
|
||||
WARNING: shell=True — deploy commands are admin-only, set in Settings by the project owner.
|
||||
"""
|
||||
import time
|
||||
from core.deploy import deploy_with_dependents
|
||||
|
||||
conn = get_conn()
|
||||
p = models.get_project(conn, project_id)
|
||||
if not p:
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ export interface PipelineStep {
|
|||
|
||||
export interface DeployStepResult {
|
||||
step: string
|
||||
command: string
|
||||
stdout: string
|
||||
stderr: string
|
||||
exit_code: number
|
||||
|
|
@ -189,7 +190,7 @@ export interface ProjectLink {
|
|||
id: number
|
||||
from_project: string
|
||||
to_project: string
|
||||
type: string
|
||||
link_type: string
|
||||
description: string | null
|
||||
created_at: string
|
||||
}
|
||||
|
|
@ -198,6 +199,7 @@ export interface TaskFull extends Task {
|
|||
pipeline_steps: PipelineStep[]
|
||||
related_decisions: Decision[]
|
||||
project_deploy_command: string | null
|
||||
project_deploy_runtime: string | null
|
||||
pipeline_id: string | null
|
||||
}
|
||||
|
||||
|
|
@ -411,7 +413,7 @@ export const api = {
|
|||
get<PipelineLog[]>(`/pipelines/${pipelineId}/logs?since_id=${sinceId}`),
|
||||
projectLinks: (projectId: string) =>
|
||||
get<ProjectLink[]>(`/projects/${projectId}/links`),
|
||||
createProjectLink: (data: { from_project: string; to_project: string; type: string; description?: string }) =>
|
||||
createProjectLink: (data: { from_project: string; to_project: string; link_type: string; description?: string }) =>
|
||||
post<ProjectLink>('/project-links', data),
|
||||
deleteProjectLink: (id: number) =>
|
||||
del<void>(`/project-links/${id}`),
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ const links = ref<ProjectLink[]>([])
|
|||
const linksLoading = ref(false)
|
||||
const linksError = ref('')
|
||||
const showAddLink = ref(false)
|
||||
const linkForm = ref({ to_project: '', type: 'depends_on', description: '' })
|
||||
const linkForm = ref({ to_project: '', link_type: 'depends_on', description: '' })
|
||||
const linkFormError = ref('')
|
||||
const linkSaving = ref(false)
|
||||
|
||||
|
|
@ -419,11 +419,11 @@ async function addLink() {
|
|||
await api.createProjectLink({
|
||||
from_project: props.id,
|
||||
to_project: linkForm.value.to_project,
|
||||
type: linkForm.value.type,
|
||||
link_type: linkForm.value.link_type,
|
||||
description: linkForm.value.description || undefined,
|
||||
})
|
||||
showAddLink.value = false
|
||||
linkForm.value = { to_project: '', type: 'depends_on', description: '' }
|
||||
linkForm.value = { to_project: '', link_type: 'depends_on', description: '' }
|
||||
await loadLinks()
|
||||
} catch (e: any) {
|
||||
linkFormError.value = e.message
|
||||
|
|
@ -1368,7 +1368,7 @@ async function addDecision() {
|
|||
<span class="text-gray-400 font-mono text-xs">{{ link.from_project }}</span>
|
||||
<span class="text-gray-600">-></span>
|
||||
<span class="text-gray-400 font-mono text-xs">{{ link.to_project }}</span>
|
||||
<span class="px-1.5 py-0.5 text-[10px] bg-indigo-900/30 text-indigo-400 border border-indigo-800 rounded">{{ link.type }}</span>
|
||||
<span class="px-1.5 py-0.5 text-[10px] bg-indigo-900/30 text-indigo-400 border border-indigo-800 rounded">{{ link.link_type }}</span>
|
||||
<span v-if="link.description" class="text-gray-500 text-xs">{{ link.description }}</span>
|
||||
</div>
|
||||
<button @click="deleteLink(link.id)"
|
||||
|
|
@ -1379,7 +1379,7 @@ async function addDecision() {
|
|||
</div>
|
||||
|
||||
<!-- Add Link Modal -->
|
||||
<Modal v-if="showAddLink" title="Add Link" @close="showAddLink = false; linkForm = { to_project: '', type: 'depends_on', description: '' }; linkFormError = ''">
|
||||
<Modal v-if="showAddLink" title="Add Link" @close="showAddLink = false; linkForm = { to_project: '', link_type: 'depends_on', description: '' }; linkFormError = ''">
|
||||
<form @submit.prevent="addLink" class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs text-gray-500 mb-1">From (current project)</label>
|
||||
|
|
@ -1396,7 +1396,7 @@ async function addDecision() {
|
|||
</div>
|
||||
<div>
|
||||
<label class="block text-xs text-gray-500 mb-1">Link type</label>
|
||||
<select v-model="linkForm.type"
|
||||
<select v-model="linkForm.link_type"
|
||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-300">
|
||||
<option value="depends_on">depends_on</option>
|
||||
<option value="triggers">triggers</option>
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ async function saveDeployConfig(projectId: string) {
|
|||
saveDeployConfigStatus.value[projectId] = ''
|
||||
try {
|
||||
await api.patchProject(projectId, {
|
||||
deploy_host: deployHosts.value[projectId] || undefined,
|
||||
deploy_path: deployPaths.value[projectId] || undefined,
|
||||
deploy_runtime: deployRuntimes.value[projectId] || undefined,
|
||||
deploy_restart_cmd: deployRestartCmds.value[projectId] || undefined,
|
||||
deploy_host: deployHosts.value[projectId],
|
||||
deploy_path: deployPaths.value[projectId],
|
||||
deploy_runtime: deployRuntimes.value[projectId],
|
||||
deploy_restart_cmd: deployRestartCmds.value[projectId],
|
||||
})
|
||||
saveDeployConfigStatus.value[projectId] = 'Saved'
|
||||
} catch (e) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue