@@ -40,6 +40,7 @@ var readFileSync = require( '@stdlib/fs/read-file' ).sync;
4040var readJSON = require ( '@stdlib/fs/read-json' ) . sync ;
4141var existsSync = require ( '@stdlib/fs/exists' ) . sync ;
4242var hasOwnProp = require ( '@stdlib/assert/has-own-property' ) ;
43+ var objectKeys = require ( '@stdlib/utils/keys' ) ;
4344var contains = require ( '@stdlib/assert/contains' ) ;
4445var memoize = require ( '@stdlib/utils/memoize' ) ;
4546var repeat = require ( '@stdlib/string/repeat' ) ;
@@ -59,6 +60,8 @@ var namespaceDeps = require( '@stdlib/_tools/pkgs/namespace-deps' );
5960var depList = require ( '@stdlib/_tools/pkgs/dep-list' ) ;
6061var name2standalone = require ( '@stdlib/_tools/pkgs/name2standalone' ) ;
6162var generateChangelog = require ( '@stdlib/_tools/changelog/generate' ) ;
63+ var recommendVersionBump = require ( '@stdlib/_tools/changelog/recommend-version-bump' ) ;
64+ var parseCommits = require ( '@stdlib/_tools/changelog/parse-commits' ) ;
6265var toposort = require ( '@stdlib/_tools/pkgs/toposort' ) . sync ;
6366var ENV = require ( '@stdlib/process/env' ) ;
6467
@@ -345,6 +348,88 @@ var memoizedNPMversionForDevDeps = memoize( npmVersion );
345348
346349// FUNCTIONS //
347350
351+ /**
352+ * Returns the date of the latest npm release for a package.
353+ *
354+ * @private
355+ * @param {string } pkg - package name
356+ * @returns {(string|null) } ISO date string or null
357+ */
358+ function getLatestReleaseDate ( pkg ) {
359+ var latestDate ;
360+ var versions ;
361+ var command ;
362+ var version ;
363+ var result ;
364+ var date ;
365+ var map ;
366+ var i ;
367+
368+ command = 'npm view ' + pkg + ' time --json' ;
369+ try {
370+ result = shell ( command ) . toString ( ) ;
371+ map = JSON . parse ( result ) ;
372+ latestDate = null ;
373+ versions = objectKeys ( map ) ;
374+ for ( i = 0 ; i < versions . length ; i ++ ) {
375+ version = versions [ i ] ;
376+ if (
377+ version !== 'created' &&
378+ version !== 'modified' &&
379+ version !== 'unpublished' &&
380+ semver . valid ( version ) &&
381+ ! semver . prerelease ( version )
382+ ) {
383+ date = new Date ( map [ version ] ) ;
384+ if ( ! latestDate || date > latestDate ) {
385+ latestDate = date ;
386+ }
387+ }
388+ }
389+ return ( latestDate ) ? latestDate . toISOString ( ) : null ;
390+ } catch ( error ) {
391+ debug ( 'Encountered an error when attempting to retrieve release dates for package `%s`: %s' , pkg , error . message ) ;
392+ return null ;
393+ }
394+ }
395+
396+ /**
397+ * Determines the release type automatically based on commits since the last release.
398+ *
399+ * @private
400+ * @param {string } pkg - package name (without @stdlib/ prefix)
401+ * @returns {(string|null) } release type (`minor`, `patch`) or null if no release needed
402+ */
403+ function determineAutoReleaseType ( pkg ) {
404+ var latestReleaseDate ;
405+ var standalonePkg ;
406+ var commitOpts ;
407+ var commits ;
408+ var bump ;
409+
410+ standalonePkg = name2standalone ( '@stdlib/' + pkg ) ;
411+ latestReleaseDate = getLatestReleaseDate ( standalonePkg ) ;
412+
413+ commitOpts = {
414+ 'dir' : join ( mainDir , 'lib/node_modules' , '@stdlib' , pkg )
415+ } ;
416+ if ( latestReleaseDate ) {
417+ commitOpts . flags = {
418+ 'after' : latestReleaseDate
419+ } ;
420+ }
421+ commits = parseCommits ( commitOpts ) ;
422+
423+ // Determine the recommended version bump:
424+ bump = recommendVersionBump ( commits ) ;
425+
426+ // Cap major bumps to minor (we don't want to increase major release line for now):
427+ if ( bump === 'major' ) {
428+ bump = 'minor' ;
429+ }
430+ return bump ;
431+ }
432+
348433/**
349434* Returns a cron schedule for a given package.
350435*
@@ -695,7 +780,18 @@ function publish( pkg, clbk ) {
695780 return invokeCallback ( null , 'skipped' ) ;
696781 }
697782
698- if ( flags [ 'release-type' ] ) {
783+ if ( flags [ 'release-type' ] === 'auto' ) {
784+ // Case: auto-determine release type based on commits...
785+ releaseType = determineAutoReleaseType ( pkg ) ;
786+ if ( releaseType ) {
787+ changelog = generateChangelog ( '@stdlib/' + pkg , {
788+ 'releaseType' : releaseType
789+ } ) ;
790+ } else {
791+ // No release needed, generate changelog without release type...
792+ changelog = generateChangelog ( '@stdlib/' + pkg ) ;
793+ }
794+ } else if ( flags [ 'release-type' ] ) {
699795 // Case: release type specified, so we generate a changelog for the specified release type...
700796 changelog = generateChangelog ( '@stdlib/' + pkg , {
701797 'releaseType' : flags [ 'release-type' ]
@@ -1087,7 +1183,7 @@ function publish( pkg, clbk ) {
10871183
10881184 // Write the current date to the `.keepalive` file...
10891185 if ( flags [ 'keep-alive' ] ) {
1090- fs . writeFileSync ( join ( dist , '.github' , '.keepalive' ) , new Date ( ) . toISOString ( ) + '\n' ) ;
1186+ fs . writeFileSync ( join ( dist , '.github' , '.keepalive' ) , new Date ( ) . toISOString ( ) + '\n' ) ; // eslint-disable-line no-restricted-syntax
10911187 }
10921188
10931189 fs . copyFileSync ( join ( __dirname , 'templates' , 'CODE_OF_CONDUCT.md.txt' ) , join ( dist , 'CODE_OF_CONDUCT.md' ) ) ;
0 commit comments