# Gitea API Client # # REST API v1 client for Gitea operations # # Version: 1.0.0 # Dependencies: http, nu_plugin_tera use ../config/loader.nu get-config # Get Gitea configuration from global config export def get-gitea-config [] -> record { let config = get-config if "gitea" not-in $config { error make { msg: "Gitea not configured" help: "Add gitea section to configuration" } } $config.gitea } # Get Gitea auth token export def get-gitea-token [ gitea_config: record ] -> string { let token_path = $gitea_config.auth.token_path | path expand if not ($token_path | path exists) { error make { msg: $"Token file not found: ($token_path)" help: "Create token file with Gitea access token" } } # Check if encrypted (SOPS) if ($token_path | str ends-with ".enc") { # Decrypt with SOPS ^sops --decrypt $token_path | str trim } else { open $token_path | str trim } } # Get base API URL export def get-api-url [ gitea_config: record ] -> string { if $gitea_config.mode == "local" { let port = $gitea_config.local.port $"http://localhost:($port)/api/v1" } else { $gitea_config.remote.api_url } } # Make API call to Gitea export def gitea-api-call [ endpoint: string method: string = "GET" body?: record --gitea-config: record ] -> record { let config = if ($gitea_config | is-empty) { get-gitea-config } else { $gitea_config } let token = get-gitea-token $config let base_url = get-api-url $config let url = $"($base_url)/($endpoint)" let headers = [ "Authorization" $"token ($token)" "Content-Type" "application/json" "Accept" "application/json" ] let result = if $method == "GET" { http get --headers $headers $url } else if $method == "POST" { if ($body | is-empty) { http post --headers $headers $url "" } else { http post --headers $headers $url ($body | to json) } } else if $method == "PUT" { if ($body | is-empty) { http put --headers $headers $url "" } else { http put --headers $headers $url ($body | to json) } } else if $method == "DELETE" { http delete --headers $headers $url } else if $method == "PATCH" { if ($body | is-empty) { http patch --headers $headers $url "" } else { http patch --headers $headers $url ($body | to json) } } else { error make { msg: $"Unsupported HTTP method: ($method)" } } $result } # Repository Operations # Create repository export def create-repository [ org: string repo_name: string description?: string private: bool = false auto_init: bool = true ] -> record { let body = { name: $repo_name description: ($description | default "") private: $private auto_init: $auto_init default_branch: "main" } gitea-api-call $"orgs/($org)/repos" "POST" $body } # Get repository export def get-repository [ owner: string repo_name: string ] -> record { gitea-api-call $"repos/($owner)/($repo_name)" "GET" } # Delete repository export def delete-repository [ owner: string repo_name: string --force (-f) ] -> bool { if not $force { print $"⚠️ About to delete repository ($owner)/($repo_name)" let confirm = input "Type repository name to confirm: " if $confirm != $repo_name { print "Deletion cancelled" return false } } gitea-api-call $"repos/($owner)/($repo_name)" "DELETE" true } # List repositories in organization export def list-repositories [ org: string ] -> list { gitea-api-call $"orgs/($org)/repos" "GET" } # List user repositories export def list-user-repositories [ username?: string ] -> list { let user = if ($username | is-empty) { (get-current-user).login } else { $username } gitea-api-call $"users/($user)/repos" "GET" } # Release Operations # Create release export def create-release [ owner: string repo_name: string tag_name: string release_name: string body?: string draft: bool = false prerelease: bool = false ] -> record { let release_body = { tag_name: $tag_name name: $release_name body: ($body | default "") draft: $draft prerelease: $prerelease target_commitish: "main" } gitea-api-call $"repos/($owner)/($repo_name)/releases" "POST" $release_body } # Upload release asset export def upload-release-asset [ owner: string repo_name: string release_id: int file_path: string ] -> bool { let config = get-gitea-config let token = get-gitea-token $config let base_url = get-api-url $config let filename = $file_path | path basename let url = $"($base_url)/repos/($owner)/($repo_name)/releases/($release_id)/assets?name=($filename)" # Use curl for file upload (http command doesn't support multipart/form-data well) let result = ^curl -X POST \ -H $"Authorization: token ($token)" \ -F $"attachment=@($file_path)" \ $url true } # Get release by tag export def get-release-by-tag [ owner: string repo_name: string tag: string ] -> record { gitea-api-call $"repos/($owner)/($repo_name)/releases/tags/($tag)" "GET" } # List releases export def list-releases [ owner: string repo_name: string ] -> list { gitea-api-call $"repos/($owner)/($repo_name)/releases" "GET" } # Delete release export def delete-release [ owner: string repo_name: string release_id: int ] -> bool { gitea-api-call $"repos/($owner)/($repo_name)/releases/($release_id)" "DELETE" true } # Issue Operations (for locking) # Create issue export def create-issue [ owner: string repo_name: string title: string body: string labels: list = [] assignee?: string ] -> record { let issue_body = { title: $title body: $body labels: $labels } let issue_with_assignee = if ($assignee | is-not-empty) { $issue_body | merge {assignee: $assignee} } else { $issue_body } gitea-api-call $"repos/($owner)/($repo_name)/issues" "POST" $issue_with_assignee } # Close issue export def close-issue [ owner: string repo_name: string issue_number: int ] -> bool { let body = {state: "closed"} gitea-api-call $"repos/($owner)/($repo_name)/issues/($issue_number)" "PATCH" $body true } # List issues export def list-issues [ owner: string repo_name: string state: string = "open" labels?: string ] -> list { let endpoint = if ($labels | is-empty) { $"repos/($owner)/($repo_name)/issues?state=($state)" } else { $"repos/($owner)/($repo_name)/issues?state=($state)&labels=($labels)" } gitea-api-call $endpoint "GET" } # Get issue export def get-issue [ owner: string repo_name: string issue_number: int ] -> record { gitea-api-call $"repos/($owner)/($repo_name)/issues/($issue_number)" "GET" } # Organization Operations # Create organization export def create-organization [ org_name: string description?: string visibility: string = "private" ] -> record { let body = { username: $org_name description: ($description | default "") visibility: $visibility } gitea-api-call "orgs" "POST" $body } # Get organization export def get-organization [ org_name: string ] -> record { gitea-api-call $"orgs/($org_name)" "GET" } # List organizations export def list-organizations [] -> list { gitea-api-call "user/orgs" "GET" } # User/Auth Operations # Get current user export def get-current-user [] -> record { gitea-api-call "user" "GET" } # Validate token export def validate-token [ gitea_config?: record ] { let config = if ($gitea_config | is-empty) { get-gitea-config } else { $gitea_config } let result = (do { gitea-api-call "user" "GET" --gitea-config $config } | complete) if $result.exit_code == 0 { let user = $result.stdout | from json $user.login? != null } else { false } } # Branch Operations # Create branch export def create-branch [ owner: string repo_name: string branch_name: string base_branch: string = "main" ] -> record { let body = { new_branch_name: $branch_name old_branch_name: $base_branch } gitea-api-call $"repos/($owner)/($repo_name)/branches" "POST" $body } # List branches export def list-branches [ owner: string repo_name: string ] -> list { gitea-api-call $"repos/($owner)/($repo_name)/branches" "GET" } # Get branch export def get-branch [ owner: string repo_name: string branch_name: string ] -> record { gitea-api-call $"repos/($owner)/($repo_name)/branches/($branch_name)" "GET" } # Tag Operations # Create tag export def create-tag [ owner: string repo_name: string tag_name: string message?: string target?: string ] -> record { let body = { tag_name: $tag_name message: ($message | default "") target: ($target | default "main") } gitea-api-call $"repos/($owner)/($repo_name)/tags" "POST" $body } # List tags export def list-tags [ owner: string repo_name: string ] -> list { gitea-api-call $"repos/($owner)/($repo_name)/tags" "GET" }