add github

This commit is contained in:
2026-06-30 15:20:26 +07:00
parent 38e22b3390
commit 840ddcdce9
4 changed files with 234 additions and 54 deletions

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
@@ -65,8 +66,27 @@ type gitPathFile struct {
content []byte
}
func githubRepoAPI(owner, repo, suffix string) string {
return fmt.Sprintf("https://api.github.com/repos/%s/%s%s",
url.PathEscape(strings.TrimSpace(owner)),
url.PathEscape(strings.TrimSpace(repo)),
suffix,
)
}
func resolveGitPushTarget(token, fallbackOwner, repoName, repoHTML string) (owner, repo string) {
if o, r, err := parseGitHubRepo(repoHTML); err == nil && o != "" && r != "" {
return o, r
}
owner = strings.TrimSpace(fallbackOwner)
if live, err := githubGetUser(token); err == nil && live != "" {
owner = live
}
return owner, trimGitHubRepoName(repoName)
}
func githubCreateBlob(token, owner, repo string, content []byte) (string, error) {
apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/blobs", owner, repo)
apiURL := githubRepoAPI(owner, repo, "/git/blobs")
body := map[string]string{
"content": base64.StdEncoding.EncodeToString(content),
"encoding": "base64",
@@ -84,7 +104,7 @@ func githubCreateBlob(token, owner, repo string, content []byte) (string, error)
}
func githubCreateTree(token, owner, repo, baseTreeSHA string, entries []map[string]string) (string, error) {
apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/trees", owner, repo)
apiURL := githubRepoAPI(owner, repo, "/git/trees")
body := map[string]any{"tree": entries}
if baseTreeSHA != "" {
body["base_tree"] = baseTreeSHA
@@ -102,7 +122,7 @@ func githubCreateTree(token, owner, repo, baseTreeSHA string, entries []map[stri
}
func githubCreateCommit(token, owner, repo, treeSHA, parentSHA, message string) (string, error) {
apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/commits", owner, repo)
apiURL := githubRepoAPI(owner, repo, "/git/commits")
body := map[string]any{
"message": message,
"tree": treeSHA,
@@ -123,22 +143,30 @@ func githubCreateCommit(token, owner, repo, treeSHA, parentSHA, message string)
}
func githubUpdateBranchRef(token, owner, repo, branch, commitSHA string) error {
apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/refs/heads/%s", owner, repo, branch)
apiURL := githubRepoAPI(owner, repo, "/git/refs/heads/"+url.PathEscape(branch))
body := map[string]any{"sha": commitSHA, "force": false}
err := githubJSON(token, http.MethodPatch, apiURL, body, nil)
if err == nil {
return nil
}
createURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/refs", owner, repo)
// Branch chưa tồn tại — tạo mới
createURL := githubRepoAPI(owner, repo, "/git/refs")
createBody := map[string]string{
"ref": "refs/heads/" + branch,
"sha": commitSHA,
}
return githubJSON(token, http.MethodPost, createURL, createBody, nil)
if createErr := githubJSON(token, http.MethodPost, createURL, createBody, nil); createErr == nil {
return nil
} else if !strings.Contains(strings.ToLower(createErr.Error()), "already exists") {
return createErr
}
// Ref đã tồn tại nhưng PATCH thất bại (non-fast-forward) — cập nhật force
forceBody := map[string]any{"sha": commitSHA, "force": true}
return githubJSON(token, http.MethodPatch, apiURL, forceBody, nil)
}
func githubBranchTip(token, owner, repo, branch string) (commitSHA, treeSHA string, err error) {
apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/ref/heads/%s", owner, repo, branch)
apiURL := githubRepoAPI(owner, repo, "/git/ref/heads/"+url.PathEscape(branch))
var refResp struct {
Object struct {
SHA string `json:"sha"`
@@ -151,7 +179,7 @@ func githubBranchTip(token, owner, repo, branch string) (commitSHA, treeSHA stri
if commitSHA == "" {
return "", "", errors.New("không lấy được commit hiện tại")
}
commitURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/commits/%s", owner, repo, commitSHA)
commitURL := githubRepoAPI(owner, repo, "/git/commits/"+url.PathEscape(commitSHA))
var commitResp struct {
Tree struct {
SHA string `json:"sha"`
@@ -178,6 +206,7 @@ func githubJSON(token, method, apiURL string, body any, out any) error {
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Accept", "application/vnd.github+json")
req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
if body != nil {
req.Header.Set("Content-Type", "application/json")
}