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

AJGranowski / preceding-tag-action / 17601988154

10 Sep 2025 03:10AM UTC coverage: 10.502% (+1.0%) from 9.524%
17601988154

push

github

web-flow
Add `include-ref` option (#14)

5 of 8 branches covered (62.5%)

Branch coverage included in aggregate %.

9 of 39 new or added lines in 3 files covered. (23.08%)

1 existing line in 1 file now uncovered.

18 of 211 relevant lines covered (8.53%)

0.09 hits per line

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

24.36
/src/fetchPrecedingTag.ts
1
import type { GitHubAPI } from "./GitHubAPI";
2

3
interface TagDifference {
4
    tags: string[]
5
    commitDifference: number
6
}
7

8
type GitRef = string;
9
interface Options {
10
    filter?: RegExp;
11
    includeRef?: boolean;
12
}
13

14
/**
15
 * This function finds the most recent tag that is reachable from a commit.
16
 * Functions similarly to git-describe using GitHub endpoints instead of a local git database.
17
 * If multiple tags are the same distance away, this function returns the most recent tag (by committer date, then author date).
18
 * If no tags are reachable from this commit, this function returns null.
19
 *
20
 * Will reject if the API is unavailable, or if the reference does not exist.
21
 */
22
async function fetchPrecedingTag(githubAPI: GitHubAPI, head: GitRef, options?: Options): Promise<string | null> {
1✔
23
    const optionsWithDefaults = {
1✔
24
        filter: /^.+$/,
1✔
25
        includeRef: false,
1✔
26
        ...options
1✔
27
    } satisfies Required<Options>;
1✔
28

29
    const allTags = await githubAPI.fetchAllTags(optionsWithDefaults.filter);
1✔
30
    const tagDistances = await Promise.all(allTags.map(async (tag) => {
1✔
31
        return {
×
32
            tags: [tag],
×
33
            commitDifference: await githubAPI.fetchCommitDifference(tag, head)
×
34
        };
×
35
    }));
1✔
36

37
    const precedingTag = tagDistances
1✔
38
        .filter((x) => {
1✔
NEW
39
            if (isNaN(x.commitDifference)) {
×
NEW
40
                return false;
×
NEW
41
            }
×
42

NEW
43
            if (optionsWithDefaults.includeRef) {
×
NEW
44
                return x.commitDifference >= 0;
×
NEW
45
            }
×
46

NEW
47
            return x.commitDifference > 0;
×
48
        })
1✔
49
        .reduce((prev: TagDifference | null, next: TagDifference) => {
1✔
50
            if (prev == null) {
×
51
                return next;
×
52
            }
×
53

54
            const nextMinusPrev = Math.abs(next.commitDifference) - Math.abs(prev.commitDifference);
×
55
            if (nextMinusPrev < 0) {
×
56
                return next;
×
57
            } else if (nextMinusPrev > 0) {
×
58
                return prev;
×
59
            }
×
60

61
            return {
×
62
                tags: prev.tags.concat(next.tags),
×
63
                commitDifference: prev.commitDifference
×
64
            };
×
65
        }, null);
1✔
66

67
    if (precedingTag == null || precedingTag.tags.length === 0) {
1!
68
        return null;
1✔
69
    } else if (precedingTag.tags.length === 1) {
1!
70
        return precedingTag.tags[0];
×
71
    }
×
72

73
    const commitDates = await Promise.all(precedingTag.tags.map(async (tag) => {
×
74
        return {
×
75
            tag: tag,
×
76
            commitDate: await githubAPI.fetchCommitDate(tag)
×
77
        };
×
78
    }));
×
79

80
    return commitDates.reduce((prev, next) => {
×
81
        let compareNextPrev = nullableDateComparator(next.commitDate.committer, prev.commitDate.committer);
×
82
        if (compareNextPrev > 0) {
×
83
            return next;
×
84
        } else if (compareNextPrev < 0) {
×
85
            return prev;
×
86
        }
×
87

88
        compareNextPrev = nullableDateComparator(next.commitDate.author, prev.commitDate.author);
×
89

90
        if (compareNextPrev > 0) {
×
91
            return next;
×
92
        } else if (compareNextPrev < 0) {
×
93
            return prev;
×
94
        }
×
95

96
        return prev;
×
97
    }).tag;
×
98
}
×
99

100
/**
101
 * Simple date comparator, but asserts null is less than any date.
102
 */
103
const nullableDateComparator = (a: string | null | undefined, b: string | null | undefined): number => {
1✔
104
    if (a != null && b != null) {
×
105
        return (new Date(a)).getTime() - (new Date(b)).getTime();
×
106
    } else if (a == null && b != null) {
×
107
        return -1;
×
108
    } else if (a != null && b == null) {
×
109
        return 1;
×
110
    }
×
111

112
    return 0;
×
113
};
×
114

115
export { fetchPrecedingTag };
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