253 lines
7.4 KiB
PowerShell
253 lines
7.4 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
# Git Sync Script with Gantt Integration
|
|
# Runs daily at 10:30 AM
|
|
|
|
param(
|
|
[string]$RepoPath = "D:/fork_project/obsidian-notes"
|
|
)
|
|
|
|
$InBoxPath = Join-Path $RepoPath "InBox"
|
|
$GanttTag = "obsidian"
|
|
$GitArgs = @("-c", "safe.directory=$RepoPath")
|
|
|
|
function Resolve-GanttApp {
|
|
$candidates = @(
|
|
"C:/Users/Administrator/Desktop/我的/app_gant2/src-tauri/target/release/gantt-app.exe",
|
|
"C:/Users/Administrator/Desktop/我的/app_gant2/src-tauri/target/debug/gantt-app.exe"
|
|
)
|
|
|
|
foreach ($candidate in $candidates) {
|
|
if (Test-Path $candidate) {
|
|
return $candidate
|
|
}
|
|
}
|
|
|
|
$searchRoot = "C:/Users/Administrator/Desktop"
|
|
if (Test-Path $searchRoot) {
|
|
$found = Get-ChildItem -Path $searchRoot -Filter "gantt-app.exe" -Recurse -ErrorAction SilentlyContinue |
|
|
Sort-Object FullName -Descending |
|
|
Select-Object -First 1 -ExpandProperty FullName
|
|
if ($found) {
|
|
return $found
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
$GanttApp = Resolve-GanttApp
|
|
|
|
# Change to repo directory
|
|
Set-Location $RepoPath
|
|
|
|
function Invoke-GitCommand {
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string[]]$Arguments
|
|
)
|
|
|
|
$output = & git @GitArgs @Arguments 2>&1
|
|
return [PSCustomObject]@{
|
|
Output = @($output)
|
|
ExitCode = $LASTEXITCODE
|
|
}
|
|
}
|
|
|
|
function Get-InBoxFileNames {
|
|
if (Test-Path $InBoxPath) {
|
|
return Get-ChildItem -Path $InBoxPath -File | Select-Object -ExpandProperty Name
|
|
}
|
|
|
|
return @()
|
|
}
|
|
|
|
# Function to get all Gantt tasks
|
|
function Get-GanttTasks {
|
|
if ($GanttApp -and (Test-Path $GanttApp)) {
|
|
try {
|
|
$result = & $GanttApp --cli list-tasks 2>$null | ConvertFrom-Json
|
|
if ($result.ok -and $result.data.tasks) {
|
|
return $result.data.tasks
|
|
}
|
|
} catch {
|
|
Write-Host "Failed to get Gantt tasks: $_"
|
|
}
|
|
}
|
|
return @()
|
|
}
|
|
|
|
# Function to show Windows notification
|
|
function Show-Notification {
|
|
param([string]$Title, [string]$Message)
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
|
|
$path = (Get-Process -Id $pid).Path
|
|
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
|
|
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Warning
|
|
$balloon.BalloonTipText = $Message
|
|
$balloon.BalloonTipTitle = $Title
|
|
$balloon.Visible = $true
|
|
$balloon.ShowBalloonTip(5000)
|
|
}
|
|
|
|
function Fail-AndExit {
|
|
param(
|
|
[string]$Title,
|
|
[string]$Message
|
|
)
|
|
|
|
Write-Host $Message
|
|
Show-Notification -Title $Title -Message $Message
|
|
exit 1
|
|
}
|
|
|
|
function Test-RepoReady {
|
|
if (-not (Test-Path $RepoPath)) {
|
|
Fail-AndExit -Title "Git Sync Error" -Message "Repository path not found: $RepoPath"
|
|
}
|
|
|
|
$statusResult = Invoke-GitCommand -Arguments @("status", "--short", "--branch")
|
|
if ($statusResult.ExitCode -ne 0) {
|
|
$message = ($statusResult.Output -join [Environment]::NewLine).Trim()
|
|
if ([string]::IsNullOrWhiteSpace($message)) {
|
|
$message = "Failed to read git status."
|
|
}
|
|
Fail-AndExit -Title "Git Sync Error" -Message $message
|
|
}
|
|
|
|
$dirtyEntries = $statusResult.Output | Where-Object {
|
|
$_ -and $_ -notmatch "^## "
|
|
}
|
|
|
|
if ($dirtyEntries.Count -gt 0) {
|
|
$preview = ($dirtyEntries | Select-Object -First 5) -join "; "
|
|
$message = "Working tree is not clean. Resolve or commit local changes before auto sync. $preview"
|
|
Fail-AndExit -Title "Git Sync Blocked" -Message $message
|
|
}
|
|
}
|
|
|
|
function Add-GanttTask {
|
|
param([string]$TaskName)
|
|
$today = Get-Date -Format "yyyy-MM-dd"
|
|
$taskId = [Guid]::NewGuid().ToString()
|
|
|
|
if ($GanttApp -and (Test-Path $GanttApp)) {
|
|
try {
|
|
& $GanttApp --cli add-task --id $taskId --name $TaskName --start $today --description "Auto-created from InBox sync" --tag $GanttTag 2>$null
|
|
Write-Host "Created Gantt task: $TaskName"
|
|
} catch {
|
|
Write-Host "Failed to create Gantt task: $_"
|
|
}
|
|
} else {
|
|
Write-Host "Gantt app not found"
|
|
}
|
|
}
|
|
|
|
function Update-GanttTaskTag {
|
|
param(
|
|
[string]$TaskId,
|
|
[string]$TaskName
|
|
)
|
|
|
|
if ($GanttApp -and (Test-Path $GanttApp)) {
|
|
try {
|
|
& $GanttApp --cli update-task --id $TaskId --tag $GanttTag 2>$null
|
|
Write-Host "Updated Gantt task tag: $TaskName"
|
|
} catch {
|
|
Write-Host "Failed to update Gantt task tag: $_"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Remove-GanttTask {
|
|
param([string]$TaskId)
|
|
if ($GanttApp -and (Test-Path $GanttApp)) {
|
|
try {
|
|
& $GanttApp --cli delete-task --id $TaskId 2>$null
|
|
Write-Host "Deleted Gantt task: $TaskId"
|
|
} catch {
|
|
Write-Host "Failed to delete Gantt task: $_"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Sync-InBoxTasks {
|
|
if (-not ($GanttApp -and (Test-Path $GanttApp))) {
|
|
Write-Host "Skipping Gantt sync because gantt-app.exe was not found"
|
|
return
|
|
}
|
|
|
|
$inboxFiles = Get-InBoxFileNames
|
|
$ganttTasks = Get-GanttTasks
|
|
$existingInboxTasks = $ganttTasks | Where-Object { $_.name -match "^Process InBox: " }
|
|
|
|
foreach ($task in $existingInboxTasks) {
|
|
$taskFileName = $task.name -replace "^Process InBox: ", ""
|
|
if ($taskFileName -notin $inboxFiles) {
|
|
Write-Host "File no longer exists, deleting task: $($task.name)"
|
|
Remove-GanttTask -TaskId $task.id
|
|
}
|
|
}
|
|
|
|
foreach ($file in $inboxFiles) {
|
|
$taskName = "Process InBox: $file"
|
|
$matchingTasks = @($existingInboxTasks | Where-Object { $_.name -eq $taskName })
|
|
|
|
if ($matchingTasks.Count -eq 0) {
|
|
Add-GanttTask -TaskName $taskName
|
|
continue
|
|
}
|
|
|
|
foreach ($task in $matchingTasks) {
|
|
if ($task.tag -ne $GanttTag) {
|
|
Update-GanttTaskTag -TaskId $task.id -TaskName $task.name
|
|
} else {
|
|
Write-Host "Task already exists for: $file"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Perform git pull
|
|
Test-RepoReady
|
|
|
|
Write-Host "Starting git pull at $(Get-Date)..."
|
|
$pullResult = Invoke-GitCommand -Arguments @("pull")
|
|
$pullOutput = $pullResult.Output
|
|
$pullExitCode = $pullResult.ExitCode
|
|
|
|
if ($pullExitCode -ne 0) {
|
|
$message = "Git pull failed: " + (($pullOutput -join [Environment]::NewLine).Trim())
|
|
Fail-AndExit -Title "Git Sync Error" -Message $message
|
|
}
|
|
|
|
Write-Host "Git pull completed: $($pullOutput -join [Environment]::NewLine)"
|
|
|
|
# Check for merge conflicts
|
|
if ($pullOutput -match "CONFLICT|conflict|Automatic merge failed") {
|
|
Show-Notification -Title "Git Sync Conflict" -Message "Merge conflicts detected during git pull. Please resolve manually."
|
|
exit 1
|
|
}
|
|
|
|
# Sync Gantt tasks against the full current InBox state
|
|
Start-Sleep -Seconds 2
|
|
Sync-InBoxTasks
|
|
|
|
# Perform git push
|
|
Write-Host "Starting git push..."
|
|
$pushResult = Invoke-GitCommand -Arguments @("push")
|
|
$pushOutput = $pushResult.Output
|
|
$pushExitCode = $pushResult.ExitCode
|
|
|
|
if ($pushExitCode -ne 0) {
|
|
$pushText = ($pushOutput -join [Environment]::NewLine).Trim()
|
|
if ($pushText -match "rejected|failed|conflict|non-fast-forward") {
|
|
Show-Notification -Title "Git Push Conflict" -Message "Push rejected. Please pull and resolve conflicts manually."
|
|
} else {
|
|
Show-Notification -Title "Git Push Error" -Message "Git push failed: $pushText"
|
|
}
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "Git push completed successfully at $(Get-Date)"
|