469 lines
10 KiB
Text
469 lines
10 KiB
Text
# Gitea Workspace Git Operations
|
|
#
|
|
# Workspace-level git integration with Gitea
|
|
#
|
|
# Version: 1.0.0
|
|
|
|
# Selective imports (ADR-025 Phase 3 Layer 2).
|
|
use domain/gitea/api_client.nu [create-repository get-gitea-config get-repository]
|
|
|
|
# Initialize workspace as git repository
|
|
export def init-workspace-git [
|
|
workspace_path: string
|
|
workspace_name: string
|
|
--remote: string = "gitea" # gitea, github, gitlab, none
|
|
--private: bool = true
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
if not ($ws_path | path exists) {
|
|
error make {
|
|
msg: $"Workspace path does not exist: ($ws_path)"
|
|
}
|
|
}
|
|
|
|
# Initialize git repository
|
|
cd $ws_path
|
|
^git init
|
|
|
|
# Configure git
|
|
^git config user.name "Provisioning System"
|
|
^git config user.email "provisioning@system.local"
|
|
|
|
# Create initial commit
|
|
^git add .
|
|
^git commit -m "Initial workspace commit"
|
|
|
|
# Create main branch
|
|
^git branch -M main
|
|
|
|
# Add remote if requested
|
|
if $remote == "gitea" {
|
|
let config = get-gitea-config
|
|
let org = $config.repositories.workspaces_org
|
|
|
|
# Create repository on Gitea
|
|
let repo = create-repository $org $workspace_name $"Workspace: ($workspace_name)" $private
|
|
|
|
let repo_url = $repo.clone_url
|
|
|
|
# Add remote
|
|
^git remote add origin $repo_url
|
|
|
|
# Push initial commit
|
|
^git push -u origin main
|
|
|
|
print $"✓ Workspace initialized with Gitea remote: ($repo_url)"
|
|
} else if $remote != "none" {
|
|
print $"⚠️ Remote type '($remote)' not yet implemented"
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
# Create repository on Gitea for workspace
|
|
export def create-workspace-repo [
|
|
workspace_name: string
|
|
--description: string = ""
|
|
--private: bool = true
|
|
] -> record {
|
|
let config = get-gitea-config
|
|
let org = $config.repositories.workspaces_org
|
|
|
|
let desc = if ($description | is-empty) {
|
|
$"Provisioning workspace: ($workspace_name)"
|
|
} else {
|
|
$description
|
|
}
|
|
|
|
create-repository $org $workspace_name $desc $private
|
|
}
|
|
|
|
# Clone workspace from Gitea
|
|
export def clone-workspace [
|
|
workspace_identifier: string # org/workspace-name or just workspace-name
|
|
destination_path: string
|
|
--branch: string = "main"
|
|
] -> bool {
|
|
let config = get-gitea-config
|
|
|
|
# Parse workspace identifier
|
|
let parts = $workspace_identifier | split row "/"
|
|
let repo_name = if ($parts | length) == 2 {
|
|
$parts.1
|
|
} else {
|
|
$workspace_identifier
|
|
}
|
|
let org = if ($parts | length) == 2 {
|
|
$parts.0
|
|
} else {
|
|
$config.repositories.workspaces_org
|
|
}
|
|
|
|
# Get repository info
|
|
let repo = get-repository $org $repo_name
|
|
let clone_url = $repo.clone_url
|
|
|
|
# Clone repository
|
|
^git clone --branch $branch $clone_url $destination_path
|
|
|
|
print $"✓ Workspace cloned from ($clone_url)"
|
|
true
|
|
}
|
|
|
|
# Push workspace changes
|
|
export def push-workspace [
|
|
workspace_path: string
|
|
commit_message?: string
|
|
--branch: string = "main"
|
|
--add-all: bool = true
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
# Check if git repository
|
|
if not ($"($ws_path)/.git" | path exists) {
|
|
error make {
|
|
msg: "Not a git repository"
|
|
help: "Initialize with 'workspace init --git'"
|
|
}
|
|
}
|
|
|
|
# Add changes
|
|
if $add_all {
|
|
^git add .
|
|
}
|
|
|
|
# Check if there are changes
|
|
let status = ^git status --porcelain | complete
|
|
if ($status.stdout | is-empty) {
|
|
print "No changes to commit"
|
|
return false
|
|
}
|
|
|
|
# Commit changes
|
|
let msg = if ($commit_message | is-empty) {
|
|
let timestamp = date now | format date "%Y-%m-%d %H:%M:%S"
|
|
$"Workspace update: ($timestamp)"
|
|
} else {
|
|
$commit_message
|
|
}
|
|
|
|
^git commit -m $msg
|
|
|
|
# Push to remote
|
|
^git push origin $branch
|
|
|
|
print $"✓ Workspace changes pushed to ($branch)"
|
|
true
|
|
}
|
|
|
|
# Pull workspace changes
|
|
export def pull-workspace [
|
|
workspace_path: string
|
|
--branch: string = "main"
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
# Check if git repository
|
|
if not ($"($ws_path)/.git" | path exists) {
|
|
error make {
|
|
msg: "Not a git repository"
|
|
}
|
|
}
|
|
|
|
# Pull changes
|
|
^git pull origin $branch
|
|
|
|
print $"✓ Workspace updated from ($branch)"
|
|
true
|
|
}
|
|
|
|
# Create branch
|
|
export def create-workspace-branch [
|
|
workspace_path: string
|
|
branch_name: string
|
|
--from-branch: string = "main"
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
# Create local branch
|
|
^git checkout -b $branch_name $from_branch
|
|
|
|
# Push to remote
|
|
^git push -u origin $branch_name
|
|
|
|
print $"✓ Branch created: ($branch_name)"
|
|
true
|
|
}
|
|
|
|
# Switch branch
|
|
export def switch-workspace-branch [
|
|
workspace_path: string
|
|
branch_name: string
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
# Switch branch
|
|
^git checkout $branch_name
|
|
|
|
print $"✓ Switched to branch: ($branch_name)"
|
|
true
|
|
}
|
|
|
|
# List branches
|
|
export def list-workspace-branches [
|
|
workspace_path: string
|
|
--remote: bool = false
|
|
] -> list {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
if $remote {
|
|
^git branch -r | lines | each {|line| $line | str trim | str replace "origin/" ""}
|
|
} else {
|
|
^git branch | lines | each {|line| $line | str trim | str replace "* " ""}
|
|
}
|
|
}
|
|
|
|
# Delete branch
|
|
export def delete-workspace-branch [
|
|
workspace_path: string
|
|
branch_name: string
|
|
--remote: bool = false
|
|
--force: bool = false
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
# Delete local branch
|
|
if $force {
|
|
^git branch -D $branch_name
|
|
} else {
|
|
^git branch -d $branch_name
|
|
}
|
|
|
|
# Delete remote branch
|
|
if $remote {
|
|
^git push origin --delete $branch_name
|
|
}
|
|
|
|
print $"✓ Branch deleted: ($branch_name)"
|
|
true
|
|
}
|
|
|
|
# Sync workspace (pull + push)
|
|
export def sync-workspace [
|
|
workspace_path: string
|
|
--branch: string = "main"
|
|
--commit-message?: string
|
|
] -> record {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
# Pull latest changes
|
|
pull-workspace $ws_path --branch $branch
|
|
|
|
# Push local changes
|
|
let pushed = push-workspace $ws_path $commit_message --branch $branch
|
|
|
|
{
|
|
pulled: true
|
|
pushed: $pushed
|
|
branch: $branch
|
|
}
|
|
}
|
|
|
|
# Get workspace git status
|
|
export def get-workspace-git-status [
|
|
workspace_path: string
|
|
] -> record {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
# Check if git repository
|
|
if not ($"($ws_path)/.git" | path exists) {
|
|
return {
|
|
is_git_repo: false
|
|
branch: null
|
|
status: null
|
|
remote: null
|
|
}
|
|
}
|
|
|
|
# Get current branch
|
|
let branch = ^git branch --show-current | str trim
|
|
|
|
# Get status
|
|
let status = ^git status --porcelain | lines
|
|
|
|
# Get remote
|
|
let remote_result = (do {
|
|
^git remote get-url origin
|
|
} | complete)
|
|
|
|
let remote = if $remote_result.exit_code == 0 {
|
|
$remote_result.stdout | str trim
|
|
} else {
|
|
null
|
|
}
|
|
|
|
# Get last commit
|
|
let commit_result = (do {
|
|
^git log -1 --format="%H|%an|%ae|%at|%s"
|
|
} | complete)
|
|
|
|
let last_commit = if $commit_result.exit_code == 0 {
|
|
$commit_result.stdout | str trim
|
|
} else {
|
|
null
|
|
}
|
|
|
|
let commit_info = if ($last_commit | is-not-empty) {
|
|
let parts = $last_commit | split row "|"
|
|
{
|
|
hash: $parts.0
|
|
author_name: $parts.1
|
|
author_email: $parts.2
|
|
timestamp: ($parts.3 | into int)
|
|
message: $parts.4
|
|
}
|
|
} else {
|
|
null
|
|
}
|
|
|
|
{
|
|
is_git_repo: true
|
|
branch: $branch
|
|
status: $status
|
|
remote: $remote
|
|
last_commit: $commit_info
|
|
has_changes: ($status | length) > 0
|
|
}
|
|
}
|
|
|
|
# Get workspace remote info
|
|
export def get-workspace-remote-info [
|
|
workspace_path: string
|
|
] -> record {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
let remote_result = (do {
|
|
^git remote get-url origin
|
|
} | complete)
|
|
|
|
if $remote_result.exit_code != 0 {
|
|
return {has_remote: false}
|
|
}
|
|
|
|
let remote_url = $remote_result.stdout | str trim
|
|
|
|
# Parse Gitea URL
|
|
let config = get-gitea-config
|
|
let base_url = if $config.mode == "local" {
|
|
$"http://localhost:($config.local.port)"
|
|
} else {
|
|
$config.remote.url
|
|
}
|
|
|
|
let is_gitea = $remote_url | str starts-with $base_url
|
|
|
|
if $is_gitea {
|
|
# Extract owner and repo from URL
|
|
let parts = $remote_url | str replace $"($base_url)/" "" | str replace ".git" "" | split row "/"
|
|
{
|
|
has_remote: true
|
|
type: "gitea"
|
|
url: $remote_url
|
|
owner: $parts.0
|
|
repo: $parts.1
|
|
}
|
|
} else {
|
|
{
|
|
has_remote: true
|
|
type: "external"
|
|
url: $remote_url
|
|
}
|
|
}
|
|
}
|
|
|
|
# Check if workspace has uncommitted changes
|
|
export def has-uncommitted-changes [
|
|
workspace_path: string
|
|
] -> bool {
|
|
let status = get-workspace-git-status $workspace_path
|
|
$status.has_changes
|
|
}
|
|
|
|
# Get workspace diff
|
|
export def get-workspace-diff [
|
|
workspace_path: string
|
|
--staged: bool = false
|
|
] -> string {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
if $staged {
|
|
^git diff --staged
|
|
} else {
|
|
^git diff
|
|
}
|
|
}
|
|
|
|
# Stash workspace changes
|
|
export def stash-workspace-changes [
|
|
workspace_path: string
|
|
message?: string
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
let msg = if ($message | is-empty) {
|
|
"Workspace stash"
|
|
} else {
|
|
$message
|
|
}
|
|
|
|
^git stash push -m $msg
|
|
|
|
print "✓ Changes stashed"
|
|
true
|
|
}
|
|
|
|
# Pop stashed changes
|
|
export def pop-workspace-stash [
|
|
workspace_path: string
|
|
] -> bool {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
^git stash pop
|
|
|
|
print "✓ Stash applied"
|
|
true
|
|
}
|
|
|
|
# List workspace stashes
|
|
export def list-workspace-stashes [
|
|
workspace_path: string
|
|
] -> list {
|
|
let ws_path = $workspace_path | path expand
|
|
|
|
cd $ws_path
|
|
|
|
^git stash list | lines
|
|
}
|