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

kubernetes-sigs / kubebuilder / 17197426363

25 Aug 2025 02:29AM UTC coverage: 65.092% (-5.0%) from 70.093%
17197426363

push

github

web-flow
Merge pull request #5040 from camilamacedo86/add-gh-model

✨ (alpha update) Add Option to use AI with alpha update

53 of 414 new or added lines in 4 files covered. (12.8%)

1 existing line in 1 file now uncovered.

3196 of 4910 relevant lines covered (65.09%)

12.62 hits per line

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

53.33
/pkg/cli/alpha/internal/update/validate.go
1
/*
2
Copyright 2025 The Kubernetes Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package update
18

19
import (
20
        "fmt"
21
        log "log/slog"
22
        "net/http"
23
        "os"
24
        "os/exec"
25
        "strings"
26

27
        "golang.org/x/mod/semver"
28

29
        "sigs.k8s.io/kubebuilder/v4/pkg/cli/alpha/internal/update/helpers"
30
)
31

32
// Validate checks the input info provided for the update and populates the cliVersion
33
func (opts *Update) Validate() error {
2✔
34
        if err := opts.validateEqualVersions(); err != nil {
2✔
35
                return fmt.Errorf("failed to validate equal versions: %w", err)
×
36
        }
×
37
        if err := opts.validateGitRepo(); err != nil {
3✔
38
                return fmt.Errorf("failed to validate git repository: %w", err)
1✔
39
        }
1✔
40
        if err := opts.validateFromBranch(); err != nil {
1✔
41
                return fmt.Errorf("failed to validate --from-branch: %w", err)
×
42
        }
×
43
        if err := opts.validateSemanticVersions(); err != nil {
1✔
44
                return fmt.Errorf("failed to validate the versions: %w", err)
×
45
        }
×
46
        if err := validateReleaseAvailability(opts.FromVersion); err != nil {
1✔
47
                return fmt.Errorf("unable to find release %s: %w", opts.FromVersion, err)
×
48
        }
×
49
        if err := validateReleaseAvailability(opts.ToVersion); err != nil {
1✔
50
                return fmt.Errorf("unable to find release %s: %w", opts.ToVersion, err)
×
51
        }
×
52

53
        if opts.OpenGhIssue {
1✔
54
                if err := exec.Command("gh", "--version").Run(); err != nil {
×
55
                        return fmt.Errorf("`gh` CLI not found or not authenticated. "+
×
56
                                "You must have gh instaled to use the --open-gh-issue option: %s", err)
×
57
                }
×
58
        }
59

60
        if opts.UseGhModels && !isGhModelsExtensionInstalled() {
1✔
NEW
61
                return fmt.Errorf("gh-models extension is not installed. To install the extension, run: " +
×
NEW
62
                        "gh extension install https://github.com/github/gh-models")
×
NEW
63
        }
×
64

65
        return nil
1✔
66
}
67

68
// isGhModelsExtensionInstalled checks if the gh-models extension is installed
NEW
69
func isGhModelsExtensionInstalled() bool {
×
NEW
70
        cmd := exec.Command("gh", "extension", "list")
×
NEW
71
        if _, err := cmd.Output(); err != nil {
×
NEW
72
                return false
×
NEW
73
        }
×
NEW
74
        return true
×
75
}
76

77
// validateGitRepo verifies if the current directory is a valid Git repository and checks for uncommitted changes.
78
func (opts *Update) validateGitRepo() error {
4✔
79
        log.Info("Checking if is a git repository")
4✔
80
        gitCmd := exec.Command("git", "rev-parse", "--git-dir")
4✔
81
        if err := gitCmd.Run(); err != nil {
6✔
82
                return fmt.Errorf("not in a git repository")
2✔
83
        }
2✔
84

85
        log.Info("Checking if branch has uncommitted changes")
2✔
86
        gitCmd = exec.Command("git", "status", "--porcelain")
2✔
87
        output, err := gitCmd.Output()
2✔
88
        if err != nil {
2✔
89
                return fmt.Errorf("failed to check branch status: %w", err)
×
90
        }
×
91
        if len(strings.TrimSpace(string(output))) > 0 {
2✔
92
                return fmt.Errorf("working directory has uncommitted changes. " +
×
93
                        "Please commit or stash them before updating")
×
94
        }
×
95
        return nil
2✔
96
}
97

98
// validateFromBranch the branch passed to the --from-branch flag
99
func (opts *Update) validateFromBranch() error {
3✔
100
        // Check if the branch exists
3✔
101
        gitCmd := exec.Command("git", "rev-parse", "--verify", opts.FromBranch)
3✔
102
        if err := gitCmd.Run(); err != nil {
4✔
103
                return fmt.Errorf("%s branch does not exist locally. "+
1✔
104
                        "Run 'git branch -a' to see all available branches",
1✔
105
                        opts.FromBranch)
1✔
106
        }
1✔
107
        return nil
2✔
108
}
109

110
// validateSemanticVersions the version informed by the user via --from-version flag
111
func (opts *Update) validateSemanticVersions() error {
3✔
112
        if !semver.IsValid(opts.FromVersion) {
4✔
113
                return fmt.Errorf(" version informed (%s) has invalid semantic version. "+
1✔
114
                        "Expect: vX.Y.Z (Ex: v4.5.0)", opts.FromVersion)
1✔
115
        }
1✔
116
        if !semver.IsValid(opts.ToVersion) {
2✔
117
                return fmt.Errorf(" version informed (%s) has invalid semantic version. "+
×
118
                        "Expect: vX.Y.Z (Ex: v4.5.0)", opts.ToVersion)
×
119
        }
×
120
        return nil
2✔
121
}
122

123
// validateReleaseAvailability will verify if the binary to scaffold from-version flag is available
124
func validateReleaseAvailability(version string) error {
4✔
125
        url := helpers.BuildReleaseURL(version)
4✔
126
        resp, err := http.Head(url)
4✔
127
        if err != nil {
4✔
128
                return fmt.Errorf("failed to check binary availability: %w", err)
×
129
        }
×
130
        defer func() {
8✔
131
                if err = resp.Body.Close(); err != nil {
4✔
132
                        log.Error("failed to close connection", "error", err)
×
133
                }
×
134
        }()
135

136
        switch resp.StatusCode {
4✔
137
        case http.StatusOK:
3✔
138
                log.Info("Binary version available", "version", version)
3✔
139
                return nil
3✔
140
        case http.StatusNotFound:
×
141
                return fmt.Errorf("binary version %s not found. Check versions available in releases",
×
142
                        version)
×
143
        default:
1✔
144
                return fmt.Errorf("unexpected response %d when checking binary availability for version %s",
1✔
145
                        resp.StatusCode, version)
1✔
146
        }
147
}
148

149
// validateEqualVersions checks if from-version and to-version are the same.
150
// If they are equal, logs an appropriate message and exits successfully.
151
func (opts *Update) validateEqualVersions() error {
2✔
152
        if opts.FromVersion == opts.ToVersion {
2✔
153
                // Check if this is the latest version to provide appropriate message
×
154
                latestVersion, err := fetchLatestRelease()
×
155
                if err != nil {
×
156
                        return fmt.Errorf("failed to fetch latest release for messaging: %w", err)
×
157
                }
×
158

159
                if opts.ToVersion == latestVersion {
×
160
                        log.Info("Your project already uses the latest version. No action taken.", "version", opts.FromVersion)
×
161
                } else {
×
162
                        log.Info("Your project already uses the specified version. No action taken.", "version", opts.FromVersion)
×
163
                }
×
164
                os.Exit(0)
×
165
        }
166
        return nil
2✔
167
}
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