Repository: actions/stale (ts)

Issue:
Stale label not being added
Stale label not being added at all in our repo. To give a specific example, let's take https://github.com/WeblateOrg/weblate/issues/4746

On the [last nightly run](https://github.com/WeblateOrg/weblate/runs/1811488912), the log contains the following entries:

```
[#4746] Found issue: issue #4746 last updated 2021-01-06T08:51:34Z (is pr? false)
[#4746] Days before issue stale: 10
[#4746] This issue hasn't a stale label
```

So, the action sees the issue is old, gets correct stale days and sees that the label is not there. It just doesn't label it as stale.

Things most likely go wrong here:

https://github.com/actions/stale/blob/f71123a6f703377ddcfc8b5936ac224202592fc0/src/IssueProcessor.ts#L280

The question is how to figure out whether there is a bug in the action or there is something misconfigured on our side.

Pull request:
Fixed should be stale condition
When different stale period is used for issues and pull requests, this code uses wrong one.

This was probably missed in https://github.com/actions/stale/pull/224

Fixes #299

This is not tested at all, but I hope the fix is correct.

Patch:
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 0000000..992d27f
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,1 @@
+* @actions/actions-runtime
diff --git a/src/IssueProcessor.ts b/src/IssueProcessor.ts
index f1c2d93..f74260d 100644
--- a/src/IssueProcessor.ts
+++ b/src/IssueProcessor.ts
@@ -273,7 +273,7 @@ export class IssueProcessor {
       // should this issue be marked stale?
       const shouldBeStale = !IssueProcessor._updatedSince(
         issue.updated_at,
-        this.options.daysBeforeStale
+        daysBeforeStale
       );
 
       // determine if this issue needs to be marked stale first


Test patch:
diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index aad95e5..6fea323 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -2262,3 +2262,201 @@ test('a PR with an exempted milestone and with an exempted issue milestone will
   expect(processor.closedIssues.length).toStrictEqual(0);
   expect(processor.removedLabelIssues.length).toStrictEqual(0);
 });
+
+test('processing an issue opened since 2 days and with the option "daysBeforeIssueStale" at 3 will not make it stale', async () => {
+  expect.assertions(2);
+  const opts: IssueProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: 10,
+    daysBeforeIssueStale: 3
+  };
+  let issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'An issue with no label',
+      issueDate.toDateString(),
+    )
+  ];
+  const processor = new IssueProcessor(
+    opts,
+    async () => 'abot',
+    async p => (p == 1 ? TestIssueList : []),
+    async (num, dt) => [],
+    async (issue, label) => new Date().toDateString()
+  );
+  
+  // process our fake issue list
+  await processor.processIssues(1);
+  
+  expect(processor.staleIssues.length).toEqual(0);
+  expect(processor.closedIssues.length).toEqual(0);
+});
+
+test('processing an issue opened since 2 days and with the option "daysBeforeIssueStale" at 2 will make it stale', async () => {
+  expect.assertions(2);
+  const opts: IssueProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: 10,
+    daysBeforeIssueStale: 2
+  };
+  let issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'An issue with no label',
+      issueDate.toDateString(),
+    )
+  ];
+  const processor = new IssueProcessor(
+    opts,
+    async () => 'abot',
+    async p => (p == 1 ? TestIssueList : []),
+    async (num, dt) => [],
+    async (issue, label) => new Date().toDateString()
+  );
+  
+  // process our fake issue list
+  await processor.processIssues(1);
+  
+  expect(processor.staleIssues.length).toEqual(1);
+  expect(processor.closedIssues.length).toEqual(0);
+});
+
+test('processing an issue opened since 2 days and with the option "daysBeforeIssueStale" at 1 will make it stale', async () => {
+  expect.assertions(2);
+  const opts: IssueProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: 10,
+    daysBeforeIssueStale: 1
+  };
+  let issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'An issue with no label',
+      issueDate.toDateString(),
+    )
+  ];
+  const processor = new IssueProcessor(
+    opts,
+    async () => 'abot',
+    async p => (p == 1 ? TestIssueList : []),
+    async (num, dt) => [],
+    async (issue, label) => new Date().toDateString()
+  );
+  
+  // process our fake issue list
+  await processor.processIssues(1);
+  
+  expect(processor.staleIssues.length).toEqual(1);
+  expect(processor.closedIssues.length).toEqual(0);
+});
+
+test('processing a pull request opened since 2 days and with the option "daysBeforePrStale" at 3 will not make it stale', async () => {
+  expect.assertions(2);
+  const opts: IssueProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: 10,
+    daysBeforePrStale: 3
+  };
+  let issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'A pull request with no label',
+      issueDate.toDateString(),
+      issueDate.toDateString(),
+      true
+    )
+  ];
+  const processor = new IssueProcessor(
+    opts,
+    async () => 'abot',
+    async p => (p == 1 ? TestIssueList : []),
+    async (num, dt) => [],
+    async (issue, label) => new Date().toDateString()
+  );
+  
+  // process our fake issue list
+  await processor.processIssues(1);
+  
+  expect(processor.staleIssues.length).toEqual(0);
+  expect(processor.closedIssues.length).toEqual(0);
+});
+
+test('processing a pull request opened since 2 days and with the option "daysBeforePrStale" at 2 will make it stale', async () => {
+  expect.assertions(2);
+  const opts: IssueProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: 10,
+    daysBeforePrStale: 2
+  };
+  let issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'A pull request with no label',
+      issueDate.toDateString(),
+      issueDate.toDateString(),
+      true
+    )
+  ];
+  const processor = new IssueProcessor(
+    opts,
+    async () => 'abot',
+    async p => (p == 1 ? TestIssueList : []),
+    async (num, dt) => [],
+    async (issue, label) => new Date().toDateString()
+  );
+  
+  // process our fake issue list
+  await processor.processIssues(1);
+  
+  expect(processor.staleIssues.length).toEqual(1);
+  expect(processor.closedIssues.length).toEqual(0);
+});
+
+test('processing a pull request opened since 2 days and with the option "daysBeforePrStale" at 1 will make it stale', async () => {
+  expect.assertions(2);
+  const opts: IssueProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: 10,
+    daysBeforePrStale: 1
+  };
+  let issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'A pull request with no label',
+      issueDate.toDateString(),
+      issueDate.toDateString(),
+      true
+    )
+  ];
+  const processor = new IssueProcessor(
+    opts,
+    async () => 'abot',
+    async p => (p == 1 ? TestIssueList : []),
+    async (num, dt) => [],
+    async (issue, label) => new Date().toDateString()
+  );
+  
+  // process our fake issue list
+  await processor.processIssues(1);
+  
+  expect(processor.staleIssues.length).toEqual(1);
+  expect(processor.closedIssues.length).toEqual(0);
+});