Skip to content

Commit 8699d85

Browse files
authored
Merge pull request cli#11491 from cli/andyfeller/10716-project-featuredetection-api-version
Report that v1 classic projects are detected on GHES 3.16.x or older
2 parents dd26fba + d102512 commit 8699d85

2 files changed

Lines changed: 90 additions & 14 deletions

File tree

internal/featuredetection/feature_detection.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/cli/cli/v2/api"
77
"github.com/cli/cli/v2/internal/gh"
8+
"github.com/hashicorp/go-version"
89
"golang.org/x/sync/errgroup"
910

1011
ghauth "github.com/cli/go-gh/v2/pkg/auth"
@@ -205,12 +206,35 @@ func (d *detector) RepositoryFeatures() (RepositoryFeatures, error) {
205206
return features, nil
206207
}
207208

209+
const (
210+
enterpriseProjectsV1Removed = "3.17.0"
211+
)
212+
208213
func (d *detector) ProjectsV1() gh.ProjectsV1Support {
209-
// Currently, projects v1 support is entirely dependent on the host. As this is deprecated in GHES,
210-
// we will do feature detection on whether the GHES version has support.
211-
if ghauth.IsEnterprise(d.host) {
214+
if !ghauth.IsEnterprise(d.host) {
215+
return gh.ProjectsV1Unsupported
216+
}
217+
218+
hostVersion, hostVersionErr := resolveEnterpriseVersion(d.httpClient, d.host)
219+
v1ProjectCutoffVersion, v1ProjectCutoffVersionErr := version.NewVersion(enterpriseProjectsV1Removed)
220+
221+
if hostVersionErr == nil && v1ProjectCutoffVersionErr == nil && hostVersion.LessThan(v1ProjectCutoffVersion) {
212222
return gh.ProjectsV1Supported
213223
}
214224

215225
return gh.ProjectsV1Unsupported
216226
}
227+
228+
func resolveEnterpriseVersion(httpClient *http.Client, host string) (*version.Version, error) {
229+
var metaResponse struct {
230+
InstalledVersion string `json:"installed_version"`
231+
}
232+
233+
apiClient := api.NewClientFromHTTP(httpClient)
234+
err := apiClient.REST(host, "GET", "meta", nil, &metaResponse)
235+
if err != nil {
236+
return nil, err
237+
}
238+
239+
return version.NewVersion(metaResponse.InstalledVersion)
240+
}

internal/featuredetection/feature_detection_test.go

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -373,17 +373,69 @@ func TestRepositoryFeatures(t *testing.T) {
373373
}
374374

375375
func TestProjectV1Support(t *testing.T) {
376-
t.Parallel()
376+
tests := []struct {
377+
name string
378+
hostname string
379+
httpStubs func(*httpmock.Registry)
380+
wantFeatures gh.ProjectsV1Support
381+
}{
382+
{
383+
name: "github.com",
384+
hostname: "github.com",
385+
wantFeatures: gh.ProjectsV1Unsupported,
386+
},
387+
{
388+
name: "ghec data residency (ghe.com)",
389+
hostname: "stampname.ghe.com",
390+
wantFeatures: gh.ProjectsV1Unsupported,
391+
},
392+
{
393+
name: "GHE 3.16.0",
394+
hostname: "git.my.org",
395+
httpStubs: func(reg *httpmock.Registry) {
396+
reg.Register(
397+
httpmock.REST("GET", "api/v3/meta"),
398+
httpmock.StringResponse(`{"installed_version":"3.16.0"}`),
399+
)
400+
},
401+
wantFeatures: gh.ProjectsV1Supported,
402+
},
403+
{
404+
name: "GHE 3.16.1",
405+
hostname: "git.my.org",
406+
httpStubs: func(reg *httpmock.Registry) {
407+
reg.Register(
408+
httpmock.REST("GET", "api/v3/meta"),
409+
httpmock.StringResponse(`{"installed_version":"3.16.1"}`),
410+
)
411+
},
412+
wantFeatures: gh.ProjectsV1Supported,
413+
},
414+
{
415+
name: "GHE 3.17",
416+
hostname: "git.my.org",
417+
httpStubs: func(reg *httpmock.Registry) {
418+
reg.Register(
419+
httpmock.REST("GET", "api/v3/meta"),
420+
httpmock.StringResponse(`{"installed_version":"3.17.0"}`),
421+
)
422+
},
423+
wantFeatures: gh.ProjectsV1Unsupported,
424+
},
425+
}
377426

378-
t.Run("when the host is enterprise, project v1 is supported", func(t *testing.T) {
379-
detector := detector{host: "my.ghes.com"}
380-
isProjectV1Supported := detector.ProjectsV1()
381-
require.Equal(t, gh.ProjectsV1Supported, isProjectV1Supported)
382-
})
427+
for _, tt := range tests {
428+
t.Run(tt.name, func(t *testing.T) {
429+
t.Parallel()
430+
reg := &httpmock.Registry{}
431+
if tt.httpStubs != nil {
432+
tt.httpStubs(reg)
433+
}
434+
httpClient := &http.Client{}
435+
httpmock.ReplaceTripper(httpClient, reg)
383436

384-
t.Run("when the host is not enterprise, project v1 is not supported", func(t *testing.T) {
385-
detector := detector{host: "github.com"}
386-
isProjectV1Supported := detector.ProjectsV1()
387-
require.Equal(t, gh.ProjectsV1Unsupported, isProjectV1Supported)
388-
})
437+
detector := NewDetector(httpClient, tt.hostname)
438+
require.Equal(t, tt.wantFeatures, detector.ProjectsV1())
439+
})
440+
}
389441
}

0 commit comments

Comments
 (0)