• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

astronomer / astro-cli / 716c27ab-af54-4fbb-904c-9fa0a6da08dc

26 May 2026 02:32PM UTC coverage: 44.676% (+5.0%) from 39.653%
716c27ab-af54-4fbb-904c-9fa0a6da08dc

push

circleci

web-flow
Migrate CLI to v1 public API; retire v1beta1 and v1alpha1 (except IDE) (#2093)

1848 of 18362 new or added lines in 58 files covered. (10.06%)

925 existing lines in 15 files now uncovered.

24957 of 55862 relevant lines covered (44.68%)

7.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

34.07
/pkg/git/git.go
1
package git
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "net/url"
7
        "os/exec"
8
        "strings"
9
)
10

11
const MaxCommitMessageLineLength = 72
12

13
// HasUncommittedChanges checks repository for uncommitted changes
14
func HasUncommittedChanges(path string) bool {
×
15
        if !IsGitRepository(path) {
×
16
                return false
×
17
        }
×
18

19
        _, err := runGitCommand(path, []string{"diff", "--quiet", "HEAD"})
×
20
        return err != nil
×
21
}
22

23
// IsGitRepository checks if current directory is a git repository
24
func IsGitRepository(path string) bool {
1✔
25
        _, err := runGitCommand(path, []string{"rev-parse", "--is-inside-working-tree"})
1✔
26
        return err == nil
1✔
27
}
1✔
28

29
func GetRemoteRepository(path, remote string) (*url.URL, error) {
×
NEW
30
        urlStr, err := GetRemoteURL(path, remote)
×
31
        if err != nil {
×
32
                return nil, err
×
33
        }
×
34
        return parseGitURL(urlStr)
×
35
}
36

37
// GetRemoteURL returns the raw remote URL string as configured by `git remote get-url`.
38
// This preserves the SCP-like form (e.g. git@github.com:astronomer/astro-cli) when present,
39
// which is what the v1 deploy API expects for GENERIC-provider remotes.
NEW
40
func GetRemoteURL(path, remote string) (string, error) {
×
NEW
41
        return runGitCommand(path, []string{"remote", "get-url", remote})
×
NEW
42
}
×
43

44
// ParseRemoteURL parses a raw remote URL into a *url.URL, handling SCP-like SSH URLs.
NEW
45
func ParseRemoteURL(urlStr string) (*url.URL, error) {
×
NEW
46
        return parseGitURL(urlStr)
×
NEW
47
}
×
48

49
func GetLocalRepositoryPathPrefix(path, dir string) (string, error) {
×
50
        path, err := runGitCommand(path, []string{"-C", dir, "rev-parse", "--show-prefix"})
×
51
        if err != nil {
×
52
                return "", err
×
53
        }
×
54
        return strings.TrimSuffix(path, "/"), nil
×
55
}
56

57
func GetBranch(path string) (string, error) {
×
58
        return runGitCommand(path, []string{"rev-parse", "--abbrev-ref", "HEAD"})
×
59
}
×
60

61
func GetHeadCommit(path string) (sha, message, name, email string, err error) {
×
62
        commitJSON, err := runGitCommand(path, []string{"log", "-1", `--pretty=format:{"sha":"%H","name":"%an","email":"%ae"}`, "HEAD"})
×
63
        if err != nil {
×
64
                return "", "", "", "", err
×
65
        }
×
66

67
        // parse the commit JSON
68
        // e.g. {"sha":"c1b4c1b...","name":"author name","email":"author email"}
69
        commit := struct {
×
70
                Sha   string `json:"sha"`
×
71
                Name  string `json:"name"`
×
72
                Email string `json:"email"`
×
73
        }{}
×
74
        err = json.Unmarshal([]byte(commitJSON), &commit)
×
75
        if err != nil {
×
76
                return "", "", "", "", err
×
77
        }
×
78

79
        // get the commit message, truncated to the first line with a max line length
80
        message, err = runGitCommand(path, []string{"log", "-1", "--pretty=%B", "HEAD"})
×
81
        if err != nil {
×
82
                return "", "", "", "", err
×
83
        }
×
84
        message = strings.Split(message, "\n")[0]
×
85
        if len(message) > MaxCommitMessageLineLength {
×
86
                message = message[:MaxCommitMessageLineLength]
×
87
        }
×
88

89
        return commit.Sha, message, commit.Name, commit.Email, nil
×
90
}
91

92
func runGitCommand(path string, args []string) (string, error) {
1✔
93
        if path != "" {
1✔
94
                args = append([]string{"-C", path}, args...)
×
95
        }
×
96
        out, err := exec.Command("git", args...).CombinedOutput()
1✔
97
        if err != nil {
1✔
98
                return "", err
×
99
        }
×
100
        return strings.TrimSpace(string(out)), nil
1✔
101
}
102

103
func parseGitURL(urlStr string) (*url.URL, error) {
7✔
104
        var parsedURL *url.URL
7✔
105
        var err error
7✔
106

7✔
107
        if strings.Contains(urlStr, "://") {
10✔
108
                parsedURL, err = url.Parse(urlStr)
3✔
109
                if err != nil {
3✔
110
                        return nil, err
×
111
                }
×
112
        } else {
4✔
113
                // if the URL is not a full URL, assume it is an "SCP-like" SSH URL
4✔
114
                // e.g. git@github.com:astronomer/astro-cli
4✔
115
                parts := strings.Split(urlStr, ":")
4✔
116
                if len(parts) != 2 {
4✔
117
                        return nil, fmt.Errorf("invalid Git URL: %s", urlStr)
×
118
                }
×
119
                userHost := strings.Split(parts[0], "@")
4✔
120
                if len(userHost) > 2 {
4✔
121
                        return nil, fmt.Errorf("invalid user@host format")
×
122
                }
×
123
                parsedURL = &url.URL{
4✔
124
                        Scheme: "ssh",
4✔
125
                        Host:   userHost[len(userHost)-1],
4✔
126
                        Path:   parts[1],
4✔
127
                }
4✔
128
        }
129

130
        parsedURL.Path = strings.TrimSuffix(parsedURL.Path, ".git")
7✔
131

7✔
132
        return parsedURL, nil
7✔
133
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc