release-please 16.15.0 → 16.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@
4
4
 
5
5
  [1]: https://www.npmjs.com/package/release-please?activeTab=versions
6
6
 
7
+ ## [16.17.0](https://github.com/googleapis/release-please/compare/v16.16.0...v16.17.0) (2025-02-20)
8
+
9
+
10
+ ### Features
11
+
12
+ * allow date updating in generic strategy ([#2440](https://github.com/googleapis/release-please/issues/2440)) ([3099091](https://github.com/googleapis/release-please/commit/3099091bb6787e49fe36e289db36ac01a71af2c3))
13
+
14
+ ## [16.16.0](https://github.com/googleapis/release-please/compare/v16.15.0...v16.16.0) (2025-02-19)
15
+
16
+
17
+ ### Features
18
+
19
+ * add strategy for R packages ([#2436](https://github.com/googleapis/release-please/issues/2436)) ([2b5ff3b](https://github.com/googleapis/release-please/commit/2b5ff3b5d7b5c8546bb112149908e150e9eba680))
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * **deps:** bump dependency versions ([#2486](https://github.com/googleapis/release-please/issues/2486)) ([6db2fb4](https://github.com/googleapis/release-please/commit/6db2fb48adcdf60f1779601fb36f982e2fb7f6f7))
25
+
7
26
  ## [16.15.0](https://github.com/googleapis/release-please/compare/v16.14.4...v16.15.0) (2024-11-13)
8
27
 
9
28
 
package/README.md CHANGED
@@ -195,6 +195,7 @@ Release Please automates releases for the following flavors of repositories:
195
195
  | `ocaml` | [An OCaml repository, containing 1 or more opam or esy files and a CHANGELOG.md](https://github.com/grain-lang/binaryen.ml) |
196
196
  | `php` | A repository with a composer.json and a CHANGELOG.md |
197
197
  | `python` | [A Python repository, with a setup.py, setup.cfg, CHANGELOG.md](https://github.com/googleapis/python-storage) and optionally a pyproject.toml and a <project>/\_\_init\_\_.py |
198
+ | `R` | A repository with a DESCRIPTION and a NEWS.md |
198
199
  | `ruby` | A repository with a version.rb and a CHANGELOG.md |
199
200
  | `rust` | A Rust repository, with a Cargo.toml (either as a crate or workspace, although note that workspaces require a [manifest driven release](https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md) and the "cargo-workspace" plugin) and a CHANGELOG.md |
200
201
  | `sfdx` | A repository with a [sfdx-project.json](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_config.htm) and a CHANGELOG.md |
@@ -210,6 +210,10 @@ function pullRequestStrategyOptions(yargs) {
210
210
  .option('latest-tag-name', {
211
211
  describe: 'Override the detected latest tag name',
212
212
  type: 'string',
213
+ })
214
+ .option('date-format', {
215
+ describe: 'format in strftime format for updating dates',
216
+ type: 'string',
213
217
  })
214
218
  .middleware(_argv => {
215
219
  const argv = _argv;
@@ -49,6 +49,7 @@ const ocaml_1 = require("./strategies/ocaml");
49
49
  const php_1 = require("./strategies/php");
50
50
  const php_yoshi_1 = require("./strategies/php-yoshi");
51
51
  const python_1 = require("./strategies/python");
52
+ const r_1 = require("./strategies/r");
52
53
  const ruby_1 = require("./strategies/ruby");
53
54
  const ruby_yoshi_1 = require("./strategies/ruby-yoshi");
54
55
  const rust_1 = require("./strategies/rust");
@@ -91,6 +92,7 @@ const releasers = {
91
92
  php: options => new php_1.PHP(options),
92
93
  'php-yoshi': options => new php_yoshi_1.PHPYoshi(options),
93
94
  python: options => new python_1.Python(options),
95
+ r: options => new r_1.R(options),
94
96
  ruby: options => new ruby_1.Ruby(options),
95
97
  'ruby-yoshi': options => new ruby_yoshi_1.RubyYoshi(options),
96
98
  rust: options => new rust_1.Rust(options),
@@ -14,4 +14,4 @@ export { Logger, setLogger } from './util/logger';
14
14
  export { GitHub } from './github';
15
15
  export declare const configSchema: any;
16
16
  export declare const manifestSchema: any;
17
- export declare const VERSION = "16.15.0";
17
+ export declare const VERSION = "16.17.0";
@@ -36,6 +36,6 @@ Object.defineProperty(exports, "GitHub", { enumerable: true, get: function () {
36
36
  exports.configSchema = require('../../schemas/config.json');
37
37
  exports.manifestSchema = require('../../schemas/manifest.json');
38
38
  // x-release-please-start-version
39
- exports.VERSION = '16.15.0';
39
+ exports.VERSION = '16.17.0';
40
40
  // x-release-please-end
41
41
  //# sourceMappingURL=index.js.map
@@ -70,6 +70,7 @@ export interface ReleaserConfig {
70
70
  releaseLabels?: string[];
71
71
  extraLabels?: string[];
72
72
  initialVersion?: string;
73
+ dateFormat?: string;
73
74
  changelogSections?: ChangelogSection[];
74
75
  changelogPath?: string;
75
76
  changelogType?: ChangelogNotesType;
@@ -122,6 +123,7 @@ interface ReleaserConfigJson {
122
123
  'skip-snapshot'?: boolean;
123
124
  'initial-version'?: string;
124
125
  'exclude-paths'?: string[];
126
+ 'date-format'?: string;
125
127
  }
126
128
  export interface ManifestOptions {
127
129
  bootstrapSha?: string;
@@ -145,6 +147,7 @@ export interface ManifestOptions {
145
147
  releaseSearchDepth?: number;
146
148
  commitSearchDepth?: number;
147
149
  logger?: Logger;
150
+ dateFormat?: string;
148
151
  }
149
152
  export interface ReleaserPackageConfig extends ReleaserConfigJson {
150
153
  'package-name'?: string;
@@ -838,6 +838,7 @@ function extractReleaserConfig(config) {
838
838
  skipSnapshot: config['skip-snapshot'],
839
839
  initialVersion: config['initial-version'],
840
840
  excludePaths: config['exclude-paths'],
841
+ dateFormat: config['date-format'],
841
842
  };
842
843
  }
843
844
  /**
@@ -1051,7 +1052,7 @@ async function latestReleaseVersion(github, targetBranch, releaseFilter, config,
1051
1052
  return candidateTagVersion.sort((a, b) => b.compare(a))[0];
1052
1053
  }
1053
1054
  function mergeReleaserConfig(defaultConfig, pathConfig) {
1054
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
1055
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7;
1055
1056
  return {
1056
1057
  releaseType: (_b = (_a = pathConfig.releaseType) !== null && _a !== void 0 ? _a : defaultConfig.releaseType) !== null && _b !== void 0 ? _b : 'node',
1057
1058
  bumpMinorPreMajor: (_c = pathConfig.bumpMinorPreMajor) !== null && _c !== void 0 ? _c : defaultConfig.bumpMinorPreMajor,
@@ -1083,6 +1084,7 @@ function mergeReleaserConfig(defaultConfig, pathConfig) {
1083
1084
  initialVersion: (_4 = pathConfig.initialVersion) !== null && _4 !== void 0 ? _4 : defaultConfig.initialVersion,
1084
1085
  extraLabels: (_5 = pathConfig.extraLabels) !== null && _5 !== void 0 ? _5 : defaultConfig.extraLabels,
1085
1086
  excludePaths: (_6 = pathConfig.excludePaths) !== null && _6 !== void 0 ? _6 : defaultConfig.excludePaths,
1087
+ dateFormat: (_7 = pathConfig.dateFormat) !== null && _7 !== void 0 ? _7 : defaultConfig.dateFormat,
1086
1088
  };
1087
1089
  }
1088
1090
  /**
@@ -52,6 +52,7 @@ export interface BaseStrategyOptions {
52
52
  logger?: Logger;
53
53
  initialVersion?: string;
54
54
  extraLabels?: string[];
55
+ dateFormat?: string;
55
56
  }
56
57
  /**
57
58
  * A strategy is responsible for determining which files are
@@ -80,6 +81,7 @@ export declare abstract class BaseStrategy implements Strategy {
80
81
  readonly componentNoSpace?: boolean;
81
82
  readonly extraFiles: ExtraFile[];
82
83
  readonly extraLabels: string[];
84
+ protected dateFormat: string;
83
85
  readonly changelogNotes: ChangelogNotes;
84
86
  protected changelogSections?: ChangelogSection[];
85
87
  constructor(options: BaseStrategyOptions);
@@ -119,7 +121,7 @@ export declare abstract class BaseStrategy implements Strategy {
119
121
  */
120
122
  buildReleasePullRequest(commits: ConventionalCommit[], latestRelease?: Release, draft?: boolean, labels?: string[], bumpOnlyOptions?: BumpReleaseOptions): Promise<ReleasePullRequest | undefined>;
121
123
  private extraFilePaths;
122
- protected extraFileUpdates(version: Version, versionsMap: VersionsMap): Promise<Update[]>;
124
+ protected extraFileUpdates(version: Version, versionsMap: VersionsMap, dateFormat: string): Promise<Update[]>;
123
125
  protected changelogEmpty(changelogEntry: string): boolean;
124
126
  protected updateVersionsMap(versionsMap: VersionsMap, conventionalCommits: ConventionalCommit[], _newVersion: Version): Promise<VersionsMap>;
125
127
  protected buildNewVersion(conventionalCommits: ConventionalCommit[], latestRelease?: Release): Promise<Version>;
@@ -66,6 +66,7 @@ class BaseStrategy {
66
66
  this.extraFiles = options.extraFiles || [];
67
67
  this.initialVersion = options.initialVersion;
68
68
  this.extraLabels = options.extraLabels || [];
69
+ this.dateFormat = options.dateFormat || generic_1.DEFAULT_DATE_FORMAT;
69
70
  }
70
71
  /**
71
72
  * Return the component for this strategy. This may be a computed field.
@@ -175,7 +176,7 @@ class BaseStrategy {
175
176
  latestVersion: latestRelease === null || latestRelease === void 0 ? void 0 : latestRelease.tag.version,
176
177
  commits: conventionalCommits,
177
178
  });
178
- const updatesWithExtras = (0, composite_1.mergeUpdates)(updates.concat(...(await this.extraFileUpdates(newVersion, versionsMap))));
179
+ const updatesWithExtras = (0, composite_1.mergeUpdates)(updates.concat(...(await this.extraFileUpdates(newVersion, versionsMap, this.dateFormat))));
179
180
  const pullRequestBody = await this.buildPullRequestBody(component, newVersion, releaseNotesBody, conventionalCommits, latestRelease, this.pullRequestHeader, this.pullRequestFooter);
180
181
  return {
181
182
  title: pullRequestTitle,
@@ -209,7 +210,7 @@ class BaseStrategy {
209
210
  return this.github.findFilesByGlobAndRef(extraFile.path, this.targetBranch, this.path);
210
211
  }
211
212
  }
212
- async extraFileUpdates(version, versionsMap) {
213
+ async extraFileUpdates(version, versionsMap, dateFormat) {
213
214
  const extraFileUpdates = [];
214
215
  for (const extraFile of this.extraFiles) {
215
216
  if (typeof extraFile === 'object') {
@@ -220,7 +221,11 @@ class BaseStrategy {
220
221
  extraFileUpdates.push({
221
222
  path: this.addPath(path),
222
223
  createIfMissing: false,
223
- updater: new generic_1.Generic({ version, versionsMap }),
224
+ updater: new generic_1.Generic({
225
+ version,
226
+ versionsMap,
227
+ dateFormat: dateFormat,
228
+ }),
224
229
  });
225
230
  break;
226
231
  case 'json':
@@ -267,21 +272,21 @@ class BaseStrategy {
267
272
  extraFileUpdates.push({
268
273
  path: this.addPath(extraFile),
269
274
  createIfMissing: false,
270
- updater: new composite_1.CompositeUpdater(new generic_json_1.GenericJson('$.version', version), new generic_1.Generic({ version, versionsMap })),
275
+ updater: new composite_1.CompositeUpdater(new generic_json_1.GenericJson('$.version', version), new generic_1.Generic({ version, versionsMap, dateFormat: dateFormat })),
271
276
  });
272
277
  }
273
278
  else if (extraFile.endsWith('.yaml') || extraFile.endsWith('.yml')) {
274
279
  extraFileUpdates.push({
275
280
  path: this.addPath(extraFile),
276
281
  createIfMissing: false,
277
- updater: new composite_1.CompositeUpdater(new generic_yaml_1.GenericYaml('$.version', version), new generic_1.Generic({ version, versionsMap })),
282
+ updater: new composite_1.CompositeUpdater(new generic_yaml_1.GenericYaml('$.version', version), new generic_1.Generic({ version, versionsMap, dateFormat: dateFormat })),
278
283
  });
279
284
  }
280
285
  else if (extraFile.endsWith('.toml')) {
281
286
  extraFileUpdates.push({
282
287
  path: this.addPath(extraFile),
283
288
  createIfMissing: false,
284
- updater: new composite_1.CompositeUpdater(new generic_toml_1.GenericToml('$.version', version), new generic_1.Generic({ version, versionsMap })),
289
+ updater: new composite_1.CompositeUpdater(new generic_toml_1.GenericToml('$.version', version), new generic_1.Generic({ version, versionsMap, dateFormat: dateFormat })),
285
290
  });
286
291
  }
287
292
  else if (extraFile.endsWith('.xml')) {
@@ -290,14 +295,14 @@ class BaseStrategy {
290
295
  createIfMissing: false,
291
296
  updater: new composite_1.CompositeUpdater(
292
297
  // Updates "version" element that is a child of the root element.
293
- new generic_xml_1.GenericXml('/*/version', version), new generic_1.Generic({ version, versionsMap })),
298
+ new generic_xml_1.GenericXml('/*/version', version), new generic_1.Generic({ version, versionsMap, dateFormat: dateFormat })),
294
299
  });
295
300
  }
296
301
  else {
297
302
  extraFileUpdates.push({
298
303
  path: this.addPath(extraFile),
299
304
  createIfMissing: false,
300
- updater: new generic_1.Generic({ version, versionsMap }),
305
+ updater: new generic_1.Generic({ version, versionsMap, dateFormat: dateFormat }),
301
306
  });
302
307
  }
303
308
  }
@@ -95,7 +95,7 @@ class Java extends base_1.BaseStrategy {
95
95
  isSnapshot: true,
96
96
  commits: [],
97
97
  });
98
- const updatesWithExtras = (0, composite_1.mergeUpdates)(updates.concat(...(await this.extraFileUpdates(newVersion, versionsMap))));
98
+ const updatesWithExtras = (0, composite_1.mergeUpdates)(updates.concat(...(await this.extraFileUpdates(newVersion, versionsMap, this.dateFormat))));
99
99
  return {
100
100
  title: pullRequestTitle,
101
101
  body: pullRequestBody,
@@ -0,0 +1,8 @@
1
+ import { BaseStrategy, BuildUpdatesOptions, BaseStrategyOptions } from './base';
2
+ import { Update } from '../update';
3
+ import { Version } from '../version';
4
+ export declare class R extends BaseStrategy {
5
+ constructor(options: BaseStrategyOptions);
6
+ protected buildUpdates(options: BuildUpdatesOptions): Promise<Update[]>;
7
+ protected initialReleaseVersion(): Version;
8
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ // Copyright 2025 Google LLC
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.R = void 0;
17
+ const base_1 = require("./base");
18
+ const news_1 = require("../updaters/r/news");
19
+ const version_1 = require("../version");
20
+ const description_1 = require("../updaters/r/description");
21
+ const CHANGELOG_SECTIONS = [
22
+ { type: 'feat', section: 'Features' },
23
+ { type: 'fix', section: 'Bug Fixes' },
24
+ { type: 'perf', section: 'Performance Improvements' },
25
+ { type: 'deps', section: 'Dependencies' },
26
+ { type: 'revert', section: 'Reverts' },
27
+ { type: 'docs', section: 'Documentation' },
28
+ { type: 'style', section: 'Styles', hidden: true },
29
+ { type: 'chore', section: 'Miscellaneous Chores', hidden: true },
30
+ { type: 'refactor', section: 'Code Refactoring', hidden: true },
31
+ { type: 'test', section: 'Tests', hidden: true },
32
+ { type: 'build', section: 'Build System', hidden: true },
33
+ { type: 'ci', section: 'Continuous Integration', hidden: true },
34
+ ];
35
+ class R extends base_1.BaseStrategy {
36
+ constructor(options) {
37
+ var _a, _b;
38
+ options.changelogPath = (_a = options.changelogPath) !== null && _a !== void 0 ? _a : 'NEWS.md';
39
+ options.changelogSections = (_b = options.changelogSections) !== null && _b !== void 0 ? _b : CHANGELOG_SECTIONS;
40
+ super(options);
41
+ }
42
+ async buildUpdates(options) {
43
+ const updates = [];
44
+ const version = options.newVersion;
45
+ updates.push({
46
+ path: this.addPath(this.changelogPath),
47
+ createIfMissing: true,
48
+ updater: new news_1.News({
49
+ version,
50
+ changelogEntry: options.changelogEntry,
51
+ }),
52
+ });
53
+ updates.push({
54
+ path: this.addPath('DESCRIPTION'),
55
+ createIfMissing: false,
56
+ updater: new description_1.DescriptionUpdater({
57
+ version,
58
+ }),
59
+ });
60
+ return updates;
61
+ }
62
+ initialReleaseVersion() {
63
+ return version_1.Version.parse('0.1.0');
64
+ }
65
+ }
66
+ exports.R = R;
67
+ //# sourceMappingURL=r.js.map
@@ -7,7 +7,7 @@ interface ChangelogJsonOptions extends UpdateOptions {
7
7
  commits: ConventionalCommit[];
8
8
  }
9
9
  /**
10
- * Maintians a machine readable CHANGELOG in chnagelog.json.
10
+ * Maintains a machine readable CHANGELOG in chnagelog.json.
11
11
  * See: https://gist.github.com/bcoe/50ef0a0024bbf107cd5bc0adbdc04758
12
12
  */
13
13
  export declare class ChangelogJson extends DefaultUpdater {
@@ -21,7 +21,7 @@ const BREAKING_CHANGE_TITLE = 'BREAKING CHANGE';
21
21
  const COMMIT_PREFIX = /^[^:]+: ?/;
22
22
  const PR_SUFFIX_REGEX = / ?\(#(?<pr>[0-9]+)\)$/;
23
23
  /**
24
- * Maintians a machine readable CHANGELOG in chnagelog.json.
24
+ * Maintains a machine readable CHANGELOG in chnagelog.json.
25
25
  * See: https://gist.github.com/bcoe/50ef0a0024bbf107cd5bc0adbdc04758
26
26
  */
27
27
  class ChangelogJson extends default_1.DefaultUpdater {
@@ -1,5 +1,6 @@
1
1
  import { DefaultUpdater, UpdateOptions } from './default';
2
2
  import { Logger } from '../util/logger';
3
+ export declare const DEFAULT_DATE_FORMAT = "%Y-%m-%d";
3
4
  /**
4
5
  * Options for the Generic updater.
5
6
  */
@@ -7,6 +8,8 @@ export interface GenericUpdateOptions extends UpdateOptions {
7
8
  inlineUpdateRegex?: RegExp;
8
9
  blockStartRegex?: RegExp;
9
10
  blockEndRegex?: RegExp;
11
+ date?: Date;
12
+ dateFormat?: string;
10
13
  }
11
14
  /**
12
15
  * The Generic updater looks for well known patterns and replaces
@@ -24,17 +27,23 @@ export interface GenericUpdateOptions extends UpdateOptions {
24
27
  * 4. `x-release-please-patch` if this string is found on the line,
25
28
  * then replace an integer looking value with the next version's
26
29
  * patch
30
+ * 5. `x-release-please-date` if this string is found on the line,
31
+ * then replace the date with the date of the last commit
32
+ * 6. `x-release-please-version-date` if this string is found on the line,
33
+ * then replace the both date and version
27
34
  *
28
35
  * You can also use a block-based replacement. Content between the
29
36
  * opening `x-release-please-start-version` and `x-release-please-end` will
30
37
  * be considered for version replacement. You can also open these blocks
31
- * with `x-release-please-start-<major|minor|patch>` to replace single
32
- * numbers
38
+ * with `x-release-please-start-<major|minor|patch|version-date>` to replace
39
+ * single numbers
33
40
  */
34
41
  export declare class Generic extends DefaultUpdater {
35
42
  private readonly inlineUpdateRegex;
36
43
  private readonly blockStartRegex;
37
44
  private readonly blockEndRegex;
45
+ private readonly date;
46
+ private readonly dateFormat;
38
47
  constructor(options: GenericUpdateOptions);
39
48
  /**
40
49
  * Given initial file contents, return updated contents.
@@ -13,14 +13,16 @@
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.Generic = void 0;
16
+ exports.Generic = exports.DEFAULT_DATE_FORMAT = void 0;
17
17
  const default_1 = require("./default");
18
18
  const logger_1 = require("../util/logger");
19
19
  const VERSION_REGEX = /(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(-(?<preRelease>[\w.]+))?(\+(?<build>[-\w.]+))?/;
20
20
  const SINGLE_VERSION_REGEX = /\b\d+\b/;
21
- const INLINE_UPDATE_REGEX = /x-release-please-(?<scope>major|minor|patch|version)/;
22
- const BLOCK_START_REGEX = /x-release-please-start-(?<scope>major|minor|patch|version)/;
21
+ const INLINE_UPDATE_REGEX = /x-release-please-(?<scope>major|minor|patch|version-date|version|date)/;
22
+ const BLOCK_START_REGEX = /x-release-please-start-(?<scope>major|minor|patch|version-date|version|date)/;
23
23
  const BLOCK_END_REGEX = /x-release-please-end/;
24
+ const DATE_FORMAT_REGEX = /%[Ymd]/g;
25
+ exports.DEFAULT_DATE_FORMAT = '%Y-%m-%d';
24
26
  /**
25
27
  * The Generic updater looks for well known patterns and replaces
26
28
  * content. The well known patterns are:
@@ -37,20 +39,26 @@ const BLOCK_END_REGEX = /x-release-please-end/;
37
39
  * 4. `x-release-please-patch` if this string is found on the line,
38
40
  * then replace an integer looking value with the next version's
39
41
  * patch
42
+ * 5. `x-release-please-date` if this string is found on the line,
43
+ * then replace the date with the date of the last commit
44
+ * 6. `x-release-please-version-date` if this string is found on the line,
45
+ * then replace the both date and version
40
46
  *
41
47
  * You can also use a block-based replacement. Content between the
42
48
  * opening `x-release-please-start-version` and `x-release-please-end` will
43
49
  * be considered for version replacement. You can also open these blocks
44
- * with `x-release-please-start-<major|minor|patch>` to replace single
45
- * numbers
50
+ * with `x-release-please-start-<major|minor|patch|version-date>` to replace
51
+ * single numbers
46
52
  */
47
53
  class Generic extends default_1.DefaultUpdater {
48
54
  constructor(options) {
49
- var _a, _b, _c;
55
+ var _a, _b, _c, _d, _e;
50
56
  super(options);
51
57
  this.inlineUpdateRegex = (_a = options.inlineUpdateRegex) !== null && _a !== void 0 ? _a : INLINE_UPDATE_REGEX;
52
58
  this.blockStartRegex = (_b = options.blockStartRegex) !== null && _b !== void 0 ? _b : BLOCK_START_REGEX;
53
59
  this.blockEndRegex = (_c = options.blockEndRegex) !== null && _c !== void 0 ? _c : BLOCK_END_REGEX;
60
+ this.date = (_d = options.date) !== null && _d !== void 0 ? _d : new Date();
61
+ this.dateFormat = (_e = options.dateFormat) !== null && _e !== void 0 ? _e : exports.DEFAULT_DATE_FORMAT;
54
62
  }
55
63
  /**
56
64
  * Given initial file contents, return updated contents.
@@ -63,8 +71,28 @@ class Generic extends default_1.DefaultUpdater {
63
71
  }
64
72
  const newLines = [];
65
73
  let blockScope;
66
- function replaceVersion(line, scope, version) {
74
+ function replaceVersion(line, scope, version, date, dateFormat) {
75
+ const dateRegex = createDateRegex(dateFormat);
76
+ const formattedDate = formatDate(dateFormat, date);
67
77
  switch (scope) {
78
+ case 'date':
79
+ if (isValidDate(formattedDate, dateFormat)) {
80
+ newLines.push(line.replace(dateRegex, formattedDate));
81
+ }
82
+ else {
83
+ logger.warn(`Invalid date format: ${formattedDate}`);
84
+ newLines.push(line);
85
+ }
86
+ return;
87
+ case 'version-date':
88
+ if (isValidDate(formattedDate, dateFormat)) {
89
+ line = line.replace(dateRegex, formattedDate);
90
+ }
91
+ else {
92
+ logger.warn(`Invalid date format: ${formattedDate}`);
93
+ }
94
+ newLines.push(line.replace(VERSION_REGEX, version.toString()));
95
+ return;
68
96
  case 'major':
69
97
  newLines.push(line.replace(SINGLE_VERSION_REGEX, `${version.major}`));
70
98
  return;
@@ -87,11 +115,11 @@ class Generic extends default_1.DefaultUpdater {
87
115
  let match = line.match(this.inlineUpdateRegex);
88
116
  if (match) {
89
117
  // replace inline versions
90
- replaceVersion(line, (((_a = match.groups) === null || _a === void 0 ? void 0 : _a.scope) || 'version'), this.version);
118
+ replaceVersion(line, (((_a = match.groups) === null || _a === void 0 ? void 0 : _a.scope) || 'version'), this.version, this.date, this.dateFormat);
91
119
  }
92
120
  else if (blockScope) {
93
121
  // in a block, so try to replace versions
94
- replaceVersion(line, blockScope, this.version);
122
+ replaceVersion(line, blockScope, this.version, this.date, this.dateFormat);
95
123
  if (line.match(this.blockEndRegex)) {
96
124
  blockScope = undefined;
97
125
  }
@@ -114,4 +142,45 @@ class Generic extends default_1.DefaultUpdater {
114
142
  }
115
143
  }
116
144
  exports.Generic = Generic;
145
+ function createDateRegex(format) {
146
+ const regexString = format.replace(DATE_FORMAT_REGEX, match => {
147
+ switch (match) {
148
+ case '%Y':
149
+ return '(\\d{4})';
150
+ case '%m':
151
+ return '(\\d{2})';
152
+ case '%d':
153
+ return '(\\d{2})';
154
+ default:
155
+ return match;
156
+ }
157
+ });
158
+ return new RegExp(regexString);
159
+ }
160
+ function formatDate(format, date) {
161
+ return format.replace(DATE_FORMAT_REGEX, match => {
162
+ switch (match) {
163
+ case '%Y':
164
+ return date.getFullYear().toString();
165
+ case '%m':
166
+ return ('0' + (date.getMonth() + 1)).slice(-2);
167
+ case '%d':
168
+ return ('0' + date.getDate()).slice(-2);
169
+ default:
170
+ return match;
171
+ }
172
+ });
173
+ }
174
+ function isValidDate(dateString, format) {
175
+ const dateParts = dateString.match(/\d+/g);
176
+ if (!dateParts)
177
+ return false;
178
+ const year = parseInt(dateParts[format.indexOf('%Y') / 3], 10);
179
+ const month = parseInt(dateParts[format.indexOf('%m') / 3], 10);
180
+ const day = parseInt(dateParts[format.indexOf('%d') / 3], 10);
181
+ if (year < 1 || month < 1 || month > 12 || day < 1 || day > 31)
182
+ return false;
183
+ const daysInMonth = new Date(year, month, 0).getDate();
184
+ return day <= daysInMonth;
185
+ }
117
186
  //# sourceMappingURL=generic.js.map
@@ -0,0 +1,12 @@
1
+ import { DefaultUpdater } from '../default';
2
+ /**
3
+ * Updates the DESCRIPTION file of an R package.
4
+ */
5
+ export declare class DescriptionUpdater extends DefaultUpdater {
6
+ /**
7
+ * Given initial file contents, return updated contents.
8
+ * @param {string} content The initial content
9
+ * @returns {string} The updated content
10
+ */
11
+ updateContent(content: string): string;
12
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ // Copyright 2025 Google LLC
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.DescriptionUpdater = void 0;
17
+ const default_1 = require("../default");
18
+ /**
19
+ * Updates the DESCRIPTION file of an R package.
20
+ */
21
+ class DescriptionUpdater extends default_1.DefaultUpdater {
22
+ /**
23
+ * Given initial file contents, return updated contents.
24
+ * @param {string} content The initial content
25
+ * @returns {string} The updated content
26
+ */
27
+ updateContent(content) {
28
+ return content.replace(/^Version:\s*[0-9]+\.[0-9]+\.[0-9]+(?:\.[0-9]+)?\s*$/m, `Version: ${this.version}`);
29
+ }
30
+ }
31
+ exports.DescriptionUpdater = DescriptionUpdater;
32
+ //# sourceMappingURL=description.js.map
@@ -0,0 +1,12 @@
1
+ import { DefaultUpdater, UpdateOptions } from '../default';
2
+ interface ChangelogOptions extends UpdateOptions {
3
+ changelogEntry: string;
4
+ versionHeaderRegex?: string;
5
+ }
6
+ export declare class News extends DefaultUpdater {
7
+ changelogEntry: string;
8
+ readonly versionHeaderRegex: RegExp;
9
+ constructor(options: ChangelogOptions);
10
+ updateContent(content: string | undefined): string;
11
+ }
12
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ // Copyright 2025 Google LLC
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.News = void 0;
17
+ const default_1 = require("../default");
18
+ const DEFAULT_VERSION_HEADER_REGEX = '\n### v?[0-9[]';
19
+ class News extends default_1.DefaultUpdater {
20
+ constructor(options) {
21
+ var _a;
22
+ super(options);
23
+ this.changelogEntry = options.changelogEntry;
24
+ this.versionHeaderRegex = new RegExp((_a = options.versionHeaderRegex) !== null && _a !== void 0 ? _a : DEFAULT_VERSION_HEADER_REGEX, 's');
25
+ }
26
+ updateContent(content) {
27
+ content = content || '';
28
+ const lastEntryIndex = content.search(this.versionHeaderRegex);
29
+ if (lastEntryIndex === -1) {
30
+ if (content) {
31
+ return `${this.changelogEntry}\n\n${adjustHeaders(content).trim()}\n`;
32
+ }
33
+ else {
34
+ return `${this.changelogEntry}\n`;
35
+ }
36
+ }
37
+ else {
38
+ const before = content.slice(0, lastEntryIndex);
39
+ const after = content.slice(lastEntryIndex);
40
+ return `${before}\n${this.changelogEntry}\n${after}`.trim() + '\n';
41
+ }
42
+ }
43
+ }
44
+ exports.News = News;
45
+ // Helper to increase markdown H1 headers to H2
46
+ function adjustHeaders(content) {
47
+ return content.replace(/^#(\s)/gm, '##$1');
48
+ }
49
+ //# sourceMappingURL=news.js.map
@@ -70,7 +70,8 @@ function releaserConfigToJsonConfig(config) {
70
70
  'tag-separator': config.tagSeparator,
71
71
  'extra-files': config.extraFiles,
72
72
  'version-file': config.versionFile,
73
- 'snapshot-label': (_c = config.snapshotLabels) === null || _c === void 0 ? void 0 : _c.join(','), // Java-only
73
+ 'snapshot-label': (_c = config.snapshotLabels) === null || _c === void 0 ? void 0 : _c.join(','),
74
+ 'date-format': config.dateFormat,
74
75
  };
75
76
  return jsonConfig;
76
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-please",
3
- "version": "16.15.0",
3
+ "version": "16.17.0",
4
4
  "description": "generate release PRs based on the conventionalcommits.org spec",
5
5
  "main": "./build/src/index.js",
6
6
  "bin": "./build/src/bin/release-please.js",
@@ -45,7 +45,7 @@
45
45
  "@types/inquirer": "^9.0.3",
46
46
  "@types/js-yaml": "^4.0.0",
47
47
  "@types/jsonpath": "^0.2.0",
48
- "@types/mocha": "^9.0.0",
48
+ "@types/mocha": "^10.0.0",
49
49
  "@types/node": "^18.0.0",
50
50
  "@types/npmlog": "^7.0.0",
51
51
  "@types/pino": "^7.0.0",
@@ -119,6 +119,10 @@
119
119
  "description": "Customize the separator between the component and version in the GitHub tag.",
120
120
  "type": "string"
121
121
  },
122
+ "date-format": {
123
+ "description": "Date format given as a strftime expression for the generic strategy.",
124
+ "type": "string"
125
+ },
122
126
  "extra-files": {
123
127
  "description": "Specify extra generic files to replace versions.",
124
128
  "type": "array",
@@ -476,6 +480,7 @@
476
480
  "separate-pull-requests": true,
477
481
  "always-update": true,
478
482
  "tag-separator": true,
483
+ "date-format": true,
479
484
  "extra-files": true,
480
485
  "version-file": true,
481
486
  "snapshot-label": true,