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

fix: updateGitTagRefs not working for versions like 0.1.2+3 #456

Merged
merged 2 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions packages/melos/lib/src/commands/version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ mixin _VersionMixin on _RunMixin {
await writeTextFileAsync(pubspec, updatedContents);
}

Future<void> _setDependentPackageVersionConstraint(
Future<void> _setDependencyVersionForDependentPackage(
Package package,
String dependencyName,
Version version,
Expand Down Expand Up @@ -429,7 +429,8 @@ mixin _VersionMixin on _RunMixin {
// specified version.
// For example, ^1.2.3 is equivalent to '>=1.2.3 <2.0.0', and ^0.1.2 is
// equivalent to '>=0.1.2 <0.2.0'.
var versionConstraint = VersionConstraint.compatibleWith(version);
var versionConstraint =
VersionConstraint.compatibleWith(version) as VersionRange;

// For nullsafety releases we use a >=currentVersion <nextMajorVersion
// constraint to allow nullsafety prerelease id versions to function similar
Expand Down Expand Up @@ -457,28 +458,30 @@ mixin _VersionMixin on _RunMixin {
Future<void> _setDependencyVersionForPackage(
Package package,
String dependencyName,
VersionConstraint dependencyVersion,
VersionRange dependencyVersion,
MelosWorkspace workspace,
) async {
if (package.pubSpec.dependencies.containsKey(dependencyName) &&
package.pubSpec.dependencies[dependencyName] is! GitReference &&
package.pubSpec.dependencies[dependencyName] is! HostedReference &&
package.pubSpec.dependencies[dependencyName]
is! ExternalHostedReference) {
logger.trace(
final dependencyReference = package.pubSpec.dependencies[dependencyName];
final devDependencyReference =
package.pubSpec.devDependencies[dependencyName];

if (dependencyReference != null &&
dependencyReference is! GitReference &&
dependencyReference is! HostedReference &&
dependencyReference is! ExternalHostedReference) {
logger.warning(
'Skipping updating dependency $dependencyName for package '
'${package.name} - '
'the version is a Map definition and is most likely a dependency that '
'is importing from a path or git remote.',
);
return;
}
if (package.pubSpec.devDependencies.containsKey(dependencyName) &&
package.pubSpec.devDependencies[dependencyName] is! GitReference &&
package.pubSpec.devDependencies[dependencyName] is! HostedReference &&
package.pubSpec.devDependencies[dependencyName]
is! ExternalHostedReference) {
logger.trace(
if (devDependencyReference != null &&
devDependencyReference is! GitReference &&
devDependencyReference is! HostedReference &&
devDependencyReference is! ExternalHostedReference) {
logger.warning(
'Skipping updating dev dependency $dependencyName for package '
'${package.name} - '
'the version is a Map definition and is most likely a dependency that '
Expand All @@ -490,38 +493,35 @@ mixin _VersionMixin on _RunMixin {
final pubspec = pubspecPathForDirectory(package.path);
final contents = await readTextFileAsync(pubspec);

final isExternalHostedReference = package
.pubSpec.dependencies[dependencyName] is ExternalHostedReference ||
package.pubSpec.devDependencies[dependencyName]
is ExternalHostedReference;

final gitReference =
package.pubSpec.dependencies[dependencyName] is GitReference ||
package.pubSpec.devDependencies[dependencyName] is GitReference;
final isExternalHostedReference =
dependencyReference is ExternalHostedReference ||
devDependencyReference is ExternalHostedReference;
final isGitReference = dependencyReference is GitReference ||
devDependencyReference is GitReference;

var updatedContents = contents;
if (isExternalHostedReference) {
updatedContents = contents.replaceAllMapped(
hostedDependencyVersionReplaceRegex(dependencyName), (Match match) {
return '${match.group(1)}$dependencyVersion';
});
} else if (gitReference &&
hostedDependencyVersionReplaceRegex(dependencyName),
(match) => '${match.group(1)}$dependencyVersion',
);
} else if (isGitReference &&
workspace.config.commands.version.updateGitTagRefs) {
updatedContents = contents.replaceAllMapped(
dependencyTagReplaceRegex(dependencyName), (Match match) {
return '${match.group(1)}$dependencyName-'
'v${dependencyVersion.toString().substring(1)}';
});
dependencyTagReplaceRegex(dependencyName),
(match) => '${match.group(1)}$dependencyName-'
'v${dependencyVersion.min ?? dependencyVersion.max!}',
);
} else {
updatedContents = contents.replaceAllMapped(
dependencyVersionReplaceRegex(dependencyName), (Match match) {
return '${match.group(1)}$dependencyVersion';
});
dependencyVersionReplaceRegex(dependencyName),
(match) => '${match.group(1)}$dependencyVersion',
);
}

// Sanity check that contents actually changed.
if (contents == updatedContents) {
logger.trace(
logger.warning(
'Failed to update dependency $dependencyName version to '
'$dependencyVersion for package ${package.name}, '
'you should probably report this issue with a copy of your '
Expand Down Expand Up @@ -625,7 +625,7 @@ mixin _VersionMixin on _RunMixin {
...pendingPackageUpdate.package.dependentsInWorkspace.values,
...pendingPackageUpdate.package.devDependentsInWorkspace.values
], (Package package) {
return _setDependentPackageVersionConstraint(
return _setDependencyVersionForDependentPackage(
package,
pendingPackageUpdate.package.name,
// Note if we're not updating dependent versions then we use the
Expand Down Expand Up @@ -654,7 +654,7 @@ mixin _VersionMixin on _RunMixin {
await Future.wait(
workspace.config.commands.version.aggregateChangelogs
.map((changelogConfig) {
return writeAggregateChangelog(
return _writeAggregateChangelog(
workspace,
changelogConfig,
pendingPackageUpdates,
Expand All @@ -664,7 +664,7 @@ mixin _VersionMixin on _RunMixin {
}
}

Future<void> writeAggregateChangelog(
Future<void> _writeAggregateChangelog(
MelosWorkspace workspace,
AggregateChangelogConfig config,
List<MelosPendingPackageUpdate> pendingPackageUpdates,
Expand Down
16 changes: 9 additions & 7 deletions packages/melos/lib/src/package.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,31 +83,33 @@ enum PackageType {
flutterApp,
}

// https://regex101.com/r/RAdBOn/3
RegExp versionReplaceRegex = RegExp(
r'''^(version\s?:\s*?['"]?)(?<version>[-\d\.+\w_]{5,})(.*$)''',
r'''^(version\s?:\s*?['"]?)(?<version>[\w\-.+_]{5,})(.*$)''',
multiLine: true,
);

// https://regex101.com/r/sY3jXt/2/
const _versionRegExp = r'''\d+\.\d+\.\d+[\w\-.+_]*''';

const _versionConstraintRegExp =
r"""(?<version>any|["'^<>=]*\d+\.\d+\.\d+['"<>=\w\-.+_]*)""";

RegExp dependencyVersionReplaceRegex(String dependencyName) {
return RegExp(
'''(?<dependency>^\\s+$dependencyName\\s?:\\s?)(?!\$)(?<version>any|["'^<>=]*\\d\\.\\d\\.\\d['"._\\s<>=\\d-\\w+]*)\$''',
'''(?<dependency>^\\s+$dependencyName\\s?:\\s?)(?!\$)$_versionConstraintRegExp''',
multiLine: true,
);
}

// https://regex101.com/r/HIeQaI/1
RegExp hostedDependencyVersionReplaceRegex(String dependencyName) {
return RegExp(
'''(^[ \t]*?(?<dependency>$dependencyName)[ \\t]*?:[ \\t]*?[\\s\\S]*?[ \\t]*?version:[ \\t]*?)(?<version>any|\\^.*|["'^<>=]*\\d\\.\\d\\.\\d['"._ \\t<>=\\d-\\w+]*|\$)\$''',
'''(^[ \t]*?(?<dependency>$dependencyName)[ \\t]*?:[ \\t]*?[\\s\\S]*?[ \\t]*?version:[ \\t]*?)$_versionConstraintRegExp''',
multiLine: true,
);
}

RegExp dependencyTagReplaceRegex(String dependencyName) {
return RegExp(
'''(?<tag_ref>^\\s+ref\\s?:\\s?)(?<opening_quote>["']?)(?<tag>$dependencyName-v[\\d]+\\.[\\d]+\\.[\\d]+)(?<closing_quote>['"]?)\$''',
'''(?<tag_ref>^\\s+ref\\s?:\\s?)(?<opening_quote>["']?)(?<tag>$dependencyName-v$_versionRegExp)(?<closing_quote>['"]?)''',
multiLine: true,
);
}
Expand Down
106 changes: 106 additions & 0 deletions packages/melos/test/package_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:glob/glob.dart';
import 'package:http/http.dart' as http;
import 'package:melos/melos.dart';
import 'package:melos/src/common/http.dart';
import 'package:melos/src/package.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:pub_semver/pub_semver.dart';
Expand All @@ -23,6 +24,36 @@ const pubPackageJson = '''
''';

void main() {
group('replace version RegExp', () {
const testedVersions = [
'0.1.2+3',
'1.2.3+4',
'1.2.3-dev',
'1.2.3-dev.4',
'0.1.2',
'1.2.3',
'10.0.0',
'0.10.0',
'0.0.10',
];
final testedVersionRanges =
testedVersions.map((version) => '^$version').toList();

group('dependencyVersion', () {
testedVersions.forEach(testDependencyVersionReplaceRegex);
testedVersionRanges.forEach(testDependencyVersionReplaceRegex);
});

group('hostedDependencyVersion', () {
testedVersions.forEach(testHostedDependencyVersionReplaceRegex);
testedVersionRanges.forEach(testHostedDependencyVersionReplaceRegex);
});

group('dependencyTag', () {
testedVersions.forEach(testDependencyTagReplaceRegex);
});
});

group('MelosPackage', () {
final httpClientMock = HttpClientMock();
late MelosWorkspace workspace;
Expand Down Expand Up @@ -197,3 +228,78 @@ void main() {
});
});
}

void testDependencyVersionReplaceRegex(String version) {
test(version, () {
const dependencyName = 'foo';
const newVersion = '9.9.9';

final regExp = dependencyVersionReplaceRegex(dependencyName);

final input = '''
dependencies:
$dependencyName: $version
''';
final output = input.replaceAllMapped(
regExp,
(match) => '${match.group(1)}$newVersion',
);

expect(output, '''
dependencies:
$dependencyName: $newVersion
''');
});
}

void testHostedDependencyVersionReplaceRegex(String version) {
test(version, () {
const dependencyName = 'foo';
const newVersion = '9.9.9';

final regExp = hostedDependencyVersionReplaceRegex(dependencyName);

final input = '''
dependencies:
$dependencyName:
version: $version
''';
final output = input.replaceAllMapped(
regExp,
(match) => '${match.group(1)}$newVersion',
);

expect(output, '''
dependencies:
$dependencyName:
version: $newVersion
''');
});
}

void testDependencyTagReplaceRegex(String version) {
test(version, () {
const dependencyName = 'foo';
const newVersion = '9.9.9';

final regExp = dependencyTagReplaceRegex(dependencyName);

final input = '''
dependencies:
$dependencyName:
git:
ref: $dependencyName-v$version
''';
final output = input.replaceAllMapped(
regExp,
(match) => '${match.group(1)}$dependencyName-v$newVersion',
);

expect(output, '''
dependencies:
$dependencyName:
git:
ref: $dependencyName-v$newVersion
''');
});
}