src/index.ts   A
last analyzed

Complexity

Total Complexity 15
Complexity/F 2.5

Size

Lines of Code 125
Function Count 6

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 99
dl 0
loc 125
rs 10
c 0
b 0
f 0
wmc 15
mnd 9
bc 9
fnc 6
bpm 1.5
cpm 2.5
noi 0

6 Functions

Rating   Name   Duplication   Size   Complexity  
A index.ts ➔ loadConfiguration 0 11 1
B index.ts ➔ processSummary 0 56 6
A index.ts ➔ fetchStatistics 0 8 2
A index.ts ➔ generateLanguageSummary 0 16 2
A index.ts ➔ generateTitle 0 6 3
A index.ts ➔ createSummaryTable 0 3 1
1
import * as core from '@actions/core';
2
import {HttpClient} from '@actions/http-client';
3
import {Octokit} from '@octokit/rest';
4
import {config as loadEnvConfig} from 'dotenv';
5
import {resolve} from 'path';
6
import formatLine from './formatLine';
7
8
loadEnvConfig({path: resolve(__dirname, '../.env')});
9
10
const DEFAULT_WAKATIME_BASE_URL = 'https://wakatime.com/api/v1';
11
const OTHER_LANGUAGES = ['Other', 'AUTO_DETECTED', 'unknown', 'Log', 'Text', 'GitIgnore file', '.env file'];
12
13
function loadConfiguration() {
14
  return {
15
    GH_TOKEN: core.getInput('GH_TOKEN', {required: true}),
16
    WAKATIME_BASE_URL: core.getInput('WAKATIME_BASE_URL', {required: false}) || DEFAULT_WAKATIME_BASE_URL,
17
    WAKA_API_KEY: core.getInput('WAKA_API_KEY', {required: true}),
18
    GIST_ID: core.getInput('GIST_ID', {required: true}),
19
    MAX_RESULT: Number(core.getInput('MAX_RESULT', {required: true})),
20
    DATE_RANGE: core.getInput('DATE_RANGE', {required: false}) || 'last_7_days',
21
    PRINT_SUMMARY: core.getBooleanInput('PRINT_SUMMARY', {required: true}),
22
    USE_OLD_FORMAT: core.getBooleanInput('USE_OLD_FORMAT', {required: false}),
23
  };
24
}
25
26
function generateTitle(range: string, updateDate: string) {
27
  let title = 'latest';
28
  if (range === 'last_7_days') title = 'weekly';
29
  else if (range === 'last_30_days') title = 'monthly';
30
  return `My ${title} stack [update ${updateDate}]`;
31
}
32
33
async function fetchStatistics(httpClient: HttpClient, wakatimeBaseURL: string, range: string, apiKey: string) {
34
  const response = await httpClient.getJson(
35
    `${wakatimeBaseURL}/users/current/stats/${range}`,
36
    {Authorization: `Basic ${Buffer.from(apiKey).toString('base64')}`}
37
  ).catch(error => core.setFailed('Action failed: ' + error.message));
38
  // @ts-ignore
39
  return response.result?.data.languages;
40
}
41
42
function generateLanguageSummary(languages: any[], maxResult: number, useOldFormat: boolean) {
43
  let otherTotalSeconds = 0;
44
  let otherPercent = 0;
45
  const lines = languages.reduce((result: any[], lang: any) => {
46
    const {name, percent, total_seconds} = lang;
47
    if (OTHER_LANGUAGES.includes(name) || result.length >= maxResult - 1) {
48
      otherTotalSeconds += total_seconds;
49
      otherPercent += percent;
50
      return result;
51
    }
52
    result.push(formatLine(name, total_seconds, percent, useOldFormat));
53
    return result;
54
  }, []);
55
  lines.push(formatLine('Other', otherTotalSeconds, otherPercent, useOldFormat));
56
  return lines;
57
}
58
59
function createSummaryTable() {
60
  return [[{data: 'Action', header: true}, {data: 'Result', header: true}]];
61
}
62
63
async function processSummary({
64
  GH_TOKEN,
65
  WAKATIME_BASE_URL,
66
  WAKA_API_KEY,
67
  GIST_ID,
68
  MAX_RESULT,
69
  DATE_RANGE,
70
  PRINT_SUMMARY,
71
  USE_OLD_FORMAT
72
}) {
73
  const httpClient = new HttpClient('WakaTime-Gist/1.3 +https://github.com/marketplace/actions/wakatime-gist');
74
  const languages = await fetchStatistics(httpClient, WAKATIME_BASE_URL, DATE_RANGE, WAKA_API_KEY);
75
  if (!languages) {
76
    core.setFailed('Action failed: empty response from wakatime.com');
77
    return;
78
  }
79
  const updateDate = new Date().toLocaleDateString('en-us', {day: 'numeric', year: 'numeric', month: 'short'});
80
  const title = generateTitle(DATE_RANGE, updateDate);
81
  const summaryTable: any[] = createSummaryTable();
82
  summaryTable.push(['Statistics received', '✔']);
83
  const lines = generateLanguageSummary(languages, MAX_RESULT, USE_OLD_FORMAT);
84
  if (lines.length === 0) {
85
    core.notice('No statistics for the last time period. Gist not updated');
86
    return;
87
  }
88
  const octokit = new Octokit({auth: GH_TOKEN});
89
  const gist = await octokit.gists.get({gist_id: GIST_ID}).catch(error => {
90
    core.setFailed('Action failed: Gist ' + error.message);
91
    return null;
92
  });
93
  if (!gist) return;
94
  const filename = Object.keys(gist.data.files || {})[0];
95
  if (!filename) {
96
    core.setFailed('Action failed: Gist filename not found');
97
    return;
98
  }
99
  await octokit.gists.update({
100
    gist_id: GIST_ID,
101
    files: {
102
      [filename]: {
103
        filename: title,
104
        content: lines.join('\n'),
105
      },
106
    },
107
  }).catch(error => core.setFailed('Action failed: Gist ' + error.message));
108
  summaryTable.push(['Gist updated', '✔']);
109
  const summary = core.summary
110
    .addHeading('Results')
111
    .addTable(summaryTable)
112
    .addBreak()
113
    .addLink('WakaTime-Gist/2.0', 'https://github.com/marketplace/actions/wakatime-gist');
114
  if (PRINT_SUMMARY) {
115
    await summary.write();
116
  } else {
117
    console.log(summary.stringify());
118
  }
119
}
120
121
(async () => {
122
  const config = loadConfiguration();
123
  await processSummary(config);
124
})();
125