diff --git a/README.md b/README.md index 4d95244e..54940c40 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # :calendar: GitHub Issue Due Dates Action -Add due dates to GitHub issues - issues are automatically tagged with labels when they pass certain date thresholds, as defined by you. +Add due dates to GitHub issues - issues are automatically tagged with `Overdue` and `Due in 1 week` labels. ## How it works: 1. Add the following snippet to the top of issues you'd like to assign due dates to: @@ -9,7 +9,7 @@ due: 2019-09-19 --- ``` 2. Create a `.github/workflows/workflow.yml` file with the following contents: -```yaml +``` name: Main Workflow on: schedule: @@ -23,30 +23,6 @@ jobs: uses: alexleventer/github-issue-due-dates-action@1.0.12 with: GH_TOKEN: "${{ secrets.GH_TOKEN }}" - OVERDUE_LABEL: OVERDUE! - INTERVALS: >- - - days: 30 - label: Due in 1 month - - days: 14 - label: Due in 2 weeks - - days: 7 - label: Due in 1 week - - days: 1 - label: DUE TOMORROW ``` 3. Generate a [personal access GitHub token](https://github.com/settings/tokens). 4. Add the following environment variable to your repository secrets: `GH_TOKEN={{your personal access token}}`. - -## Defining intervals - -Intervals are defined as a sequence (list) with a number of `days` and -a `label` to be set. - -You can define intervals and labels to meet your requirements; the -above is simply a guide. - -### Note the block syntax - -The value of the `INTERVALS` key must be interpreted as a string, -and must be a valid YAML block. Your action will fail if you do not -set the block indicator. diff --git a/__tests__/Octokit.test.ts b/__tests__/Octokit.test.ts index 8956e597..64c94344 100644 --- a/__tests__/Octokit.test.ts +++ b/__tests__/Octokit.test.ts @@ -21,19 +21,19 @@ describe('Octokit', () => { await gh.addLabelToIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, issues[1].number, ['Test']); const updatedIssue = await gh.get(TEST_REPO_AUTHOR, TEST_REPO_NAME, issues[1].number); expect(updatedIssue.labels.map(label => label.name).join(', ')).toContain('Test'); - await gh.removeLabelsFromIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, issues[1].number, ['Test']); + await gh.removeLabelFromIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, 'Test', issues[1].number); }); - it('should remove labels from issue without label', async () => { + it('should remove label from issue without label', async () => { const issues = await gh.listAllOpenIssues(TEST_REPO_AUTHOR, TEST_REPO_NAME); - const results = await gh.removeLabelsFromIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, issues[0].number, ['Test']); + const results = await gh.removeLabelFromIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, 'Test', issues[0].number); expect(results).toHaveLength(0); }); it('should remove label from issue with label', async () => { const issues = await gh.listAllOpenIssues(TEST_REPO_AUTHOR, TEST_REPO_NAME); await gh.addLabelToIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, issues[1].number, ['Test']); - const results = await gh.removeLabelsFromIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, issues[1].number, ['Test']); + const results = await gh.removeLabelFromIssue(TEST_REPO_AUTHOR, TEST_REPO_NAME, 'Test', issues[1].number); expect(results).toHaveLength(1); }); diff --git a/action.yml b/action.yml index 9ab0f048..d8a459c7 100644 --- a/action.yml +++ b/action.yml @@ -5,14 +5,6 @@ inputs: GH_TOKEN: description: GitHub token used to make API requests required: true - INTERVALS: - description: >- - A list containing a `label` to set when - the ticket is due in the specified `days` - required: true - OVERDUE_LABEL: - description: The label to set when an issue is overdue - required: false branding: icon: 'calendar' color: 'purple' diff --git a/package.json b/package.json index 3ace88f2..afb6500d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "main": "dist/app.js", - "version": "1.0.13", + "version": "1.0.12", "license": "MIT", "scripts": { "build": "tsc", @@ -19,8 +19,7 @@ "@actions/core": "^1.2.6", "@actions/github": "^4.0.0", "@slack/client": "^5.0.2", - "front-matter": "^4.0.2", - "moment": "^2.29.0", - "yaml": "^1.10.0" + "front-matter": "^3.1.0", + "moment": "^2.25.3" } } diff --git a/src/app.ts b/src/app.ts index 98da2f08..c04386f7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,60 +1,33 @@ import * as core from '@actions/core'; -import {GitHub, context} from '@actions/github'; +import {context} from '@actions/github'; import Octokit from './integrations/Octokit'; -import {datesToDue, byDays} from './utils/dateUtils'; -import YAML from 'yaml'; +import {datesToDue} from './utils/dateUtils'; +import {OVERDUE_TAG_NAME, NEXT_WEEK_TAG_NAME} from './constants'; export const run = async () => { try { const githubToken = core.getInput('GH_TOKEN'); - const inputIntervals = core.getInput('INTERVALS'); - const overdueLabel = core.getInput('OVERDUE_LABEL') || 'OVERDUE'; - if (!githubToken) { throw new Error('Missing GH_TOKEN environment variable'); } - if (!inputIntervals) { - throw new Error('Missing INTERVALS environment variable'); - } - const ok = new Octokit(githubToken); const issues = await ok.listAllOpenIssues(context.repo.owner, context.repo.repo); - console.log(`Found ${issues.length} open issue(s)`); - const results = await ok.getIssuesWithDueDate(issues); - console.log(`Found ${results.length} issue(s) with due dates`); - - const intervals = YAML.parse(inputIntervals).sort(byDays); - const intervalLabels = intervals.map(interval => interval.label); - console.log(`Found ${intervals.length} defined intervals`); - results.forEach(async issue => { - console.log(`Processing issue #${issue.number} with due date of ${issue.due}`); const daysUtilDueDate = await datesToDue(issue.due); - - if (daysUtilDueDate <= 0) { - await ok.removeLabelsFromIssue(context.repo.owner, context.repo.repo, issue.number, intervalLabels); - await ok.addLabelToIssue(context.repo.owner, context.repo.repo, issue.number, [overdueLabel]); - console.log(`Marked issue #${issue.number} as overdue`); - } else { - for (const interval of intervals) { - if (daysUtilDueDate <= interval.days) { - await ok.removeLabelsFromIssue(context.repo.owner, context.repo.repo, issue.number, intervalLabels); - await ok.addLabelToIssue(context.repo.owner, context.repo.repo, issue.number, [interval.label]); - console.log(`Marked issue #${issue.number} with label: ${interval.label}`); - break; // don't process any more intervals - } - } + if (daysUtilDueDate <= 7 && daysUtilDueDate > 0) { + await ok.addLabelToIssue(context.repo.owner, context.repo.repo, issue.number, [NEXT_WEEK_TAG_NAME]); + } else if (daysUtilDueDate <= 0) { + await ok.removeLabelFromIssue(context.repo.owner, context.repo.repo, NEXT_WEEK_TAG_NAME, issue.number); + await ok.addLabelToIssue(context.repo.owner, context.repo.repo, issue.number, [OVERDUE_TAG_NAME]); } }); - return { ok: true, issuesProcessed: results.length, } - } catch (e) { core.setFailed(e.message); throw e; diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 00000000..7162753e --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,2 @@ +export const OVERDUE_TAG_NAME = 'Overdue'; +export const NEXT_WEEK_TAG_NAME = 'Due in next week'; diff --git a/src/integrations/Octokit.ts b/src/integrations/Octokit.ts index 3bbecc2c..660c7db1 100644 --- a/src/integrations/Octokit.ts +++ b/src/integrations/Octokit.ts @@ -27,31 +27,29 @@ export default class Octokit { return data; } - async addLabelToIssue(owner: string, repo: string, issue_number: number, labels: string[]) { + async addLabelToIssue(owner: string, repo: string, issueNumber: number, labels: string[]) { const {data} = await this.client.issues.addLabels({ owner, repo, - issue_number, + issue_number: issueNumber, labels, }); return data; } - async removeLabelsFromIssue(owner: string, repo: string, issue_number: number, labels: string[]) { - labels.forEach(async label => { - try { - const {data} = await this.client.issues.removeLabel({ - owner, - repo, - issue_number, - label, - }); - return data; - } catch (e) { - // Do not throw error - return []; - } - }); + async removeLabelFromIssue(owner: string, repo: string, name: string, issue_number: number) { + try { + const {data} = await this.client.issues.removeLabel({ + owner, + repo, + name, + issue_number, + }); + return data; + } catch (e) { + // Do not throw error + return []; + } } async getIssuesWithDueDate(rawIssues: any[]) { diff --git a/src/utils/dateUtils.ts b/src/utils/dateUtils.ts index ce6e42fc..36cbd2eb 100644 --- a/src/utils/dateUtils.ts +++ b/src/utils/dateUtils.ts @@ -5,14 +5,3 @@ export const datesToDue = (date: string) => { const today = moment(); return eventDate.diff(today, 'days'); }; - -export const byDays = (a: any, b: any) => { - switch(true) { - case a.days < b.days: - return -1; - case a.days > b.days: - return 1; - default: - return 0; - } -};