From ea9445b74e87abe2f693883255448b1400b0c30c Mon Sep 17 00:00:00 2001
From: "Eray Erdin (&mut self)" <eraygezer.94@gmail.com>
Date: Mon, 26 Feb 2024 23:01:48 +0300
Subject: [PATCH] [GithubCreatedAt] Add Created At Badge for Github (#9981)

* init GithubCreatedAt service

* render raw created_at

* impl formatted date

* add color

* add test for absent repo

* add `reversed` parameter to `age` color formatter

* inverse the colors of the badge

---------

Co-authored-by: Studio <studio@192.168.1.20>
---
 services/color-formatters.js                 | 20 ++++----
 services/color-formatters.spec.js            | 24 +++++++--
 services/github/github-created-at.service.js | 54 ++++++++++++++++++++
 services/github/github-created-at.tester.js  | 14 +++++
 4 files changed, 99 insertions(+), 13 deletions(-)
 create mode 100644 services/github/github-created-at.service.js
 create mode 100644 services/github/github-created-at.tester.js

diff --git a/services/color-formatters.js b/services/color-formatters.js
index 0976343be8..f43b8a3f93 100644
--- a/services/color-formatters.js
+++ b/services/color-formatters.js
@@ -5,8 +5,8 @@
  * @module
  */
 
-import dayjs from 'dayjs'
 import pep440 from '@renovatebot/pep440'
+import dayjs from 'dayjs'
 
 /**
  * Determines the color used for a badge based on version.
@@ -175,24 +175,26 @@ function colorScale(steps, colors, reversed) {
 /**
  * Determines the color used for a badge according to the age.
  * Age is calculated as days elapsed till current date.
- * The color varies from bright green to red as the age increases.
+ * The color varies from bright green to red as the age increases
+ * or the other way around if `reverse` is given `true`.
  *
  * @param {string} date Date string
+ * @param {boolean} reversed Reverse the color scale a.k.a. the older, the better
  * @returns {string} Badge color
  */
-function age(date) {
-  const colorByAge = colorScale([7, 30, 180, 365, 730], undefined, true)
+function age(date, reversed = false) {
+  const colorByAge = colorScale([7, 30, 180, 365, 730], undefined, !reversed)
   const daysElapsed = dayjs().diff(dayjs(date), 'days')
   return colorByAge(daysElapsed)
 }
 
 export {
-  version,
-  pep440VersionColor,
-  downloadCount,
+  age,
+  colorScale,
   coveragePercentage,
+  downloadCount,
   floorCount,
   letterScore,
-  colorScale,
-  age,
+  pep440VersionColor,
+  version,
 }
diff --git a/services/color-formatters.spec.js b/services/color-formatters.spec.js
index c661acc864..39348a4288 100644
--- a/services/color-formatters.spec.js
+++ b/services/color-formatters.spec.js
@@ -1,12 +1,12 @@
-import { test, given, forCases } from 'sazerac'
 import { expect } from 'chai'
+import { forCases, given, test } from 'sazerac'
 import {
-  coveragePercentage,
+  age,
   colorScale,
+  coveragePercentage,
   letterScore,
-  age,
-  version,
   pep440VersionColor,
+  version,
 } from './color-formatters.js'
 
 describe('Color formatters', function () {
@@ -75,6 +75,22 @@ describe('Color formatters', function () {
     given(monthsAgo(15))
       .describe('when given a Date 15 months ago')
       .expect('orange')
+    // --- reversed --- //
+    given(Date.now(), true)
+      .describe('when given the current timestamp and reversed')
+      .expect('red')
+    given(new Date(), true)
+      .describe('when given the current Date and reversed')
+      .expect('red')
+    given(new Date(2001, 1, 1), true)
+      .describe('when given a Date many years ago and reversed')
+      .expect('brightgreen')
+    given(monthsAgo(2), true)
+      .describe('when given a Date two months ago and reversed')
+      .expect('yellow')
+    given(monthsAgo(15), true)
+      .describe('when given a Date 15 months ago and reversed')
+      .expect('green')
   })
 
   test(version, () => {
diff --git a/services/github/github-created-at.service.js b/services/github/github-created-at.service.js
new file mode 100644
index 0000000000..c6f3f6c0b9
--- /dev/null
+++ b/services/github/github-created-at.service.js
@@ -0,0 +1,54 @@
+import dayjs from 'dayjs'
+import Joi from 'joi'
+import { age } from '../color-formatters.js'
+import { pathParams } from '../index.js'
+import { formatDate } from '../text-formatters.js'
+import { GithubAuthV3Service } from './github-auth-service.js'
+import { documentation, httpErrorsFor } from './github-helpers.js'
+
+const schema = Joi.object({
+  created_at: Joi.date().required(),
+}).required()
+
+export default class GithubCreatedAt extends GithubAuthV3Service {
+  static category = 'activity'
+  static route = { base: 'github/created-at', pattern: ':user/:repo' }
+  static openApi = {
+    '/github/created-at/{user}/{repo}': {
+      get: {
+        summary: 'Github Created At',
+        description: documentation,
+        parameters: pathParams(
+          {
+            name: 'user',
+            example: 'mashape',
+          },
+          {
+            name: 'repo',
+            example: 'apistatus',
+          },
+        ),
+      },
+    },
+  }
+
+  static defaultBadgeData = { label: 'created at' }
+
+  static render({ createdAt }) {
+    const date = dayjs(createdAt)
+    return {
+      message: formatDate(date),
+      color: age(date, true),
+    }
+  }
+
+  async handle({ user, repo }) {
+    const { created_at: createdAt } = await this._requestJson({
+      schema,
+      url: `/repos/${user}/${repo}`,
+      httpErrors: httpErrorsFor('repo not found'),
+    })
+
+    return this.constructor.render({ createdAt })
+  }
+}
diff --git a/services/github/github-created-at.tester.js b/services/github/github-created-at.tester.js
new file mode 100644
index 0000000000..0f47346820
--- /dev/null
+++ b/services/github/github-created-at.tester.js
@@ -0,0 +1,14 @@
+import { isFormattedDate } from '../test-validators.js'
+import { createServiceTester } from '../tester.js'
+
+export const t = await createServiceTester()
+
+t.create('created at').get('/erayerdin/firereact.json').expectBadge({
+  label: 'created at',
+  message: isFormattedDate,
+})
+
+t.create('created at').get('/erayerdin/not-a-valid-repo.json').expectBadge({
+  label: 'created at',
+  message: 'repo not found',
+})
-- 
GitLab