@ -1,11 +1,12 @@
/ / ignore_for_file: avoid_print
/ / ignore_for_file: avoid_print
import ' dart:convert ' show jsonDecode , jsonEncode ;
import ' dart:io ' show File , exit ;
import ' dart:io ' show File , exit ;
import ' package:yaml_edit/yaml_edit.dart ' ;
import ' package:yaml_edit/yaml_edit.dart ' show YamlEditor ;
/ / / The list of the packages that which will be used to update the ` CHANGELOG . md `
/ / / The list of the packages that which will be used to update the ` CHANGELOG . md `
/ / / and ` README . md ` files for all the packages
/ / / and the version in the ` pubspec . yaml ` for all the packages
final _packages = [
final _packages = [
' ./ ' ,
' ./ ' ,
' ./dart_quill_delta ' ,
' ./dart_quill_delta ' ,
@ -15,51 +16,120 @@ final _packages = [
' ./quill_pdf_converter ' ,
' ./quill_pdf_converter ' ,
] ;
] ;
const _usage = ' Usage: ./script <version> <changelog-version-content> ' ;
/ / / A script that should run in the root folder and not inside any other folder
/ / / A script that should run in the root folder and not inside any other folder
/ / / it has one task , which update the version for ` pubspec . yaml ` and ` CHANGELOG . md ` for all the packages
/ / / it has one task , which update the version for ` pubspec . yaml ` and
/ / / since we have only one CHANGELOG . md file and version , previously we had different ` CHANGELOG . md ` and ` pubspec . yaml ` package version
/ / / ` CHANGELOG . md ` for all the packages , the ` CHANGELOG . md ` files will be
/ / / for each package
/ / / generated from a json file which is the source of the data
/ / /
/ / / the script can be used with the following args [ _usage ]
/ / / it will require a version and the changes for that version ( as a [ String ] )
/ / / if the version exist then it will modify it with the new changes
/ / / if not , then will be added at the start
/ / /
/ / /
/ / / the new version should be passed in the [ args ] , the script accept only one argument
/ / / the source file ( which used to generate the ` CHANGELOG . md ` files ) will
/ / / also updated with the new change
/ / /
/ / / this script designed to run in CI to automate the process of updating
/ / / the package
Future < void > main ( List < String > args ) async {
Future < void > main ( List < String > args ) async {
if ( args . isEmpty ) {
if ( args . isEmpty | | args . length < 2 ) {
print ( ' Missing required version argument. Usage: ./script <new-version> ' ) ;
print ( ' Missing required arguments. $ _usage ' ) ;
exit ( 1 ) ;
exit ( 1 ) ;
}
}
if ( args . length > 1 ) {
if ( args . length > 2 ) {
print ( ' Too many arguments. Usage: ./script <new-version> ' ) ;
print ( ' Too many arguments. $ _usage ' ) ;
exit ( 1 ) ;
exit ( 1 ) ;
}
}
final new Version = args [ 0 ] ;
final passed Version = args [ 0 ] ;
if ( new Version. isEmpty ) {
if ( passed Version. isEmpty ) {
print ( ' The new version is empty. Usage: ./script <new-version> ' ) ;
print ( ' The version is empty. $ _usage ' ) ;
exit ( 1 ) ;
exit ( 1 ) ;
}
}
final passedVersionContent = args [ 1 ] ;
if ( passedVersionContent . isEmpty ) {
print ( ' The version content is empty. $ _usage ' ) ;
exit ( 1 ) ;
}
/ / A file that will be used to build the ` CHANGELOG . md ` files
/ / the data format is in Json
final sourceChangeLogFile = File ( ' ./CHANGELOG.json ' ) ;
await _replaceVersion (
sourceChangeLogFile: sourceChangeLogFile ,
version: passedVersion ,
versionContent: passedVersionContent ,
) ;
final sourceChangeLog = jsonDecode ( await sourceChangeLogFile . readAsString ( ) )
as Map < String , Object ? > ;
final generatedChangeLogBuffer = StringBuffer ( )
. . write (
' <!-- This file is auto-generated from ${ sourceChangeLogFile . uri . pathSegments . last } using a script - Manual changes will be overwritten --> \n \n ' ,
)
. . write ( ' # Changelog \n \n ' )
. . write (
' All notable changes to this project will be documented in this file. \n \n ' ,
) ;
sourceChangeLog . forEach ( ( version , versionContent ) {
generatedChangeLogBuffer
. . write ( ' ## $ version \n \n ' )
. . write ( ' $ versionContent \n \n ' ) ;
} ) ;
for ( final packagePath in _packages ) {
for ( final packagePath in _packages ) {
await updatePubspecYamlFile ( ' $ packagePath /pubspec.yaml ' ,
await _updatePubspecYamlFile (
newVersion: newVersion ) ;
pubspecYamlPath: ' $ packagePath /pubspec.yaml ' ,
if ( packagePath ! = _packages . first ) {
newVersion: passedVersion ,
updateChangelogMD ( ' $ packagePath /CHANGELOG.md ' ) ;
) ;
}
_updateChangelog (
changeLogFilePath: ' $ packagePath /CHANGELOG.md ' ,
changeLogContent: generatedChangeLogBuffer . toString ( ) ,
) ;
}
}
}
}
/ / / Replace the version content by the version if it exist
/ / / or add the version at the start of the map if it doesn ' t exist
/ / /
/ / / then save the changes to the [ sourceChangeLogFile ]
Future < void > _replaceVersion ( {
required File sourceChangeLogFile ,
required String version ,
required String versionContent ,
} ) async {
final sourceChangeLog = jsonDecode ( await sourceChangeLogFile . readAsString ( ) )
as Map < String , Object ? > ;
if ( sourceChangeLog [ version ] ! = null ) {
sourceChangeLog [ version ] = versionContent ;
} else {
/ / A workaround to add the new item at the start , the order matter
/ / becase later it will generate the markdown files
final newMap = < String , Object ? > { version: versionContent } ;
sourceChangeLog
. . forEach ( ( key , value ) = > newMap [ key ] = value )
. . clear ( )
. . addAll ( newMap ) ;
}
await sourceChangeLogFile . writeAsString ( jsonEncode ( sourceChangeLog ) ) ;
}
/ / / Update the [ pubspecYamlPath ] file to update the ` version ` property from [ newVersion ]
/ / / Update the [ pubspecYamlPath ] file to update the ` version ` property from [ newVersion ]
Future < void > updatePubspecYamlFile (
Future < void > _ updatePubspecYamlFile( {
String pubspecYamlPath , {
required String pubspecYamlPath ,
required String newVersion ,
required String newVersion ,
} ) async {
} ) async {
final file = File ( pubspecYamlPath ) ;
final file = File ( pubspecYamlPath ) ;
final yaml = await file . readAsString ( ) ;
final yaml = await file . readAsString ( ) ;
final yamlEditor = YamlEditor ( yaml ) . . update ( [ ' version ' ] , newVersion ) ;
final yamlEditor = YamlEditor ( yaml ) . . update ( [ ' version ' ] , newVersion ) ;
await file . writeAsString ( yamlEditor . toString ( ) ) ;
await file . writeAsString ( yamlEditor . toString ( ) ) ;
print ( yamlEditor . toString ( ) ) ;
}
}
/ / / Read the contents of the root ` CHANGELOG . md ` file and copy it
/ / / Copy [ changeLogContent ] and overwrite it to the [ changeLogFilePath ]
/ / / to the [ changeLogFilePath ]
Future < void > _updateChangelog ( {
Future < void > updateChangelogMD ( String changeLogFilePath ) async {
required String changeLogFilePath ,
final rootChangeLogFileContent = await File ( ' ./CHANGELOG.md ' ) . readAsString ( ) ;
required String changeLogContent ,
} ) async {
final changeLogFile = File ( changeLogFilePath ) ;
final changeLogFile = File ( changeLogFilePath ) ;
await changeLogFile . writeAsString ( rootChangeLogFileContent ) ;
await changeLogFile . writeAsString ( changeLog Content) ;
}
}