Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(migrations): extend abstract migration #12963

Merged
Merged
2 changes: 1 addition & 1 deletion lib/config/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function migrateConfig(
optionTypes[option.name] = option.type;
});
}
const newConfig = MigrationsService.run(config);
const newConfig = MigrationsService.run(config).migratedConfig;
viceice marked this conversation as resolved.
Show resolved Hide resolved
const migratedConfig = clone(newConfig) as MigratedRenovateConfig;
const depTypes = [
'dependencies',
Expand Down
45 changes: 35 additions & 10 deletions lib/config/migrations/base/abstract-migration.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,49 @@
import is from '@sindresorhus/is';
import type { RenovateConfig } from '../../types';
import type { Migration } from '../types';

export abstract class AbstractMigration implements Migration {
readonly propertyName: string;
abstract readonly propertyName: string;

protected readonly originalConfig: RenovateConfig;
private readonly originalConfig: RenovateConfig;

protected readonly migratedConfig: RenovateConfig;
private readonly migratedConfig: RenovateConfig;

constructor(
propertyName: string,
originalConfig: RenovateConfig,
migratedConfig: RenovateConfig
) {
this.propertyName = propertyName;
constructor(originalConfig: RenovateConfig, migratedConfig: RenovateConfig) {
this.originalConfig = originalConfig;
this.migratedConfig = migratedConfig;
}

abstract run(): void;
abstract run(value: unknown): void;

protected get<Key extends keyof RenovateConfig>(
key: Key
): RenovateConfig[Key] {
return this.migratedConfig[key] ?? this.originalConfig[key];
}

protected setSafely<Key extends keyof RenovateConfig>(
key: Key,
value: RenovateConfig[Key]
): void {
if (
is.nullOrUndefined(this.originalConfig[key]) &&
is.nullOrUndefined(this.migratedConfig[key])
) {
this.migratedConfig[key] = value;
}
}

protected setHard<Key extends keyof RenovateConfig>(
key: Key,
value: RenovateConfig[Key]
): void {
this.migratedConfig[key] = value;
}

protected rewrite(value: unknown): void {
this.setHard(this.propertyName, value);
}

protected delete(property: string): void {
delete this.migratedConfig[property];
Expand Down
12 changes: 12 additions & 0 deletions lib/config/migrations/base/remove-property-migration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import type { RenovateConfig } from '../../types';
import { AbstractMigration } from './abstract-migration';

export class RemovePropertyMigration extends AbstractMigration {
readonly propertyName: string;

constructor(
propertyName: string,
originalConfig: RenovateConfig,
migratedConfig: RenovateConfig
) {
super(originalConfig, migratedConfig);
this.propertyName = propertyName;
}

override run(): void {
this.delete(this.propertyName);
}
Expand Down
12 changes: 7 additions & 5 deletions lib/config/migrations/base/rename-property-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@ import type { RenovateConfig } from '../../types';
import { AbstractMigration } from './abstract-migration';

export class RenamePropertyMigration extends AbstractMigration {
protected readonly newPropertyName: string;
readonly propertyName: string;

private readonly newPropertyName: string;

constructor(
deprecatedPropertyName: string,
newPropertyName: string,
originalConfig: RenovateConfig,
migratedConfig: RenovateConfig
) {
super(deprecatedPropertyName, originalConfig, migratedConfig);
super(originalConfig, migratedConfig);
this.propertyName = deprecatedPropertyName;
this.newPropertyName = newPropertyName;
}

override run(): void {
override run(value): void {
this.delete(this.propertyName);

this.migratedConfig[this.newPropertyName] =
this.originalConfig[this.propertyName];
this.setSafely(this.newPropertyName, value);
}
}
7 changes: 5 additions & 2 deletions lib/config/migrations/custom/binary-source-migration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import { MigrationsService } from '../migrations-service';

describe('config/migrations/custom/binary-source-migration', () => {
it('should migrate "auto" to "global"', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
binarySource: 'auto',
});

expect(migratedConfig.binarySource).toBe('global');
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({
binarySource: 'global',
});
});
});
11 changes: 4 additions & 7 deletions lib/config/migrations/custom/binary-source-migration.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import type { RenovateConfig } from '../../types';
import { AbstractMigration } from '../base/abstract-migration';

export class BinarySourceMigration extends AbstractMigration {
constructor(originalConfig: RenovateConfig, migratedConfig: RenovateConfig) {
super('binarySource', originalConfig, migratedConfig);
}
readonly propertyName = 'binarySource';

override run(): void {
if (this.originalConfig.binarySource === 'auto') {
this.migratedConfig.binarySource = 'global';
override run(value): void {
if (value === 'auto') {
this.rewrite('global');
}
}
}
22 changes: 13 additions & 9 deletions lib/config/migrations/custom/go-mod-tidy-migration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@ import { MigrationsService } from '../migrations-service';

describe('config/migrations/custom/go-mod-tidy-migration', () => {
it('should add postUpdateOptions option when true', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
gomodTidy: true,
postUpdateOptions: ['test'],
});

expect(migratedConfig).not.toHaveProperty('gomodTidy');
expect(migratedConfig.postUpdateOptions).toEqual(['test', 'gomodTidy']);
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({
postUpdateOptions: ['test', 'gomodTidy'],
});
});

it('should handle case when postUpdateOptions is not defined ', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
gomodTidy: true,
});

expect(migratedConfig).not.toHaveProperty('gomodTidy');
expect(migratedConfig.postUpdateOptions).toEqual(['gomodTidy']);
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({
postUpdateOptions: ['gomodTidy'],
});
});

it('should only remove when false', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
gomodTidy: false,
});

expect(migratedConfig).not.toHaveProperty('gomodTidy');
expect(migratedConfig).not.toHaveProperty('postUpdateOptions');
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({});
});
});
17 changes: 8 additions & 9 deletions lib/config/migrations/custom/go-mod-tidy-migration.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import type { RenovateConfig } from '../../types';
import { AbstractMigration } from '../base/abstract-migration';

export class GoModTidyMigration extends AbstractMigration {
constructor(originalConfig: RenovateConfig, migratedConfig: RenovateConfig) {
super('gomodTidy', originalConfig, migratedConfig);
}
readonly propertyName = 'gomodTidy';

override run(): void {
const { gomodTidy, postUpdateOptions } = this.originalConfig;
override run(value): void {
const postUpdateOptions = this.get('postUpdateOptions');

this.delete(this.propertyName);

if (gomodTidy) {
this.migratedConfig.postUpdateOptions ??= postUpdateOptions ?? [];
this.migratedConfig.postUpdateOptions.push('gomodTidy');
if (value) {
const newPostUpdateOptions = Array.isArray(postUpdateOptions)
? postUpdateOptions.concat(['gomodTidy'])
: ['gomodTidy'];
this.setHard('postUpdateOptions', newPostUpdateOptions);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { MigrationsService } from '../migrations-service';

describe('config/migrations/custom/ignore-node-modules-migration', () => {
it('should migrate to ignorePaths', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
ignoreNodeModules: true,
});

expect(migratedConfig.ignorePaths).toEqual(['node_modules/']);
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({ ignorePaths: ['node_modules/'] });
});
});
11 changes: 3 additions & 8 deletions lib/config/migrations/custom/ignore-node-modules-migration.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import type { RenovateConfig } from '../../types';
import { AbstractMigration } from '../base/abstract-migration';

export class IgnoreNodeModulesMigration extends AbstractMigration {
constructor(originalConfig: RenovateConfig, migratedConfig: RenovateConfig) {
super('ignoreNodeModules', originalConfig, migratedConfig);
}
readonly propertyName = 'ignoreNodeModules';

override run(): void {
override run(value): void {
this.delete(this.propertyName);

this.migratedConfig.ignorePaths = this.originalConfig.ignoreNodeModules
? ['node_modules/']
: [];
this.setSafely('ignorePaths', value ? ['node_modules/'] : []);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { MigrationsService } from '../migrations-service';

describe('config/migrations/custom/required-status-checks-migration', () => {
it('should migrate requiredStatusChecks=null to ignoreTests=true', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
requiredStatusChecks: null,
});

expect(migratedConfig).not.toHaveProperty('requiredStatusChecks');
expect(migratedConfig.ignoreTests).toBeTrue();
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({
ignoreTests: true,
});
});
});
11 changes: 4 additions & 7 deletions lib/config/migrations/custom/required-status-checks-migration.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import type { RenovateConfig } from '../../types';
import { AbstractMigration } from '../base/abstract-migration';

export class RequiredStatusChecksMigration extends AbstractMigration {
constructor(originalConfig: RenovateConfig, migratedConfig: RenovateConfig) {
super('requiredStatusChecks', originalConfig, migratedConfig);
}
readonly propertyName = 'requiredStatusChecks';

override run(): void {
override run(value): void {
this.delete(this.propertyName);

if (this.originalConfig.requiredStatusChecks === null) {
this.migratedConfig.ignoreTests = true;
if (value === null) {
this.setSafely('ignoreTests', true);
}
}
}
22 changes: 14 additions & 8 deletions lib/config/migrations/custom/trust-level-migration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@ import { MigrationsService } from '../migrations-service';

describe('config/migrations/custom/trust-level-migration', () => {
it('should handle hight level', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
trustLevel: 'high',
});

expect(migratedConfig.allowCustomCrateRegistries).toBeTrue();
expect(migratedConfig.allowScripts).toBeTrue();
expect(migratedConfig.exposeAllEnv).toBeTrue();
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({
allowCustomCrateRegistries: true,
allowScripts: true,
exposeAllEnv: true,
});
});

it('should not rewrite provided properties', () => {
const migratedConfig = MigrationsService.run({
const { isMigrated, migratedConfig } = MigrationsService.run({
allowCustomCrateRegistries: false,
allowScripts: false,
exposeAllEnv: false,
trustLevel: 'high',
});

expect(migratedConfig.allowCustomCrateRegistries).toBeFalse();
expect(migratedConfig.allowScripts).toBeFalse();
expect(migratedConfig.exposeAllEnv).toBeFalse();
expect(isMigrated).toBeTrue();
expect(migratedConfig).toEqual({
allowCustomCrateRegistries: false,
allowScripts: false,
exposeAllEnv: false,
});
});
});
18 changes: 6 additions & 12 deletions lib/config/migrations/custom/trust-level-migration.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import type { RenovateConfig } from '../../types';
import { AbstractMigration } from '../base/abstract-migration';

export class TrustLevelMigration extends AbstractMigration {
constructor(originalConfig: RenovateConfig, migratedConfig: RenovateConfig) {
super('trustLevel', originalConfig, migratedConfig);
}
readonly propertyName = 'trustLevel';

override run(): void {
override run(value): void {
this.delete(this.propertyName);

if (this.originalConfig.trustLevel === 'high') {
this.migratedConfig.allowCustomCrateRegistries =
this.originalConfig.allowCustomCrateRegistries ?? true;
this.migratedConfig.allowScripts =
this.originalConfig.allowScripts ?? true;
this.migratedConfig.exposeAllEnv =
this.originalConfig.exposeAllEnv ?? true;
if (value === 'high') {
this.setSafely('allowCustomCrateRegistries', true);
this.setSafely('allowScripts', true);
this.setSafely('exposeAllEnv', true);
}
}
}
Loading