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

AJGranowski / preceding-tag-action / 25260058069

02 May 2026 07:32PM UTC coverage: 93.324% (-0.4%) from 93.711%
25260058069

Pull #77

github

AJGranowski
Create cache directory in loadCache
Pull Request #77: Add request cache

172 of 183 branches covered (93.99%)

Branch coverage included in aggregate %.

165 of 178 new or added lines in 4 files covered. (92.7%)

4 existing lines in 2 files now uncovered.

485 of 521 relevant lines covered (93.09%)

12.17 hits per line

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

97.47
/src/Input.ts
1
import type { getBooleanInput, getInput, warning } from "@actions/core";
2
import type { context } from "@actions/github";
3

4
import type { Repository } from "./types/Repository";
5

6
type Core_getBooleanInput = typeof getBooleanInput;
7
type Core_getInput = typeof getInput;
8
type Core_warning = typeof warning;
9
type Github_context = typeof context;
10

11
type MemoizationTable = {
12
    [key in keyof Input]?: key extends `get${string}` ? ReturnType<Input[key]> : never
13
}
14

15
class Input {
1✔
16
    private readonly context: Github_context;
1✔
17
    private readonly getBooleanInput: Core_getBooleanInput;
21✔
18
    private readonly getInput: Core_getInput;
21✔
19
    private readonly warning: Core_warning;
21✔
20

21
    private readonly memoization: MemoizationTable;
21✔
22

23
    constructor(getInput: Core_getInput, getBooleanInput: Core_getBooleanInput, warning: Core_warning, context: Github_context) {
1✔
24
        this.context = context;
21✔
25
        this.getBooleanInput = getBooleanInput;
21✔
26
        this.getInput = getInput;
21✔
27
        this.warning = warning;
21✔
28

29
        this.memoization = {};
21✔
30
    }
21✔
31

32
    /**
33
     * Validate each input.
34
     */
35
    validateInputs(): void {
1✔
36
        this.getDefaultTag();
6✔
37
        this.getFilter();
6✔
38
        this.getIncludeRef();
6✔
39
        this.getRef();
6✔
40
        this.getRepository();
6✔
41
        this.getToken();
6✔
42
    }
6✔
43

44
    /**
45
     * The default value to return if no preceding tag was found.
46
     */
47
    getDefaultTag(): string {
1✔
48
        if (this.memoization.getDefaultTag != null) {
13✔
49
            return this.memoization.getDefaultTag;
4✔
50
        }
4✔
51

52
        const defaultTag = this.getInput("default-tag");
9✔
53
        if (defaultTag.length !== 0 && !this.getFilter()(defaultTag)) {
13✔
54
            this.warning(`Input default-tag "${defaultTag}" does not match the tag filter.`);
1✔
55
        }
1✔
56

57
        this.memoization.getDefaultTag = defaultTag;
9✔
58
        return defaultTag;
9✔
59
    }
13✔
60

61
    /**
62
     * Get the tag filtering regular expression, defaults to matching every non-zero string.
63
     */
64
    getFilter(): (string: string) => boolean {
1✔
65
        if (this.memoization.getFilter != null) {
14✔
66
            return this.memoization.getFilter;
5✔
67
        }
5✔
68

69
        const filterString = this.getInput("regex");
9✔
70
        if (filterString.length === 0) {
14✔
71
            this.memoization.getFilter = (string: string): boolean => string.length > 0;
8✔
72
        } else {
14✔
73
            const regex = new RegExp(filterString);
1✔
74
            this.memoization.getFilter = regex.test.bind(regex);
1✔
75
        }
1✔
76

77
        return this.memoization.getFilter;
9✔
78
    }
14✔
79

80
    /**
81
     * Return the include-ref option, defaults to false.
82
     */
83
    getIncludeRef(): boolean {
1✔
84
        if (this.memoization.getIncludeRef != null) {
11✔
85
            return this.memoization.getIncludeRef;
4✔
86
        }
4✔
87

88
        if (this.getInput("include-ref").length === 0) {
8✔
89
            this.memoization.getIncludeRef = false;
6✔
90
        } else {
11✔
91
            this.memoization.getIncludeRef = this.getBooleanInput("include-ref");
1✔
92
        }
1✔
93

94
        return this.memoization.getIncludeRef;
7✔
95
    }
11✔
96

97
    /**
98
     * Get the ref to get the preceding tag of. Defaults to HEAD if not supplied for some reason.
99
     */
100
    getRef(): string {
1✔
101
        if (this.memoization.getRef != null) {
22✔
102
            return this.memoization.getRef;
10✔
103
        }
10✔
104

105
        const startsWithRef = /^refs\//i;
12✔
106
        const invalidGitSequences = /(\.\/)|(\.\.)|(\.lock$)|[~^:?*[@\\]|(\/\/)|(\.$)/;
12✔
107
        const invalidURLSequences = /[?&/$%]|(^\.)|(\.$)/;
12✔
108
        const ref = this.getInput("ref");
12✔
109
        if (startsWithRef.test(ref) || invalidGitSequences.test(ref) || invalidURLSequences.test(ref)) {
22✔
110
            throw new SyntaxError(`Invalid input ref "${ref}"`);
5✔
111
        }
5✔
112

113
        this.memoization.getRef = ref.length > 0 ? ref : "HEAD";
22!
114
        return this.memoization.getRef;
22✔
115
    }
22✔
116

117
    /**
118
     * Generate a Repository object, either from the action inputs or the context this action is running in.
119
     */
120
    getRepository(): Repository {
1✔
121
        if (this.memoization.getRepository != null) {
22✔
122
            return this.memoization.getRepository;
9✔
123
        }
9✔
124

125
        const validRepositoryString = /^[a-z\d-]+\/[\w.-]+$/i;
13✔
126
        const invalidRepositorySequences = /(\/\.)|(\/\.\.)/;
13✔
127
        const inputString = this.getInput("repository");
13✔
128
        if (inputString.length === 0) {
22✔
129
            this.memoization.getRepository = {
6✔
130
                owner: this.context.repo.owner,
6✔
131
                repo: this.context.repo.repo
6✔
132
            };
6✔
133

134
            return this.memoization.getRepository;
6✔
135
        }
6✔
136

137
        const matcher = inputString.match(/^(?<owner>[^/]+)\/(?<repo>[^/]+)$/);
7✔
138
        if (!validRepositoryString.test(inputString) || invalidRepositorySequences.test(inputString) || matcher == null || matcher.groups == null) {
22✔
139
            throw new SyntaxError(`Invalid input repository "${inputString}". Expected format {owner}/{repo}`);
4✔
140
        }
4✔
141

142
        this.memoization.getRepository = {
3✔
143
            owner: matcher.groups.owner,
3✔
144
            repo: matcher.groups.repo
3✔
145
        };
3✔
146

147
        return this.memoization.getRepository;
3✔
148
    }
22✔
149

150
    /**
151
     * Return the token if it exists, or undefined.
152
     */
153
    getToken(): string | undefined {
1✔
154
        if ("getToken" in this.memoization) {
16✔
155
            return this.memoization.getToken;
9✔
156
        }
9✔
157

158
        const token = this.getInput("token");
7✔
159
        if (token.length === 0) {
7✔
160
            this.memoization.getToken = undefined;
7✔
161
        } else {
16!
UNCOV
162
            this.memoization.getToken = token;
×
UNCOV
163
        }
✔
164

165
        return this.memoization.getToken;
7✔
166
    }
16✔
167
}
1✔
168

169
export { Input };
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