Skip to content

Commit 922e836

Browse files
committed
fix: handle lightweight tags in get_tag tool
Lightweight tags point directly to commits, not tag objects. The get_tag tool previously always called the Git Tag API which returns 404 for lightweight tags since their SHA references a commit, not a tag object. Now checks ref.Object.Type: if "commit" (lightweight), resolves the commit directly and returns a tag-like structure for consistency. If "tag" (annotated), proceeds with the existing tag object fetch.
1 parent c79439e commit 922e836

File tree

2 files changed

+109
-2
lines changed

2 files changed

+109
-2
lines changed

pkg/github/repositories.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,58 @@ func GetTag(t translations.TranslationHelperFunc) inventory.ServerTool {
15921592
return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to get tag reference", resp, body), nil, nil
15931593
}
15941594

1595-
// Then get the tag object
1595+
// Handle both annotated and lightweight tags.
1596+
// Annotated tags have ref.Object.Type == "tag" and point to a tag object.
1597+
// Lightweight tags have ref.Object.Type == "commit" and point directly to a commit.
1598+
if ref.Object.Type != nil && *ref.Object.Type == "commit" {
1599+
// Lightweight tag — resolve the commit directly
1600+
commit, resp, err := client.Git.GetCommit(ctx, owner, repo, *ref.Object.SHA)
1601+
if err != nil {
1602+
return ghErrors.NewGitHubAPIErrorResponse(ctx,
1603+
"failed to get commit for lightweight tag",
1604+
resp,
1605+
err,
1606+
), nil, nil
1607+
}
1608+
defer func() { _ = resp.Body.Close() }()
1609+
1610+
if resp.StatusCode != http.StatusOK {
1611+
body, err := io.ReadAll(resp.Body)
1612+
if err != nil {
1613+
return nil, nil, fmt.Errorf("failed to read response body: %w", err)
1614+
}
1615+
return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to get commit for lightweight tag", resp, body), nil, nil
1616+
}
1617+
1618+
// Return a tag-like structure for consistency
1619+
lightweightTag := &github.Tag{
1620+
SHA: ref.Object.SHA,
1621+
Tag: github.Ptr(tag),
1622+
Object: &github.GitObject{
1623+
Type: github.Ptr("commit"),
1624+
SHA: ref.Object.SHA,
1625+
},
1626+
}
1627+
if commit.Message != nil {
1628+
lightweightTag.Message = commit.Message
1629+
}
1630+
if commit.Author != nil {
1631+
lightweightTag.Tagger = &github.CommitAuthor{
1632+
Name: commit.Author.Name,
1633+
Email: commit.Author.Email,
1634+
Date: commit.Author.Date,
1635+
}
1636+
}
1637+
1638+
r, err := json.Marshal(lightweightTag)
1639+
if err != nil {
1640+
return nil, nil, fmt.Errorf("failed to marshal response: %w", err)
1641+
}
1642+
1643+
return utils.NewToolResultText(string(r)), nil, nil
1644+
}
1645+
1646+
// Annotated tag — fetch the tag object
15961647
tagObj, resp, err := client.Git.GetTag(ctx, owner, repo, *ref.Object.SHA)
15971648
if err != nil {
15981649
return ghErrors.NewGitHubAPIErrorResponse(ctx,

pkg/github/repositories_test.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2840,7 +2840,16 @@ func Test_GetTag(t *testing.T) {
28402840
mockTagRef := &github.Reference{
28412841
Ref: github.Ptr("refs/tags/v1.0.0"),
28422842
Object: &github.GitObject{
2843-
SHA: github.Ptr("v1.0.0-tag-sha"),
2843+
SHA: github.Ptr("v1.0.0-tag-sha"),
2844+
Type: github.Ptr("tag"),
2845+
},
2846+
}
2847+
2848+
mockLightweightTagRef := &github.Reference{
2849+
Ref: github.Ptr("refs/tags/v2.0.0"),
2850+
Object: &github.GitObject{
2851+
SHA: github.Ptr("lightweight-commit-sha"),
2852+
Type: github.Ptr("commit"),
28442853
},
28452854
}
28462855

@@ -2854,6 +2863,15 @@ func Test_GetTag(t *testing.T) {
28542863
},
28552864
}
28562865

2866+
mockCommit := &github.Commit{
2867+
SHA: github.Ptr("lightweight-commit-sha"),
2868+
Message: github.Ptr("Initial commit"),
2869+
Author: &github.CommitAuthor{
2870+
Name: github.Ptr("Test User"),
2871+
Email: github.Ptr("test@example.com"),
2872+
},
2873+
}
2874+
28572875
tests := []struct {
28582876
name string
28592877
mockedClient *http.Client
@@ -2892,6 +2910,44 @@ func Test_GetTag(t *testing.T) {
28922910
expectError: false,
28932911
expectedTag: mockTagObj,
28942912
},
2913+
{
2914+
name: "successful lightweight tag retrieval",
2915+
mockedClient: NewMockedHTTPClient(
2916+
WithRequestMatchHandler(
2917+
GetReposGitRefByOwnerByRepoByRef,
2918+
expectPath(
2919+
t,
2920+
"/repos/owner/repo/git/ref/tags/v2.0.0",
2921+
).andThen(
2922+
mockResponse(t, http.StatusOK, mockLightweightTagRef),
2923+
),
2924+
),
2925+
WithRequestMatchHandler(
2926+
GetReposGitCommitsByOwnerByRepoByCommitSHA,
2927+
expectPath(
2928+
t,
2929+
"/repos/owner/repo/git/commits/lightweight-commit-sha",
2930+
).andThen(
2931+
mockResponse(t, http.StatusOK, mockCommit),
2932+
),
2933+
),
2934+
),
2935+
requestArgs: map[string]any{
2936+
"owner": "owner",
2937+
"repo": "repo",
2938+
"tag": "v2.0.0",
2939+
},
2940+
expectError: false,
2941+
expectedTag: &github.Tag{
2942+
SHA: github.Ptr("lightweight-commit-sha"),
2943+
Tag: github.Ptr("v2.0.0"),
2944+
Message: github.Ptr("Initial commit"),
2945+
Object: &github.GitObject{
2946+
Type: github.Ptr("commit"),
2947+
SHA: github.Ptr("lightweight-commit-sha"),
2948+
},
2949+
},
2950+
},
28952951
{
28962952
name: "tag reference not found",
28972953
mockedClient: NewMockedHTTPClient(

0 commit comments

Comments
 (0)