diff --git a/lib/stale.js b/lib/stale.js index 786a93d..ac45b83 100644 --- a/lib/stale.js +++ b/lib/stale.js @@ -62,7 +62,7 @@ module.exports = class Stale { } } - getStale (type) { + async getStale (type) { const onlyLabels = this.getConfigValue(type, 'onlyLabels') const staleLabel = this.getConfigValue(type, 'staleLabel') const exemptLabels = this.getConfigValue(type, 'exemptLabels') @@ -80,7 +80,68 @@ module.exports = class Stale { const query = queryParts.join(' ') const days = this.getConfigValue(type, 'days') || this.getConfigValue(type, 'daysUntilStale') - return this.search(type, days, query) + const results = await this.search(type, days, query) + + const pinned = await this.getPinnedNumbers(type) + const nonPinned = results.data.items.filter(issue => pinned.includes(issue.number)) + return { + ...results, + data: { + ...results.data, + total_count: nonPinned.length, + items: nonPinned, + } + } + } + + async getPinnedNumbers(type) { + if (type === 'pulls') { + // Pull Requests cannot be pinned + return [] + } else if (type !== 'issues') { + throw new Error(`Unknown type: ${type}. Valid types are 'pulls' and 'issues'`) + } + + const { owner, repo } = this.config + + try { + // GitHub's v3 REST API doesn't support Pinned Issues; v4 GraphQL API does + const {data, errors} = await this.github.graphql( + ` + query Issues($owner: String!, $repo: String!) { + repository(owner: $owner, name: $repo) { + pinnedIssues(first: 100) { + nodes { + number + } + pageInfo { + # This should always be false, as only 3 issues can be pinned at the same time + hasNextPage + } + } + } + } + `, + { + owner, + repo, + headers: { + // Opt-in to Pinned Issues API preview + accept: 'application/vnd.github.elektra-preview+json' + }, + }, + ) + + if (errors && errors.length) { + throw new Error(errors[0].message) + } + + return data.repository.pinnedIssues.nodes.map(issue => issue.number) + } catch (error) { + this.logger.error(`Encountered an error while excluding pinned items for ${owner}/${repo}: ${error}`) + // In the event of an error, proceed as if no pinned issues found + return [] + } } getClosable (type) { diff --git a/test/stale.test.js b/test/stale.test.js index 40d2a9b..50ce87e 100644 --- a/test/stale.test.js +++ b/test/stale.test.js @@ -195,4 +195,12 @@ describe('stale', () => { expect(stale.getClosable).not.toHaveBeenCalled() } ) + + test('should ignore pinned issues', () => { + expect('Test implementation pending').toStrictEqual('Test implemented') + }) + + test('should log, but ignore errors fetching pinned issues', () => { + expect('Test implementation pending').toStrictEqual('Test implemented') + }) })