Skip to content

Commit 40c105a

Browse files
MishaKavclaude
andauthored
Fix running in annotated git tag GitHub (#227)
* Fix: Handle annotated git tags in push events (#195) Resolves issue where the action failed when triggered by annotated tag pushes with error "No commit found for SHA". The problem occurred because payload.after contains the tag object's SHA for annotated tags, not the commit SHA. Changes: - Added resolveCommitSha() helper function to detect tag pushes and resolve annotated tag objects to their underlying commit SHA using GitHub's Git Data API - Initialize octokit early in main() to enable tag resolution before setting options.commit - Updated getChangedFiles() to use the resolved commit SHA from options - Gracefully handles both annotated tags (resolves to commit) and lightweight tags (already contain commit SHA) The fix ensures createCommitComment() receives a valid commit SHA regardless of whether the push event was triggered by a regular commit, lightweight tag, or annotated tag. * chore: update octokit API calls for @actions/github v6 compatibility Add .rest namespace to all octokit API calls to support @actions/github v6. This change is required before merging PR #229 (dependency updates). Changes: - Updated 7 octokit method calls to use .rest namespace - Rebuilt bundled action with updated code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update CHANGELOG for version 1.1.58, including fixes for annotated git tags in push events, dependency updates for @actions/github, and resolution of security vulnerabilities in Octokit dependencies. * 1.1.58 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7eb6504 commit 40c105a

5 files changed

Lines changed: 131 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog of the Pytest Coverage Comment
22

3+
## [Pytest Coverage Comment 1.1.58](https://github.com/MishaKav/pytest-coverage-comment/tree/v1.1.58)
4+
5+
**Release Date:** 2025-11-08
6+
7+
#### Changes
8+
9+
- fix handling of annotated git tags in push events (#195)
10+
- update `@actions/github` from v4.0.0 to v6.0.1 (#229)
11+
- fix 3 security vulnerabilities in Octokit dependencies
12+
313
## [Pytest Coverage Comment 1.1.57](https://github.com/MishaKav/pytest-coverage-comment/tree/v1.1.57)
414

515
**Release Date:** 2025-08-30

dist/index.js

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18710,6 +18710,50 @@ const FILE_STATUSES = Object.freeze({
1871018710
RENAMED: 'renamed',
1871118711
});
1871218712

18713+
/**
18714+
* Resolves a potential tag object SHA to the underlying commit SHA.
18715+
* For annotated tags, GitHub's push event payload.after contains the tag object SHA,
18716+
* not the commit SHA. This function detects tag pushes and resolves them to commits.
18717+
*
18718+
* @param {object} octokit - GitHub API client
18719+
* @param {string} owner - Repository owner
18720+
* @param {string} repo - Repository name
18721+
* @param {string} sha - SHA to resolve (might be tag object or commit)
18722+
* @param {string} ref - Git ref (e.g., refs/tags/v1.0.0 or refs/heads/main)
18723+
* @returns {Promise<string>} - The commit SHA
18724+
*/
18725+
const resolveCommitSha = async (octokit, owner, repo, sha, ref) => {
18726+
// Check if this is a tag push
18727+
if (ref && ref.startsWith('refs/tags/')) {
18728+
try {
18729+
core.info(`Detected tag push: ${ref}`);
18730+
core.info(`Attempting to resolve SHA: ${sha}`);
18731+
18732+
// Try to get the tag object
18733+
const { data: tag } = await octokit.rest.git.getTag({
18734+
owner,
18735+
repo,
18736+
tag_sha: sha,
18737+
});
18738+
18739+
// If it's an annotated tag, it will have an object field pointing to the commit
18740+
if (tag && tag.object && tag.object.sha) {
18741+
core.info(`Resolved annotated tag to commit: ${tag.object.sha}`);
18742+
return tag.object.sha;
18743+
}
18744+
} catch (error) {
18745+
// If getTag fails, it might be a lightweight tag or direct commit
18746+
// In this case, the SHA is already a commit SHA
18747+
// prettier-ignore
18748+
core.info(`SHA is not an annotated tag object, using as commit SHA: ${sha}`);
18749+
core.debug(`Error details: ${error.message}`);
18750+
}
18751+
}
18752+
18753+
// Return original SHA if not a tag or if it's a lightweight tag
18754+
return sha;
18755+
};
18756+
1871318757
const truncateSummary = (content, maxLength) => {
1871418758
if (content.length <= maxLength) {
1871518759
return content;
@@ -18847,12 +18891,23 @@ const main = async () => {
1884718891
options.repoUrl =
1884818892
payload.repository?.html_url || `https://github.com/${options.repository}`;
1884918893

18894+
// Initialize octokit early so we can use it for tag resolution
18895+
const octokit = github.getOctokit(token);
18896+
1885018897
if (eventName === 'pull_request' || eventName === 'pull_request_target') {
1885118898
options.commit = payload.pull_request.head.sha;
1885218899
options.head = payload.pull_request.head.ref;
1885318900
options.base = payload.pull_request.base.ref;
1885418901
} else if (eventName === 'push') {
18855-
options.commit = payload.after;
18902+
// For annotated tags, payload.after contains the tag object SHA, not the commit SHA
18903+
// Resolve it to the actual commit SHA
18904+
options.commit = await resolveCommitSha(
18905+
octokit,
18906+
owner,
18907+
repo,
18908+
payload.after,
18909+
context.ref,
18910+
);
1885618911
options.head = context.ref;
1885718912
} else if (eventName === 'workflow_dispatch') {
1885818913
options.commit = context.sha;
@@ -18976,7 +19031,6 @@ const main = async () => {
1897619031
return;
1897719032
}
1897819033
const body = WATERMARK + finalHtml;
18979-
const octokit = github.getOctokit(token);
1898019034

1898119035
const issue_number = payload.pull_request
1898219036
? payload.pull_request.number
@@ -19075,7 +19129,9 @@ const getChangedFiles = async (options, pr_number) => {
1907519129
break;
1907619130
case 'push':
1907719131
base = payload.before;
19078-
head = payload.after;
19132+
// Use the resolved commit SHA from options instead of payload.after
19133+
// This handles annotated tags correctly
19134+
head = options.commit || payload.after;
1907919135
break;
1908019136
case 'workflow_run':
1908119137
case 'workflow_dispatch': {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pytest-coverage-comment",
3-
"version": "1.1.57",
3+
"version": "1.1.58",
44
"description": "Comments a pull request with the pytest code coverage badge, full report and tests summary",
55
"author": "Misha Kav",
66
"license": "MIT",

src/index.js

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,50 @@ const FILE_STATUSES = Object.freeze({
1818
RENAMED: 'renamed',
1919
});
2020

21+
/**
22+
* Resolves a potential tag object SHA to the underlying commit SHA.
23+
* For annotated tags, GitHub's push event payload.after contains the tag object SHA,
24+
* not the commit SHA. This function detects tag pushes and resolves them to commits.
25+
*
26+
* @param {object} octokit - GitHub API client
27+
* @param {string} owner - Repository owner
28+
* @param {string} repo - Repository name
29+
* @param {string} sha - SHA to resolve (might be tag object or commit)
30+
* @param {string} ref - Git ref (e.g., refs/tags/v1.0.0 or refs/heads/main)
31+
* @returns {Promise<string>} - The commit SHA
32+
*/
33+
const resolveCommitSha = async (octokit, owner, repo, sha, ref) => {
34+
// Check if this is a tag push
35+
if (ref && ref.startsWith('refs/tags/')) {
36+
try {
37+
core.info(`Detected tag push: ${ref}`);
38+
core.info(`Attempting to resolve SHA: ${sha}`);
39+
40+
// Try to get the tag object
41+
const { data: tag } = await octokit.rest.git.getTag({
42+
owner,
43+
repo,
44+
tag_sha: sha,
45+
});
46+
47+
// If it's an annotated tag, it will have an object field pointing to the commit
48+
if (tag && tag.object && tag.object.sha) {
49+
core.info(`Resolved annotated tag to commit: ${tag.object.sha}`);
50+
return tag.object.sha;
51+
}
52+
} catch (error) {
53+
// If getTag fails, it might be a lightweight tag or direct commit
54+
// In this case, the SHA is already a commit SHA
55+
// prettier-ignore
56+
core.info(`SHA is not an annotated tag object, using as commit SHA: ${sha}`);
57+
core.debug(`Error details: ${error.message}`);
58+
}
59+
}
60+
61+
// Return original SHA if not a tag or if it's a lightweight tag
62+
return sha;
63+
};
64+
2165
const truncateSummary = (content, maxLength) => {
2266
if (content.length <= maxLength) {
2367
return content;
@@ -155,12 +199,23 @@ const main = async () => {
155199
options.repoUrl =
156200
payload.repository?.html_url || `https://github.com/${options.repository}`;
157201

202+
// Initialize octokit early so we can use it for tag resolution
203+
const octokit = github.getOctokit(token);
204+
158205
if (eventName === 'pull_request' || eventName === 'pull_request_target') {
159206
options.commit = payload.pull_request.head.sha;
160207
options.head = payload.pull_request.head.ref;
161208
options.base = payload.pull_request.base.ref;
162209
} else if (eventName === 'push') {
163-
options.commit = payload.after;
210+
// For annotated tags, payload.after contains the tag object SHA, not the commit SHA
211+
// Resolve it to the actual commit SHA
212+
options.commit = await resolveCommitSha(
213+
octokit,
214+
owner,
215+
repo,
216+
payload.after,
217+
context.ref,
218+
);
164219
options.head = context.ref;
165220
} else if (eventName === 'workflow_dispatch') {
166221
options.commit = context.sha;
@@ -284,7 +339,6 @@ const main = async () => {
284339
return;
285340
}
286341
const body = WATERMARK + finalHtml;
287-
const octokit = github.getOctokit(token);
288342

289343
const issue_number = payload.pull_request
290344
? payload.pull_request.number
@@ -383,7 +437,9 @@ const getChangedFiles = async (options, pr_number) => {
383437
break;
384438
case 'push':
385439
base = payload.before;
386-
head = payload.after;
440+
// Use the resolved commit SHA from options instead of payload.after
441+
// This handles annotated tags correctly
442+
head = options.commit || payload.after;
387443
break;
388444
case 'workflow_run':
389445
case 'workflow_dispatch': {

0 commit comments

Comments
 (0)