← 输入框|github.com|刷新
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/skills/installer/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func Install(opts *Options) (*Result, error) {
return nil, fmt.Errorf("failed to install skill %q: %w", skill.InstallName(), err)
}
var warnings []string
if err := lockfile.RecordInstall(skill.InstallName(), opts.Owner, opts.Repo, skill.Path+"/SKILL.md", skill.TreeSHA, opts.PinnedRef); err != nil {
if err := lockfile.RecordInstall(opts.Host, skill.InstallName(), opts.Owner, opts.Repo, skill.Path+"/SKILL.md", skill.TreeSHA, opts.PinnedRef); err != nil {
warnings = append(warnings, fmt.Sprintf("could not record install for %s: %v", skill.InstallName(), err))
}
return &Result{Installed: []string{skill.InstallName()}, Dir: targetDir, Warnings: warnings}, nil
Expand Down Expand Up @@ -129,7 +129,7 @@ func Install(opts *Options) (*Result, error) {
}
installed = append(installed, r.name)
skill := opts.Skills[i]
if err := lockfile.RecordInstall(skill.InstallName(), opts.Owner, opts.Repo, skill.Path+"/SKILL.md", skill.TreeSHA, opts.PinnedRef); err != nil {
if err := lockfile.RecordInstall(opts.Host, skill.InstallName(), opts.Owner, opts.Repo, skill.Path+"/SKILL.md", skill.TreeSHA, opts.PinnedRef); err != nil {
warnings = append(warnings, fmt.Sprintf("could not record install for %s: %v", skill.InstallName(), err))
}
}
Expand Down
5 changes: 3 additions & 2 deletions internal/skills/lockfile/lockfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/cli/cli/v2/internal/flock"
"github.com/cli/cli/v2/internal/ghinstance"
)

const (
Expand Down Expand Up @@ -93,7 +94,7 @@ func writeTo(f *os.File, lf *file) error {
// RecordInstall adds or updates a skill entry in the lock file.
// It uses a file-based lock to prevent concurrent read-modify-write races
// when multiple install processes run simultaneously.
func RecordInstall(skillName, owner, repo, skillPath, treeSHA, pinnedRef string) error {
func RecordInstall(host, skillName, owner, repo, skillPath, treeSHA, pinnedRef string) error {
lockPath, err := lockfilePath()
if err != nil {
return err
Expand Down Expand Up @@ -124,7 +125,7 @@ func RecordInstall(skillName, owner, repo, skillPath, treeSHA, pinnedRef string)
f.Skills[skillName] = entry{
Source: owner + "/" + repo,
SourceType: "github",
SourceURL: "https://github.com/" + owner + "/" + repo + ".git",
SourceURL: ghinstance.HostPrefix(host) + owner + "/" + repo + ".git",
SkillPath: skillPath,
SkillFolderHash: treeSHA,
InstalledAt: installedAt,
Expand Down
31 changes: 27 additions & 4 deletions internal/skills/lockfile/lockfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestRecordInstall(t *testing.T) {
tests := []struct {
name string
setup func(t *testing.T)
host string
skill string
owner string
repo string
Expand All @@ -35,6 +36,7 @@ func TestRecordInstall(t *testing.T) {
}{
{
name: "fresh install creates lockfile",
host: "github.com",
skill: "code-review",
owner: "monalisa",
repo: "octocat-skills",
Expand All @@ -55,8 +57,25 @@ func TestRecordInstall(t *testing.T) {
assert.Empty(t, e.PinnedRef)
},
},
{
name: "tenancy host uses correct URL",
host: "mycompany.ghe.com",
skill: "code-review",
owner: "monalisa",
repo: "octocat-skills",
skillPath: "skills/code-review/SKILL.md",
treeSHA: "abc123",
verify: func(t *testing.T, lockPath string) {
t.Helper()
f := readTestLockfile(t, lockPath)
require.Contains(t, f.Skills, "code-review")
e := f.Skills["code-review"]
assert.Equal(t, "https://mycompany.ghe.com/monalisa/octocat-skills.git", e.SourceURL)
},
},
{
name: "install with pinned ref",
host: "github.com",
skill: "pr-summary",
owner: "hubot",
repo: "skills-repo",
Expand All @@ -73,8 +92,9 @@ func TestRecordInstall(t *testing.T) {
name: "multiple skills coexist",
setup: func(t *testing.T) {
t.Helper()
require.NoError(t, RecordInstall("code-review", "monalisa", "octocat-skills", "skills/code-review/SKILL.md", "sha1", ""))
require.NoError(t, RecordInstall("github.com", "code-review", "monalisa", "octocat-skills", "skills/code-review/SKILL.md", "sha1", ""))
},
host: "github.com",
skill: "issue-triage",
owner: "monalisa",
repo: "octocat-skills",
Expand Down Expand Up @@ -107,6 +127,7 @@ func TestRecordInstall(t *testing.T) {
require.NoError(t, err)
t.Cleanup(unlock)
},
host: "github.com",
skill: "code-review",
owner: "monalisa",
repo: "octocat-skills",
Expand All @@ -123,6 +144,7 @@ func TestRecordInstall(t *testing.T) {
require.NoError(t, os.MkdirAll(filepath.Dir(lockPath), 0o755))
require.NoError(t, os.WriteFile(lockPath, []byte("{invalid json"), 0o644))
},
host: "github.com",
skill: "code-review",
owner: "monalisa",
repo: "octocat-skills",
Expand All @@ -145,6 +167,7 @@ func TestRecordInstall(t *testing.T) {
data, _ := json.Marshal(file{Version: 999, Skills: map[string]entry{"old-skill": {}}})
require.NoError(t, os.WriteFile(lockPath, data, 0o644))
},
host: "github.com",
skill: "code-review",
owner: "monalisa",
repo: "octocat-skills",
Expand All @@ -166,7 +189,7 @@ func TestRecordInstall(t *testing.T) {
tt.setup(t)
}

err := RecordInstall(tt.skill, tt.owner, tt.repo, tt.skillPath, tt.treeSHA, tt.pinnedRef)
err := RecordInstall(tt.host, tt.skill, tt.owner, tt.repo, tt.skillPath, tt.treeSHA, tt.pinnedRef)
if tt.wantErr {
require.Error(t, err)
return
Expand All @@ -181,10 +204,10 @@ func TestRecordInstall(t *testing.T) {
t.Run("update preserves InstalledAt and updates treeSHA", func(t *testing.T) {
lockPath := setupTestHome(t)

require.NoError(t, RecordInstall("code-review", "monalisa", "octocat-skills", "skills/code-review/SKILL.md", "old-sha", ""))
require.NoError(t, RecordInstall("github.com", "code-review", "monalisa", "octocat-skills", "skills/code-review/SKILL.md", "old-sha", ""))
firstInstalledAt := readTestLockfile(t, lockPath).Skills["code-review"].InstalledAt

require.NoError(t, RecordInstall("code-review", "monalisa", "octocat-skills", "skills/code-review/SKILL.md", "new-sha", ""))
require.NoError(t, RecordInstall("github.com", "code-review", "monalisa", "octocat-skills", "skills/code-review/SKILL.md", "new-sha", ""))
entry := readTestLockfile(t, lockPath).Skills["code-review"]

assert.Equal(t, "new-sha", entry.SkillFolderHash, "treeSHA should be updated")
Expand Down
15 changes: 11 additions & 4 deletions internal/skills/source/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"strings"

ghauth "github.com/cli/go-gh/v2/pkg/auth"

"github.com/cli/cli/v2/internal/ghrepo"
)

Expand Down Expand Up @@ -48,16 +50,21 @@ func ParseMetadataRepo(meta map[string]interface{}) (ghrepo.Interface, bool, err
return repo, true, nil
}

// ValidateSupportedHost rejects hosts that are not supported in public preview.
// ValidateSupportedHost rejects hosts that are not supported.
// Supported hosts are github.com and GHEC with data residency (*.ghe.com).
// GitHub Enterprise Server is not currently supported.
func ValidateSupportedHost(host string) error {
host = normalizeHost(host)
if host == "" {
return fmt.Errorf("could not determine repository host")
}
if host != SupportedHost {
return fmt.Errorf("GitHub Skills currently supports only %s as a host; got %s", SupportedHost, host)
if host == SupportedHost || ghauth.IsTenancy(host) {
return nil
}
if ghauth.IsEnterprise(host) {
return fmt.Errorf("GitHub Skills does not currently support GitHub Enterprise Server; got %s", host)
}
return nil
return fmt.Errorf("unsupported host for GitHub Skills: %s", host)
}

func normalizeHost(host string) string {
Expand Down
4 changes: 3 additions & 1 deletion internal/skills/source/source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,7 @@ func TestParseMetadataRepo(t *testing.T) {

func TestValidateSupportedHost(t *testing.T) {
require.NoError(t, ValidateSupportedHost("github.com"))
require.ErrorContains(t, ValidateSupportedHost("acme.ghes.com"), "supports only github.com")
require.NoError(t, ValidateSupportedHost("mycompany.ghe.com"), "GHEC data residency tenancy hosts should be accepted")
require.ErrorContains(t, ValidateSupportedHost("acme.ghes.com"), "does not currently support GitHub Enterprise Server")
require.ErrorContains(t, ValidateSupportedHost("github.localhost"), "unsupported host")
}
2 changes: 1 addition & 1 deletion pkg/cmd/skills/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ func TestInstallRun(t *testing.T) {
SkillName: "git-commit",
}
},
wantErr: "supports only github.com",
wantErr: "does not currently support GitHub Enterprise Server",
},
{
name: "select all skills in interactive prompt",
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/skills/preview/preview_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ func TestPreviewRun_UnsupportedHost(t *testing.T) {
repo: ghrepo.NewWithHost("github", "awesome-copilot", "acme.ghes.com"),
Telemetry: &telemetry.NoOpService{},
})
require.ErrorContains(t, err, "supports only github.com")
require.ErrorContains(t, err, "does not currently support GitHub Enterprise Server")
}

func TestPreviewRun_Interactive(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/skills/publish/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ func detectGitHubRemote(gitClient *git.Client, dir string) (*gitHubRemote, error
}

// parseGitHubURL extracts owner/repo from a GitHub remote URL.
// Only GitHub.com URLs are recognized.
// Only github.com and GHEC data residency (*.ghe.com) URLs are recognized.
func parseGitHubURL(rawURL string) (ghrepo.Interface, error) {
u, err := git.ParseURL(rawURL)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/skills/publish/publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestPublishRun_UnsupportedHost(t *testing.T) {
HttpClient: func() (*http.Client, error) { return nil, nil },
host: "acme.ghes.com",
})
require.ErrorContains(t, err, "supports only github.com")
require.ErrorContains(t, err, "does not currently support GitHub Enterprise Server")
}

func TestPublishRun(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/skills/search/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestSearchRun_UnsupportedHost(t *testing.T) {
HttpClient: func() (*http.Client, error) { return &http.Client{}, nil },
Config: func() (gh.Config, error) { return cfg, nil },
})
require.ErrorContains(t, err, "supports only github.com")
require.ErrorContains(t, err, "does not currently support GitHub Enterprise Server")
}

func TestNewCmdSearch(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/skills/update/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestScanInstalledSkills(t *testing.T) {
require.NoError(t, err)
require.Len(t, skills, 1)
require.Error(t, skills[0].metadataErr)
assert.Contains(t, skills[0].metadataErr.Error(), "supports only github.com")
assert.Contains(t, skills[0].metadataErr.Error(), "does not currently support GitHub Enterprise Server")
},
},
{
Expand Down
Loading