Sleep added between redmine api calls
This commit is contained in:
parent
623b62e6ff
commit
6c672cb45d
7 changed files with 95 additions and 45 deletions
|
|
@ -7,5 +7,8 @@ charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[src/logic/*]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
|
||||||
32
.eslintrc
32
.eslintrc
|
|
@ -2,5 +2,35 @@
|
||||||
"extends": [
|
"extends": [
|
||||||
"oclif",
|
"oclif",
|
||||||
"oclif-typescript"
|
"oclif-typescript"
|
||||||
]
|
],
|
||||||
|
"rules": {
|
||||||
|
"quotes": "off",
|
||||||
|
"indent": "off",
|
||||||
|
"semi": "off",
|
||||||
|
"unicorn/prefer-node-protocol": "off",
|
||||||
|
"unicorn/prefer-ternary": "off",
|
||||||
|
"dot-notation": "off",
|
||||||
|
"padding-line-between-statements": "off",
|
||||||
|
"camelcase": "off",
|
||||||
|
"unicorn/no-console-spaces": "off",
|
||||||
|
"new-cap": "off",
|
||||||
|
"no-await-in-loop": "off",
|
||||||
|
"unicorn/no-for-loop": "off",
|
||||||
|
"comma-dangle": "off",
|
||||||
|
"node/no-missing-import": "off",
|
||||||
|
"no-else-return": "off",
|
||||||
|
"quote-props": "off",
|
||||||
|
"no-inner-declarations": "off",
|
||||||
|
"no-process-exit": "off",
|
||||||
|
"unicorn/no-process-exit": "off",
|
||||||
|
"eol-last": "off",
|
||||||
|
"no-prototype-builtins": "off",
|
||||||
|
"padded-blocks": "off",
|
||||||
|
"unicorn/prefer-number-properties": "off",
|
||||||
|
"operator-assignment": "off",
|
||||||
|
"no-negated-condition": "off",
|
||||||
|
"unicorn/catch-error-name": "off",
|
||||||
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
"unicorn/prefer-includes": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "redmine-time-manager",
|
"name": "redmine-time-manager",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"description": "Redmine Time Manager",
|
"description": "Redmine Time Manager",
|
||||||
"author": "Pavel Gnedov @pavel-g",
|
"author": "Pavel Gnedov @pavel-g",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ export const defaultConfig: ConfigTypes.Config = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getConfig(force: boolean = false): ConfigTypes.Config {
|
export function getConfig(force = false): ConfigTypes.Config {
|
||||||
if (!force && !Args.args['config']) {
|
if (!force && !Args.args['config']) {
|
||||||
return defaultConfig;
|
return defaultConfig;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
import {config} from "./config";
|
import {config} from "./config";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export async function loadEntries(date: string): Promise<Record<string, any>> {
|
type TimeEntry = Record<string, any>;
|
||||||
|
type TimeEntriesResponse = {time_entries: TimeEntry[]};
|
||||||
|
|
||||||
|
export async function loadEntries(date: string): Promise<TimeEntry[]> {
|
||||||
const url = `${config.redmine.url}/time_entries.json`;
|
const url = `${config.redmine.url}/time_entries.json`;
|
||||||
const params = {
|
const params = {
|
||||||
user_id: config.redmine.user_id,
|
user_id: config.redmine.user_id,
|
||||||
from: date,
|
from: date,
|
||||||
to: date
|
to: date
|
||||||
};
|
};
|
||||||
const resp = await axios.get<Record<string, any>>(url, {params: params});
|
const resp = await axios.get<TimeEntriesResponse>(url, {params: params});
|
||||||
if (!resp || resp.status !== 200 || !resp.data || !resp.data.time_entries) {
|
if (!resp || resp.status !== 200 || !resp.data || !resp.data.time_entries) {
|
||||||
throw new Error('Не удалось загрузить записи за дату');
|
throw new Error('Не удалось загрузить записи за дату');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {config} from "./config";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {loadEntries} from "./open";
|
import {loadEntries} from "./open";
|
||||||
import {ColumnConverter, filterByQuery, getDate, getItemForRedmine, TimeEntryForRedmine} from "./csv";
|
import {ColumnConverter, filterByQuery, getDate, getItemForRedmine, TimeEntryForRedmine} from "./csv";
|
||||||
import {uniq} from "./utils";
|
import {sleep, uniq} from './utils'
|
||||||
|
|
||||||
function readContentFromFile(fileName: string): string {
|
function readContentFromFile(fileName: string): string {
|
||||||
return fs.readFileSync(fileName, {encoding: 'utf8'});
|
return fs.readFileSync(fileName, {encoding: 'utf8'});
|
||||||
|
|
@ -13,7 +13,7 @@ function readContentFromFile(fileName: string): string {
|
||||||
|
|
||||||
async function readContentFromStdin(): Promise<string> {
|
async function readContentFromStdin(): Promise<string> {
|
||||||
const GetStdin = await import('get-stdin');
|
const GetStdin = await import('get-stdin');
|
||||||
return await GetStdin.default();
|
return GetStdin.default();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readContent(): Promise<string> {
|
async function readContent(): Promise<string> {
|
||||||
|
|
@ -26,23 +26,24 @@ async function readContent(): Promise<string> {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
function backupEntries(entries: Record<string, any>): void {
|
function backupEntries(entries: Record<string, any>[]): void {
|
||||||
const fileName = `entries-${args['date']}.json`;
|
const fileName = `entries-${args['date']}.json`;
|
||||||
const content = JSON.stringify(entries);
|
const content = JSON.stringify(entries);
|
||||||
fs.writeFileSync(fileName, content, {encoding: "utf8"});
|
fs.writeFileSync(fileName, content, {encoding: "utf8"});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteEntries(entries: Record<string, any>): Promise<void> {
|
async function deleteEntries(entries: Record<string, any>[]): Promise<void> {
|
||||||
await Promise.all(
|
let i: number;
|
||||||
entries.map(async (entry: Record<string, any>) => {
|
for (i = 0; i < entries.length; i++) {
|
||||||
|
const entry = entries[i];
|
||||||
const url = `${config.redmine.url}/time_entries/${entry.id}.xml`;
|
const url = `${config.redmine.url}/time_entries/${entry.id}.xml`;
|
||||||
if (args['dry']) {
|
if (args['dry']) {
|
||||||
console.log('Delete time entry:', {url, entry});
|
console.log('Delete time entry:', {url, entry});
|
||||||
} else {
|
} else {
|
||||||
await axios.delete(url);
|
await axios.delete(url);
|
||||||
}
|
}
|
||||||
})
|
await sleep(100);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cleanTimeEntries(items: TimeEntryForRedmine[]): Promise<void> {
|
async function cleanTimeEntries(items: TimeEntryForRedmine[]): Promise<void> {
|
||||||
|
|
@ -91,6 +92,7 @@ async function saveCsv(csvData: TimeEntryForRedmine[]): Promise<void> {
|
||||||
}
|
}
|
||||||
const saveResult = await saveItem(item);
|
const saveResult = await saveItem(item);
|
||||||
if (saveResult) successCount++;
|
if (saveResult) successCount++;
|
||||||
|
await sleep(100);
|
||||||
}
|
}
|
||||||
console.log(`Сохранено записей: ${successCount}`);
|
console.log(`Сохранено записей: ${successCount}`);
|
||||||
}
|
}
|
||||||
|
|
@ -113,8 +115,14 @@ export async function save(): Promise<void> {
|
||||||
})
|
})
|
||||||
.map(item => item.item) as TimeEntryForRedmine[];
|
.map(item => item.item) as TimeEntryForRedmine[];
|
||||||
|
|
||||||
if (args['rewrite']) await cleanTimeEntries(items);
|
if (args['rewrite']) {
|
||||||
|
console.log('Очистка существующих записей...')
|
||||||
|
await cleanTimeEntries(items);
|
||||||
|
console.log('Очистка существующих записей завершена')
|
||||||
|
}
|
||||||
|
console.log('Сохранение новых записей...');
|
||||||
await saveCsv(items);
|
await saveCsv(items);
|
||||||
|
console.log('Сохранение новых записей завершено');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUniqDates(items: TimeEntryForRedmine[]): string[] {
|
export function getUniqDates(items: TimeEntryForRedmine[]): string[] {
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,40 @@
|
||||||
export function invert(obj: Record<any, any>): Record<any, any> {
|
export function invert(obj: Record<any, any>): Record<any, any> {
|
||||||
const newObj = {};
|
const newObj = {}
|
||||||
let key;
|
let key
|
||||||
for (key in obj) {
|
for (key in obj) {
|
||||||
if (!obj.hasOwnProperty(key)) continue;
|
if (!obj.hasOwnProperty(key)) continue
|
||||||
const value = obj[key];
|
const value = obj[key]
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
newObj[value] = key;
|
newObj[value] = key
|
||||||
}
|
}
|
||||||
return newObj;
|
return newObj
|
||||||
}
|
}
|
||||||
|
|
||||||
export function uniq<T>(src: T[]): T[] {
|
export function uniq<T>(src: T[]): T[] {
|
||||||
const res = [];
|
const res = []
|
||||||
let i: number;
|
let i: number
|
||||||
for (i = 0; i < src.length; i++) {
|
for (i = 0; i < src.length; i++) {
|
||||||
const value = src[i];
|
const value = src[i]
|
||||||
if (res.indexOf(value) < 0) {
|
if (res.indexOf(value) < 0) {
|
||||||
res.push(value);
|
res.push(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assign(target: Record<string, any>, src: Record<string, any>): Record<string, any> {
|
export function assign(target: Record<string, any>, src: Record<string, any>): Record<string, any> {
|
||||||
let key: string;
|
let key: string
|
||||||
for (key in src) {
|
for (key in src) {
|
||||||
if (src.hasOwnProperty(key)) {
|
if (src.hasOwnProperty(key)) {
|
||||||
console.debug('rewrite key:', key, ' with value:', src[key]); // DEBUG
|
console.debug('rewrite key:', key, ' with value:', src[key]) // DEBUG
|
||||||
target[key] = src[key];
|
target[key] = src[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return target;
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sleep(timeout: number): Promise<void> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, timeout)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue