feat: implemented token auth

This commit is contained in:
2026-03-15 21:00:42 +03:00
parent 4dbe4da184
commit c51e4ea188
4 changed files with 99 additions and 12 deletions

57
git.go
View File

@@ -3,14 +3,21 @@ package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
)
// gitRun executes a git command in repoPath, returning a descriptive error
// that includes the combined stdout+stderr on failure.
func gitRun(repoPath string, args ...string) error {
cmd := exec.Command("git", append([]string{"-C", repoPath}, args...)...)
func gitRun(cfg *Config, args ...string) error {
env, err := gitCommandEnv(cfg)
if err != nil {
return err
}
cmd := exec.Command("git", append([]string{"-C", cfg.RepoPath}, args...)...)
cmd.Env = env
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("git %s: %w\n%s",
@@ -20,8 +27,14 @@ func gitRun(repoPath string, args ...string) error {
}
// gitOutput executes a git command and returns its stdout as a string.
func gitOutput(repoPath string, args ...string) (string, error) {
cmd := exec.Command("git", append([]string{"-C", repoPath}, args...)...)
func gitOutput(cfg *Config, args ...string) (string, error) {
env, err := gitCommandEnv(cfg)
if err != nil {
return "", err
}
cmd := exec.Command("git", append([]string{"-C", cfg.RepoPath}, args...)...)
cmd.Env = env
out, err := cmd.Output()
if err != nil {
var stderr []byte
@@ -34,14 +47,38 @@ func gitOutput(repoPath string, args ...string) (string, error) {
return string(out), nil
}
// gitCommandEnv builds the environment for git subprocesses.
// If GIT_AUTH_TOKEN is provided, non-interactive HTTPS auth is enabled via askpass.
func gitCommandEnv(cfg *Config) ([]string, error) {
env := os.Environ()
if cfg.GitAuthToken == "" {
return env, nil
}
exePath, err := os.Executable()
if err != nil {
return nil, fmt.Errorf("resolve executable path for GIT_ASKPASS: %w", err)
}
env = append(env,
"GIT_TERMINAL_PROMPT=0",
"GIT_ASKPASS_REQUIRE=force",
"GIT_ASKPASS="+exePath,
"TDW_GIT_ASKPASS=1",
"GIT_AUTH_USERNAME="+cfg.GitAuthUsername,
"GIT_AUTH_TOKEN="+cfg.GitAuthToken,
)
return env, nil
}
// GitPull fetches from the remote and rebases the local branch.
// Using --autostash ensures any uncommitted changes are preserved across the rebase
// (should not normally happen but guards against manual edits).
func GitPull(cfg *Config) error {
if err := gitRun(cfg.RepoPath, "fetch", "--prune", cfg.RepoRemote); err != nil {
if err := gitRun(cfg, "fetch", "--prune", cfg.RepoRemote); err != nil {
return fmt.Errorf("git fetch: %w", err)
}
if err := gitRun(cfg.RepoPath,
if err := gitRun(cfg,
"pull", "--rebase", "--autostash",
cfg.RepoRemote, cfg.RepoBranch,
); err != nil {
@@ -52,7 +89,7 @@ func GitPull(cfg *Config) error {
// GitStatusChanged reports true when the working tree has uncommitted changes.
func GitStatusChanged(cfg *Config) (bool, error) {
out, err := gitOutput(cfg.RepoPath, "status", "--porcelain")
out, err := gitOutput(cfg, "status", "--porcelain")
if err != nil {
return false, err
}
@@ -63,17 +100,17 @@ func GitStatusChanged(cfg *Config) (bool, error) {
// and pushes to the configured remote branch.
// Author identity is passed via git -c flags to avoid requiring global git config.
func GitCommitAndPush(cfg *Config, message string) error {
if err := gitRun(cfg.RepoPath, "add", cfg.DynamicDir); err != nil {
if err := gitRun(cfg, "add", cfg.DynamicDir); err != nil {
return fmt.Errorf("git add: %w", err)
}
if err := gitRun(cfg.RepoPath,
if err := gitRun(cfg,
"-c", "user.name="+cfg.AuthorName,
"-c", "user.email="+cfg.AuthorEmail,
"commit", "-m", message,
); err != nil {
return fmt.Errorf("git commit: %w", err)
}
if err := gitRun(cfg.RepoPath, "push", cfg.RepoRemote, cfg.RepoBranch); err != nil {
if err := gitRun(cfg, "push", cfg.RepoRemote, cfg.RepoBranch); err != nil {
return fmt.Errorf("git push: %w", err)
}
return nil