feat(worker): convert 'branch' to typescript (#4449)

Co-Authored-By: Jamie Magee <JamieMagee@users.noreply.github.com>
This commit is contained in:
Michael Kriese 2019-10-18 14:30:51 +02:00 committed by Rhys Arkins
parent 4d6b98f9b0
commit 2a4de19c77
12 changed files with 165 additions and 91 deletions

View file

@ -157,7 +157,7 @@ export interface Upgrade<T = Record<string, any>>
version?: string; version?: string;
} }
interface ArtifactError { export interface ArtifactError {
lockFile?: string; lockFile?: string;
stderr?: string; stderr?: string;
} }

View file

@ -2,6 +2,11 @@ import got from 'got';
import Git from 'simple-git/promise'; import Git from 'simple-git/promise';
import { RenovateConfig } from '../config/common'; import { RenovateConfig } from '../config/common';
export interface FileData {
name: string;
contents: string;
}
export interface GotApiOptions { export interface GotApiOptions {
useCache?: boolean; useCache?: boolean;
hostType?: string; hostType?: string;

View file

@ -1,11 +1,18 @@
const { logger } = require('../../logger'); import { logger } from '../../logger';
const { platform } = require('../../platform'); import { RenovateConfig } from '../../config';
import { platform } from '../../platform';
module.exports = { export type AutomergeResult =
tryBranchAutomerge, | 'automerged'
}; | 'automerge aborted - PR exists'
| 'branch status error'
| 'failed'
| 'no automerge'
| 'not ready';
async function tryBranchAutomerge(config) { export async function tryBranchAutomerge(
config: RenovateConfig
): Promise<AutomergeResult> {
logger.debug('Checking if we can automerge branch'); logger.debug('Checking if we can automerge branch');
if (!(config.automerge && config.automergeType === 'branch')) { if (!(config.automerge && config.automergeType === 'branch')) {
return 'no automerge'; return 'no automerge';

View file

@ -1,11 +1,11 @@
const { logger } = require('../../logger'); import { logger } from '../../logger';
const { platform } = require('../../platform'); import { RenovateConfig } from '../../config';
import { platform } from '../../platform';
module.exports = { /** TODO: Proper return type */
prAlreadyExisted, export async function prAlreadyExisted(
}; config: RenovateConfig
): Promise<any | null> {
async function prAlreadyExisted(config) {
logger.trace({ config }, 'prAlreadyExisted'); logger.trace({ config }, 'prAlreadyExisted');
if (config.recreateClosed) { if (config.recreateClosed) {
logger.debug('recreateClosed is true'); logger.debug('recreateClosed is true');

View file

@ -1,12 +1,21 @@
import is from '@sindresorhus/is'; import is from '@sindresorhus/is';
import { platform } from '../../platform'; import minimatch from 'minimatch';
import { FileData, platform } from '../../platform';
import { logger } from '../../logger';
import { RenovateConfig } from '../../config';
const minimatch = require('minimatch'); export type CommitConfig = RenovateConfig & {
const { logger } = require('../../logger'); baseBranch?: string;
branchName: string;
commitMessage: string;
excludeCommitPaths?: string[];
updatedPackageFiles: FileData[];
updatedArtifacts: FileData[];
};
export { commitFilesToBranch }; export async function commitFilesToBranch(
config: CommitConfig
async function commitFilesToBranch(config) { ): Promise<boolean> {
let updatedFiles = config.updatedPackageFiles.concat(config.updatedArtifacts); let updatedFiles = config.updatedPackageFiles.concat(config.updatedArtifacts);
// istanbul ignore if // istanbul ignore if
if (is.nonEmptyArray(config.excludeCommitPaths)) { if (is.nonEmptyArray(config.excludeCommitPaths)) {

View file

@ -1,17 +1,25 @@
import is from '@sindresorhus/is'; import is from '@sindresorhus/is';
import { platform } from '../../platform'; import { FileData, platform } from '../../platform';
import { logger } from '../../logger';
import { get } from '../../manager';
import { RenovateConfig } from '../../config';
import { UpdateArtifactsConfig, ArtifactError } from '../../manager/common';
const { logger } = require('../../logger'); export interface PackageFilesResult {
const { get } = require('../../manager'); artifactErrors: ArtifactError[];
parentBranch: string;
updatedPackageFiles: FileData[];
updatedArtifacts: FileData[];
}
export { getUpdatedPackageFiles }; export async function getUpdatedPackageFiles(
config: RenovateConfig & UpdateArtifactsConfig
async function getUpdatedPackageFiles(config) { ): Promise<PackageFilesResult> {
logger.debug('manager.getUpdatedPackageFiles()'); logger.debug('manager.getUpdatedPackageFiles()');
logger.trace({ config }); logger.trace({ config });
const updatedFileContents = {}; const updatedFileContents: Record<string, string> = {};
const packageFileManagers = {}; const packageFileManagers: Record<string, string> = {};
const packageFileUpdatedDeps = {}; const packageFileUpdatedDeps: Record<string, string[]> = {};
const lockFileMaintenanceFiles = []; const lockFileMaintenanceFiles = [];
for (const upgrade of config.upgrades) { for (const upgrade of config.upgrades) {
const { manager, packageFile, depName } = upgrade; const { manager, packageFile, depName } = upgrade;
@ -68,8 +76,8 @@ async function getUpdatedPackageFiles(config) {
name, name,
contents: updatedFileContents[name], contents: updatedFileContents[name],
})); }));
const updatedArtifacts = []; const updatedArtifacts: FileData[] = [];
const artifactErrors = []; const artifactErrors: ArtifactError[] = [];
for (const packageFile of updatedPackageFiles) { for (const packageFile of updatedPackageFiles) {
const manager = packageFileManagers[packageFile.name]; const manager = packageFileManagers[packageFile.name];
const updatedDeps = packageFileUpdatedDeps[packageFile.name]; const updatedDeps = packageFileUpdatedDeps[packageFile.name];
@ -82,7 +90,7 @@ async function getUpdatedPackageFiles(config) {
config config
); );
if (is.nonEmptyArray(results)) { if (is.nonEmptyArray(results)) {
for (/** @type any */ const res of results) { for (const res of results) {
const { file, artifactError } = res; const { file, artifactError } = res;
if (file) { if (file) {
updatedArtifacts.push(file); updatedArtifacts.push(file);
@ -109,7 +117,7 @@ async function getUpdatedPackageFiles(config) {
config config
); );
if (is.nonEmptyArray(results)) { if (is.nonEmptyArray(results)) {
for (/** @type any */ const res of results) { for (const res of results) {
const { file, artifactError } = res; const { file, artifactError } = res;
if (file) { if (file) {
updatedArtifacts.push(file); updatedArtifacts.push(file);

View file

@ -1,26 +1,52 @@
const { DateTime } = require('luxon'); import { DateTime } from 'luxon';
const { logger, setMeta } = require('../../logger'); import { logger, setMeta } from '../../logger';
const schedule = require('./schedule'); import { isScheduledNow } from './schedule';
const { getUpdatedPackageFiles } = require('./get-updated'); import { getUpdatedPackageFiles } from './get-updated';
const { getAdditionalFiles } = require('../../manager/npm/post-update'); import {
const { commitFilesToBranch } = require('./commit'); getAdditionalFiles,
const { getParentBranch } = require('./parent'); AdditionalPackageFiles,
const { tryBranchAutomerge } = require('./automerge'); } from '../../manager/npm/post-update';
const { setStability, setUnpublishable } = require('./status-checks'); import { commitFilesToBranch, CommitConfig } from './commit';
const { prAlreadyExisted } = require('./check-existing'); import { getParentBranch } from './parent';
const prWorker = require('../pr'); import { tryBranchAutomerge } from './automerge';
const { appName, appSlug } = require('../../config/app-strings'); import {
const { platform } = require('../../platform'); setStability,
const { emojify } = require('../../util/emoji'); setUnpublishable,
StabilityConfig,
UnpublishableConfig,
} from './status-checks';
import { prAlreadyExisted } from './check-existing';
import { ensurePr, checkAutoMerge } from '../pr';
import { appName, appSlug } from '../../config/app-strings';
import { RenovateConfig } from '../../config';
import { platform } from '../../platform';
import { emojify } from '../../util/emoji';
const { isScheduledNow } = schedule; export type BranchConfig = RenovateConfig &
StabilityConfig &
UnpublishableConfig &
CommitConfig;
module.exports = { export type ProcessBranchResult =
processBranch, | 'already-existed'
}; | 'automerged'
| 'done'
| 'error'
| 'needs-approval'
| 'needs-pr-approval'
| 'not-scheduled'
| 'no-work'
| 'pending'
| 'pr-created'
| 'pr-edited'
| 'pr-hourly-limit-reached';
async function processBranch(branchConfig, prHourlyLimitReached, packageFiles) { export async function processBranch(
branchConfig: BranchConfig,
prHourlyLimitReached?: boolean,
packageFiles?: AdditionalPackageFiles
): Promise<ProcessBranchResult> {
const config = { ...branchConfig }; const config = { ...branchConfig };
const dependencies = config.upgrades const dependencies = config.upgrades
.map(upgrade => upgrade.depName) .map(upgrade => upgrade.depName)
@ -418,7 +444,7 @@ async function processBranch(branchConfig, prHourlyLimitReached, packageFiles) {
logger.debug( logger.debug(
`There are ${config.errors.length} errors and ${config.warnings.length} warnings` `There are ${config.errors.length} errors and ${config.warnings.length} warnings`
); );
const pr = await prWorker.ensurePr(config); const pr = await ensurePr(config);
// TODO: ensurePr should check for automerge itself // TODO: ensurePr should check for automerge itself
if (pr === 'needs-pr-approval') { if (pr === 'needs-pr-approval') {
return 'needs-pr-approval'; return 'needs-pr-approval';
@ -504,7 +530,7 @@ async function processBranch(branchConfig, prHourlyLimitReached, packageFiles) {
await platform.ensureCommentRemoval(pr.number, topic); await platform.ensureCommentRemoval(pr.number, topic);
} }
} }
const prAutomerged = await prWorker.checkAutoMerge(pr, config); const prAutomerged = await checkAutoMerge(pr, config);
if (prAutomerged) { if (prAutomerged) {
return 'automerged'; return 'automerged';
} }
@ -530,7 +556,8 @@ async function processBranch(branchConfig, prHourlyLimitReached, packageFiles) {
return 'done'; return 'done';
} }
function rebaseCheck(config, branchPr) { // TODO: proper typings
function rebaseCheck(config: RenovateConfig, branchPr: any): boolean {
const titleRebase = branchPr.title && branchPr.title.startsWith('rebase!'); const titleRebase = branchPr.title && branchPr.title.startsWith('rebase!');
const labelRebase = const labelRebase =
branchPr.labels && branchPr.labels.includes(config.rebaseLabel); branchPr.labels && branchPr.labels.includes(config.rebaseLabel);

View file

@ -1,12 +1,13 @@
const { logger } = require('../../logger'); import { logger } from '../../logger';
const { appSlug } = require('../../config/app-strings'); import { appSlug } from '../../config/app-strings';
const { platform } = require('../../platform'); import { RenovateConfig } from '../../config';
import { platform } from '../../platform';
module.exports = { type ParentBranch = { parentBranch: string | undefined; isModified?: boolean };
getParentBranch,
};
async function getParentBranch(config) { export async function getParentBranch(
config: RenovateConfig
): Promise<ParentBranch> {
const { branchName } = config; const { branchName } = config;
// Check if branch exists // Check if branch exists
const branchExists = await platform.branchExists(branchName); const branchExists = await platform.branchExists(branchName);

View file

@ -1,35 +1,30 @@
import is from '@sindresorhus/is'; import is from '@sindresorhus/is';
import later from 'later';
const later = require('later'); import moment from 'moment-timezone';
const moment = require('moment-timezone'); import { logger } from '../../logger';
const { logger } = require('../../logger');
export { hasValidTimezone, hasValidSchedule, isScheduledNow };
const scheduleMappings = { const scheduleMappings = {
'every month': 'before 3am on the first day of the month', 'every month': 'before 3am on the first day of the month',
monthly: 'before 3am on the first day of the month', monthly: 'before 3am on the first day of the month',
}; };
function fixShortHours(input) { function fixShortHours(input: string): string {
return input.replace(/( \d?\d)((a|p)m)/g, '$1:00$2'); return input.replace(/( \d?\d)((a|p)m)/g, '$1:00$2');
} }
/** export function hasValidTimezone(
* @returns {[boolean] | [boolean, string]} timezone: string
*/ ): [boolean] | [boolean, string] {
function hasValidTimezone(timezone) {
if (!moment.tz.zone(timezone)) { if (!moment.tz.zone(timezone)) {
return [false, `Invalid timezone: ${timezone}`]; return [false, `Invalid timezone: ${timezone}`];
} }
return [true]; return [true];
} }
/** export function hasValidSchedule(
* @returns {[boolean] | [boolean, string]} schedule: string[] | null | 'at any time'
*/ ): [boolean] | [boolean, string] {
function hasValidSchedule(schedule) { let message: string;
let message;
if ( if (
!schedule || !schedule ||
schedule === 'at any time' || schedule === 'at any time' ||
@ -70,7 +65,7 @@ function hasValidSchedule(schedule) {
return [true, '']; return [true, ''];
} }
function isScheduledNow(config) { export function isScheduledNow(config) {
let configSchedule = config.schedule; let configSchedule = config.schedule;
logger.debug(`Checking schedule(${configSchedule}, ${config.timezone})`); logger.debug(`Checking schedule(${configSchedule}, ${config.timezone})`);
if ( if (

View file

@ -1,13 +1,14 @@
const { logger } = require('../../logger'); import { logger } from '../../logger';
const { appSlug, urls } = require('../../config/app-strings'); import { appSlug, urls } from '../../config/app-strings';
const { platform } = require('../../platform'); import { RenovateConfig } from '../../config';
import { platform } from '../../platform';
module.exports = { async function setStatusCheck(
setStability, branchName: string,
setUnpublishable, context: string,
}; description: string,
state: string
async function setStatusCheck(branchName, context, description, state) { ) {
const existingState = await platform.getBranchStatusCheck( const existingState = await platform.getBranchStatusCheck(
branchName, branchName,
context context
@ -27,7 +28,12 @@ async function setStatusCheck(branchName, context, description, state) {
} }
} }
async function setStability(config) { export type StabilityConfig = RenovateConfig & {
stabilityStatus: string;
branchName: string;
};
export async function setStability(config: StabilityConfig) {
if (!config.stabilityStatus) { if (!config.stabilityStatus) {
return; return;
} }
@ -44,7 +50,15 @@ async function setStability(config) {
); );
} }
async function setUnpublishable(config) { export type UnpublishableConfig = RenovateConfig & {
unpublishSafe?: boolean;
canBeUnpublished?: boolean;
branchName: string;
};
export async function setUnpublishable(
config: UnpublishableConfig
): Promise<void> {
if (!config.unpublishSafe) { if (!config.unpublishSafe) {
return; return;
} }

View file

@ -182,6 +182,7 @@
"@types/later": "1.2.5", "@types/later": "1.2.5",
"@types/lodash": "4.14.144", "@types/lodash": "4.14.144",
"@types/luxon": "1.15.2", "@types/luxon": "1.15.2",
"@types/moment-timezone": "0.5.12",
"@types/nock": "10.0.3", "@types/nock": "10.0.3",
"@types/node": "11.13.22", "@types/node": "11.13.22",
"@types/node-emoji": "1.8.1", "@types/node-emoji": "1.8.1",

View file

@ -1236,6 +1236,13 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/moment-timezone@0.5.12":
version "0.5.12"
resolved "https://registry.yarnpkg.com/@types/moment-timezone/-/moment-timezone-0.5.12.tgz#0fb680c03db194fe8ff4551eaeb1eec8d3d80e9f"
integrity sha512-hnHH2+Efg2vExr/dSz+IX860nSiyk9Sk4pJF2EmS11lRpMcNXeB4KBW5xcgw2QPsb9amTXdsVNEe5IoJXiT0uw==
dependencies:
moment ">=2.14.0"
"@types/nock@10.0.3": "@types/nock@10.0.3":
version "10.0.3" version "10.0.3"
resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.3.tgz#dab1d18ffbccfbf2db811dab9584304eeb6e1c4c" resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.3.tgz#dab1d18ffbccfbf2db811dab9584304eeb6e1c4c"
@ -6163,7 +6170,7 @@ moment-timezone@0.5.26:
dependencies: dependencies:
moment ">= 2.9.0" moment ">= 2.9.0"
moment@2.24.0, "moment@>= 2.9.0", moment@^2.10.6: moment@2.24.0, "moment@>= 2.9.0", moment@>=2.14.0, moment@^2.10.6:
version "2.24.0" version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==