diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index c126ca5..2277315 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -10,7 +10,6 @@ component { "changelogFileName" = "CHANGELOG.md", "targetBranch" = "master", "buildCommitMessage" = "__SEMANTIC RELEASE VERSION UPDATE__", - "plugins-VerifyConditions" = "GitHubActionsConditionsVerifier@commandbox-semantic-release", "plugins-VerifyConditions-buildTimeout" = 600, // seconds "plugins-VerifyConditions-pollingInterval" = 5, // seconds @@ -25,55 +24,59 @@ component { "plugins-CommitArtifacts" = "GitHubArtifactsCommitter@commandbox-semantic-release", "plugins-CommitArtifacts-authorName" = "CommandBox Semantic Release", "plugins-CommitArtifacts-authorEmail" = "csr@example.com", + "plugins-CommitArtifacts-commitBoxJson" = true, "plugins-PublishRelease" = "ForgeBoxReleasePublisher@commandbox-semantic-release", "plugins-PublicizeRelease" = "GitHubReleasePublicizer@commandbox-semantic-release" }; - binder.map( "TravisConditionsVerifier@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.TravisConditionsVerifier" ); - binder.map( "NullConditionsVerifier@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.NullConditionsVerifier" ); - binder.map( "GitLabConditionsVerifier@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.GitLabConditionsVerifier" ); - binder.map( "GitHubActionsConditionsVerifier@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.GitHubActionsConditionsVerifier" ); - binder.map( "ForgeBoxReleaseFetcher@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.ForgeBoxReleaseFetcher" ); - binder.map( "JGitCommitsRetriever@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.JGitCommitsRetriever" ); binder.map( "ConventionalChangelogParser@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.ConventionalChangelogParser" ); - binder.map( "EmojiLogCommitParser@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.EmojiLogCommitParser" ); - binder.map( "DefaultCommitFilterer@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.DefaultCommitFilterer" ); binder.map( "DefaultCommitAnalyzer@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.DefaultCommitAnalyzer" ); + binder.map( "DefaultCommitFilterer@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.DefaultCommitFilterer" ); binder.map( "EmojiLogCommitAnalyzer@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.EmojiLogCommitAnalyzer" ); - binder.map( "NullReleaseVerifier@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.NullReleaseVerifier" ); - binder.map( "GitHubMarkdownNotesGenerator@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.GitHubMarkdownNotesGenerator" ); + binder.map( "EmojiLogCommitParser@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.EmojiLogCommitParser" ); binder.map( "FileAppendChangelogUpdater@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.FileAppendChangelogUpdater" ); - binder.map( "NullArtifactsCommitter@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.NullArtifactsCommitter" ); - binder.map( "GitHubArtifactsCommitter@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.GitHubArtifactsCommitter" ); + binder.map( "ForgeBoxReleaseFetcher@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.ForgeBoxReleaseFetcher" ); binder.map( "ForgeBoxReleasePublisher@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.ForgeBoxReleasePublisher" ); + binder.map( "GitHubActionsConditionsVerifier@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.GitHubActionsConditionsVerifier" ); + binder.map( "GitHubArtifactsCommitter@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.GitHubArtifactsCommitter" ); + binder.map( "GitHubMarkdownNotesGenerator@commandbox-semantic-release" ). + to( "#moduleMapping#.models.plugins.GitHubMarkdownNotesGenerator" ); binder.map( "GitHubReleasePublicizer@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.GitHubReleasePublicizer" ); - - binder.map( "GitLabConditionsVerifier@commandbox-semantic-release" ) - .to( "#moduleMapping#.models.plugins.GitLabConditionsVerifier" ); binder.map( "GitLabArtifactsCommitter@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.GitLabArtifactsCommitter" ); + binder.map( "GitLabConditionsVerifier@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.GitLabConditionsVerifier" ); binder.map( "GitLabReleaseFetcher@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.GitLabReleaseFetcher" ); binder.map( "GitLabReleasePublicizer@commandbox-semantic-release" ) .to( "#moduleMapping#.models.plugins.GitLabReleasePublicizer" ); + binder.map( "JGitCommitsRetriever@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.JGitCommitsRetriever" ); + binder.map( "NullArtifactsCommitter@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.NullArtifactsCommitter" ); + binder.map( "NullChangelogUpdater@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.NullChangelogUpdater" ); + binder.map( "NullConditionsVerifier@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.NullConditionsVerifier" ); + binder.map( "NullNotesGenerator@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.NullNotesGenerator" ); + binder.map( "NullReleasePublisher@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.NullReleasePublisher" ); + binder.map( "NullReleaseVerifier@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.NullReleaseVerifier" ); + binder.map( "TravisConditionsVerifier@commandbox-semantic-release" ) + .to( "#moduleMapping#.models.plugins.TravisConditionsVerifier" ); } function onLoad() { diff --git a/README.md b/README.md index 4b4e2e3..4450b1f 100644 --- a/README.md +++ b/README.md @@ -359,7 +359,7 @@ a struct for each of the plugin interfaces. Arbitrary keys and values can be set via the command line. ``` -box config set modules.settings.commandbox-semantic-release.plugins-VerifyConditions-buildTimeout=1000 +box config set modules.commandbox-semantic-release.plugins-VerifyConditions-buildTimeout=1000 ``` These values can then be used in your plugins: @@ -392,10 +392,9 @@ You set your custom plugins or settings via CommandBox just prior to calling the after_success: - box install commandbox-semantic-release - box config set endpoints.forgebox.APIToken=${FORGEBOX_TOKEN} - - box config set modules.settings.commandbox-semantic-release.versionPrefix = "" - - box config set modules.settings.commandbox-semantic-release.plugins-GenerateNotes = "MyCustomNotesGenerator@commandbox-semantic-release-custom-notes" + - box config set modules.commandbox-semantic-release.versionPrefix = "" + - box config set modules.commandbox-semantic-release.plugins-GenerateNotes = "MyCustomNotesGenerator@commandbox-semantic-release-custom-notes" - box config set modules.commandbox-semantic-release.plugins-VerifyConditions="GitLabConditionsVerifier@commandbox-semantic-release" - - box config set modules.commandbox-semantic-release.plugins-GenerateNotes="GitHubMarkdownNotesGenerator@commandbox-semantic-release" - box config set modules.commandbox-semantic-release.plugins-CommitArtifacts="GitLabArtifactsCommitter@commandbox-semantic-release" - box config set modules.commandbox-semantic-release.plugins-PublicizeRelease="GitLabReleasePublicizer@commandbox-semantic-release" - box semantic-release diff --git a/commands/semantic-release.cfc b/commands/semantic-release.cfc index 492d3e6..7f4e4d9 100644 --- a/commands/semantic-release.cfc +++ b/commands/semantic-release.cfc @@ -20,7 +20,12 @@ component { property name="PublicizeRelease" inject="PublicizeRelease@commandbox-semantic-release"; property name="targetBranch" inject="commandbox:moduleSettings:commandbox-semantic-release:targetBranch"; - function run( dryRun = false, verbose = false, force = false, targetBranch = variables.targetBranch, preReleaseID = systemSettings.getSystemSetting( "BUILD_VERSION_PRERELEASEID", "" ), buildID = systemSettings.getSystemSetting( "BUILD_VERSION_BUILDID", "" ) ) { + function run( dryRun = false, verbose = false, force = false, targetBranch = variables.targetBranch, preReleaseID = systemSettings.getSystemSetting( "BUILD_VERSION_PRERELEASEID", "" ), buildID = systemSettings.getSystemSetting( "BUILD_VERSION_BUILDID", 0 ) ) { + if( verbose ){ + print.boldWhiteOnBlackLine( "Arguments to Command" ).toConsole(); + print.line( serializeJSON( arguments ) ).toConsole(); + } + if ( dryRun ) { print.line() .boldBlackOnYellowLine( " " ) @@ -33,7 +38,7 @@ component { if ( force ) { print.yellowLine( "Skipping verification checks due to force flag" ).toConsole(); } - else if ( ! VerifyConditions.run( dryRun, verbose ) ) { + else if ( ! VerifyConditions.run( dryRun, verbose, arguments.targetBranch ) ) { print.yellowLine( "Verify conditions check failed — switching to dry run mode." ).toConsole(); arguments.dryRun = true; print.line() @@ -88,7 +93,7 @@ component { .indentedWhite( "Next release type: " ) .line( " #type# ", getTypeColor( type ) ); - var nextVersion = getNextVersionNumber( lastVersion, type, preReleaseID, buildID ); + var nextVersion = getNextVersionNumber( lastVersion, type, arguments.preReleaseID, arguments.buildID ); print.indentedGreen( "✓" ) .indentedWhite( "Next version number: " ) .whiteOnCyanLine( " #nextVersion# " ) @@ -125,7 +130,7 @@ component { .indentedWhiteLine( "Release published" ) .toConsole(); - CommitArtifacts.run( nextVersion, dryRun, verbose, targetBranch ); + CommitArtifacts.run( nextVersion, dryRun, verbose, arguments.targetBranch ); print.indentedGreen( "✓" ) .indentedWhiteLine( "Artifacts committed" ) .toConsole(); @@ -136,7 +141,7 @@ component { getPackageRepositoryURL(), dryRun, verbose, - targetBranch + arguments.targetBranch ); print.indentedGreen( "✓" ) .indentedWhiteLine( "Release publicized" ) @@ -188,15 +193,30 @@ component { } } - private string function getNextVersionNumber( required string lastVersion, required string type, string preReleaseID = "", string buildID = "" ) { + private string function getPackageVersion() { + var path = fileSystemUtil.resolvePath( "" ); + if ( ! packageService.isPackage( path ) ) { + return "0.0.0"; + } + return packageService.readPackageDescriptor( path ).version; + } + + private string function getNextVersionNumber( required string lastVersion, required string type, string preReleaseID = "", string buildID = 0 ) { var versionInfo = semanticVersion.parseVersion( lastVersion ); - versionInfo.preReleaseID = ( len( arguments.preReleaseID ) ? arguments.preReleaseID : versionInfo.preReleaseID ); - versionInfo.buildID = ( len( arguments.buildID ) ? arguments.buildID : versionInfo.buildID ); if ( lastVersion == "0.0.0" ) { - versionInfo.major = 1; - versionInfo.minor = 0; - versionInfo.revision = 0; + var currentPackageVersion = getPackageVersion(); + if ( currentPackageVersion != semanticVersion.parseVersion( currentPackageVersion ).major ) { + versionInfo = semanticVersion.parseVersion( currentPackageVersion ); + } else { + versionInfo.major = 1; + versionInfo.minor = 0; + versionInfo.revision = 0; + versionInfo.preReleaseID = ""; + versionInfo.buildID = 0; + } + versionInfo.preReleaseID = arguments.preReleaseID; + versionInfo.buildID = arguments.buildID; return semanticVersion.getVersionAsString( versionInfo ); } @@ -222,6 +242,12 @@ component { versionInfo.revision += 1; break; } + + print.boldWhiteOnBlackLine( "Version Info" ).toConsole(); + print.table( [ versionInfo ] ).toConsole(); + + versionInfo.preReleaseID = arguments.preReleaseID; + versionInfo.buildID = arguments.buildID; return semanticVersion.getVersionAsString( versionInfo ) } diff --git a/models/plugins/GitHubArtifactsCommitter.cfc b/models/plugins/GitHubArtifactsCommitter.cfc index 67a973d..d7d7021 100644 --- a/models/plugins/GitHubArtifactsCommitter.cfc +++ b/models/plugins/GitHubArtifactsCommitter.cfc @@ -46,8 +46,13 @@ component implements="interfaces.ArtifactsCommitter" { .setName( targetBranch ) .call(); + if( options[ "plugins-CommitArtifacts-commitBoxJson" ] == true ) { + jGit.add() + .addFilePattern( "box.json" ) + .call(); + } + jGit.add() - .addFilePattern( "box.json" ) .addFilePattern( changelogFileName ) .call(); diff --git a/models/plugins/GitLabArtifactsCommitter.cfc b/models/plugins/GitLabArtifactsCommitter.cfc index 0ae8b24..5dbd6e1 100644 --- a/models/plugins/GitLabArtifactsCommitter.cfc +++ b/models/plugins/GitLabArtifactsCommitter.cfc @@ -7,7 +7,8 @@ component implements="interfaces.ArtifactsCommitter" { property name="changelogFileName" inject="commandbox:moduleSettings:commandbox-semantic-release:changelogFileName"; property name="versionPrefix" inject="commandbox:moduleSettings:commandbox-semantic-release:versionPrefix"; property name="targetBranch" inject="commandbox:moduleSettings:commandbox-semantic-release:targetBranch"; - + property name="options" inject="commandbox:moduleSettings:commandbox-semantic-release"; + /** * Set up jGit for the current repository. */ @@ -45,8 +46,13 @@ component implements="interfaces.ArtifactsCommitter" { .setName( targetBranch ) .call(); + if( options[ "plugins-CommitArtifacts-commitBoxJson" ] == true ) { + jGit.add() + .addFilePattern( "box.json" ) + .call(); + } + jGit.add() - .addFilePattern( "box.json" ) .addFilePattern( changelogFileName ) .call(); diff --git a/models/plugins/GitLabReleaseFetcher.cfc b/models/plugins/GitLabReleaseFetcher.cfc index a27e7b9..a2e4e6c 100644 --- a/models/plugins/GitLabReleaseFetcher.cfc +++ b/models/plugins/GitLabReleaseFetcher.cfc @@ -25,12 +25,12 @@ component implements="interfaces.ReleaseFetcher" { ) { cfhttpparam( type="header", - name="PRIVATE-TOKEN", + name="JOB-TOKEN", value="#systemSettings.getSystemSetting( "CI_JOB_TOKEN" )#" ); }; var res = deserializeJSON( httpResponse.filecontent ); - var tag = res.isEmpty() ? "0.0.0" : res.tag_name; + var tag = res.isEmpty() ? "0.0.0" : res[1].tag_name; return left( tag, 1 ) == "v" ? mid( tag, 2, tag.len() - 1 ) : tag; } diff --git a/models/plugins/GitLabReleasePublicizer.cfc b/models/plugins/GitLabReleasePublicizer.cfc index 060a17b..949823c 100644 --- a/models/plugins/GitLabReleasePublicizer.cfc +++ b/models/plugins/GitLabReleasePublicizer.cfc @@ -33,13 +33,18 @@ component implements="interfaces.ReleasePublicizer" { ) { cfhttpparam( type="header", - name="PRIVATE-TOKEN", + name="Content-Type", + value="application/json" + ); + cfhttpparam( + type="header", + name="JOB-TOKEN", value="#systemSettings.getSystemSetting( "CI_JOB_TOKEN" )#" ); cfhttpparam( type = "body", value = serializeJSON( { "name": "#versionPrefix##nextVersion#", "tag_name": "#versionPrefix##nextVersion#", - "ref": targetBranch, + "ref": arguments.targetBranch, "description": notes } ) ); } diff --git a/models/plugins/NullChangelogUpdater.cfc b/models/plugins/NullChangelogUpdater.cfc new file mode 100644 index 0000000..6dac977 --- /dev/null +++ b/models/plugins/NullChangelogUpdater.cfc @@ -0,0 +1,29 @@ +component implements="interfaces.ChangelogUpdater" { + + property name="print" inject="PrintBuffer"; + + /** + * Updates the current changelog with the new notes. + * + * @notes The notes for the new release. + * @dryRun Flag to indicate a dry run of the release. + * @verbose Flag to indicate printing out extra information. + */ + public void function run( + required string notes, + required string nextVersion, + boolean dryRun = false, + boolean verbose = false + ) { + + if ( verbose ) { + print.line() + .indented() + .boldBlackOnYellowLine( " NULL CHANGELOG UPDATER - NO CHANGELOG WRITTEN " ) + .line() + .toConsole(); + } + + } + +} diff --git a/models/plugins/NullNotesGenerator.cfc b/models/plugins/NullNotesGenerator.cfc new file mode 100644 index 0000000..feab062 --- /dev/null +++ b/models/plugins/NullNotesGenerator.cfc @@ -0,0 +1,28 @@ +component implements="interfaces.NotesGenerator" { + + /** + * Generates markdown notes for the new release on GitHub + * + * @lastVersion The last version of the package. + * @nextVersion The next version of the package. + * @commits An array of commits between the two versions. + * @type The type of the next release: major, minor, or patch. + * @repositoryUrl The url of the remote repository. + * @dryRun Flag to indicate a dry run of the release. + * @verbose Flag to indicate printing out extra information. + * + * @return A string containing the new notes for the release. + */ + public string function run( + required string lastVersion, + required string nextVersion, + required array commits, + required string type, + required string repositoryUrl, + boolean dryRun = false, + boolean verbose = true + ) { + return ""; + } + +}