Compare commits
No commits in common. "main" and "lord7-schema" have entirely different histories.
main
...
lord7-sche
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
*.tgz
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
_templates
|
|
||||||
Taskfile.yaml
|
|
||||||
*.tgz
|
|
||||||
prettier.config.*
|
|
||||||
changelog-next/
|
|
||||||
*.test.js
|
|
37
CHANGELOG.md
37
CHANGELOG.md
@ -1,37 +0,0 @@
|
|||||||
# Changelog for [changelord][homepage]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 0.2.0 2023-05-18
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add `git-gather` command
|
|
||||||
* add 'next' to alias to 'upcoming'
|
|
||||||
* cutting a release also add a new NEXT release
|
|
||||||
* git-gather also filters on descs
|
|
||||||
* add the validate command
|
|
||||||
* support changelog-next directory
|
|
||||||
|
|
||||||
### Statistics
|
|
||||||
|
|
||||||
* code churn: 21 files changed, 563 insertions(+), 153 deletions(-)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 0.1.0 2023-05-16
|
|
||||||
|
|
||||||
* port the core of the Perl changelord to JavaScript.
|
|
||||||
|
|
||||||
### Statistics
|
|
||||||
|
|
||||||
* code churn: 23 files changed, 767 insertions(+)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[homepage]: https://git.babyl.ca/yanick/changelord.js
|
|
@ -1,41 +1,12 @@
|
|||||||
project:
|
project:
|
||||||
name: changelord
|
name: null
|
||||||
homepage: https://git.babyl.ca/yanick/changelord.js
|
homepage: null
|
||||||
with_stats: true
|
with_stats: true
|
||||||
next_directory: ./changelog-next
|
ticket_url: null
|
||||||
releases:
|
releases:
|
||||||
- version: NEXT
|
- version: NEXT
|
||||||
changes: []
|
changes: []
|
||||||
- version: 0.2.0
|
|
||||||
changes:
|
|
||||||
- type: feat
|
|
||||||
desc: add `git-gather` command
|
|
||||||
- type: feat
|
|
||||||
desc: add 'next' to alias to 'upcoming'
|
|
||||||
- type: feat
|
|
||||||
desc: cutting a release also add a new NEXT release
|
|
||||||
- type: feat
|
|
||||||
desc: git-gather also filters on descs
|
|
||||||
- type: feat
|
|
||||||
desc: add the validate command
|
|
||||||
- desc: support changelog-next directory
|
|
||||||
type: feat
|
|
||||||
- type: stats
|
|
||||||
desc: |
|
|
||||||
code churn: 21 files changed, 563 insertions(+), 153 deletions(-)
|
|
||||||
date: 2023-05-18
|
|
||||||
- version: 0.1.0
|
|
||||||
changes:
|
|
||||||
- port the core of the Perl changelord to JavaScript.
|
|
||||||
- type: stats
|
|
||||||
desc: |
|
|
||||||
code churn: 23 files changed, 767 insertions(+)
|
|
||||||
date: 2023-05-16
|
|
||||||
change_types:
|
change_types:
|
||||||
- title: ""
|
|
||||||
level: minor
|
|
||||||
keywords:
|
|
||||||
- ""
|
|
||||||
- title: Features
|
- title: Features
|
||||||
level: minor
|
level: minor
|
||||||
keywords:
|
keywords:
|
||||||
|
130
README.md
130
README.md
@ -1,130 +0,0 @@
|
|||||||
# Changelord, registrar of deeds extraordinaire
|
|
||||||
|
|
||||||
Changelord is a changelog manager scratching my particular itches.
|
|
||||||
It's cli-based, and keep its data in a YAML file adhering
|
|
||||||
to a well-defined schema.
|
|
||||||
|
|
||||||
The first iteration of `changelord` was written [in Perl][original]. You can
|
|
||||||
read its [introductory article][blog] on my blog.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
pnpm install changelord
|
|
||||||
|
|
||||||
## `changelog-next` directory
|
|
||||||
|
|
||||||
If you want to mininize merge conflicts in `CHANGELOG.yml`,
|
|
||||||
you can set the option `project.next_directory` to a directory (typically
|
|
||||||
`./changelog-next`) that will hold yaml files containing the
|
|
||||||
changes for the NEXT release. Each of those files is expected to
|
|
||||||
have a list of changes.
|
|
||||||
|
|
||||||
## CLI commands
|
|
||||||
|
|
||||||
### Global options
|
|
||||||
|
|
||||||
#### `--help`
|
|
||||||
|
|
||||||
Outputs the list of commands and options.
|
|
||||||
|
|
||||||
#### `--version`
|
|
||||||
|
|
||||||
Outputs the `changelord` version.
|
|
||||||
|
|
||||||
#### `--source`
|
|
||||||
|
|
||||||
Specifies which source yaml file to use. Defaults to the `CHANGELOG.yml` file
|
|
||||||
in the current directory.
|
|
||||||
|
|
||||||
### `changelord init`
|
|
||||||
|
|
||||||
Initializes the changelog source file. The YAML file is made of three
|
|
||||||
sections.
|
|
||||||
|
|
||||||
- `project` -- contains information and configuration about the project itself.
|
|
||||||
- `releases` -- the entries for the changelog proper.
|
|
||||||
- `change_types` -- defines all types of changes this project supports.
|
|
||||||
|
|
||||||
### `changelord add`
|
|
||||||
|
|
||||||
Adds an entry to the `NEXT` release.
|
|
||||||
|
|
||||||
If `project.next_directory` is defined, the entry will be added to that
|
|
||||||
directory instead of directly into `CHANGELOG.yml`.
|
|
||||||
|
|
||||||
$ changelord add --type=maint added a changelog to the project.
|
|
||||||
|
|
||||||
#### Options
|
|
||||||
|
|
||||||
- `--type` -- type of change.
|
|
||||||
- `--ticket` -- associated ticket.
|
|
||||||
|
|
||||||
### `changelord print`
|
|
||||||
|
|
||||||
Renders the changelog as markdown.
|
|
||||||
|
|
||||||
#### Options
|
|
||||||
|
|
||||||
- `--no-next` -- don't show the `NEXT` section.
|
|
||||||
|
|
||||||
### `changelord cut`
|
|
||||||
|
|
||||||
Cuts the next release. That is, resolves the `NEXT` version number based on the
|
|
||||||
latest version and the changes in the `NEXT` section, and sets its date as
|
|
||||||
today. Modifies the source file with the result.
|
|
||||||
|
|
||||||
If the `project.next_directory` option is present,
|
|
||||||
all the changes in that directory are
|
|
||||||
merged to `CHANGELOG.yml` and the files themselves are deleted.
|
|
||||||
|
|
||||||
#### Options
|
|
||||||
|
|
||||||
- `--dry` -- Resolves the next version but only outputs the resulting section
|
|
||||||
without changing the source file.
|
|
||||||
|
|
||||||
### `changelord schema`
|
|
||||||
|
|
||||||
Outputs the JSON schema defining the structure of the source file.
|
|
||||||
|
|
||||||
### `changelord upcoming`
|
|
||||||
|
|
||||||
Outputs the changes listed in the `NEXT` release.
|
|
||||||
|
|
||||||
### `changelord latest-version`
|
|
||||||
|
|
||||||
Outputs the latest non-NEXT release.
|
|
||||||
|
|
||||||
$ changelord latest-version
|
|
||||||
3.2.0
|
|
||||||
|
|
||||||
### `changelord validate`
|
|
||||||
|
|
||||||
Validates the changelog source against its json schema.
|
|
||||||
|
|
||||||
### `changelord git-gather`
|
|
||||||
|
|
||||||
Gathers change entries from git commits. If any are found, they are
|
|
||||||
added to the changelog.
|
|
||||||
|
|
||||||
#### Lower bound of the git log
|
|
||||||
|
|
||||||
`git-gather` inspects the git log from the most recent of those
|
|
||||||
three points:
|
|
||||||
|
|
||||||
- The last change in the NEXT release having a `commit` property.
|
|
||||||
- The last tagged version.
|
|
||||||
- The beginning of time.
|
|
||||||
|
|
||||||
#### Change-like git message
|
|
||||||
|
|
||||||
Git messages are compared to the regular expression
|
|
||||||
configured at `project.commit_regex`. If none is found, it
|
|
||||||
defaults to
|
|
||||||
|
|
||||||
^(?<type>[^: ]+):\s*(?<desc>.*?)(\[(?<ticket>[^\]]+)\])?$
|
|
||||||
|
|
||||||
The regular expression must capture a `desc` field, and may
|
|
||||||
capture a `type` and `ticket` as well.
|
|
||||||
|
|
||||||
[blog]: https://techblog.babyl.ca/entry/changelord/
|
|
||||||
[original]: https://metacpan.org/dist/App-Changelord/view/bin/changelord
|
|
@ -1,22 +0,0 @@
|
|||||||
# https://taskfile.dev
|
|
||||||
version: "3"
|
|
||||||
|
|
||||||
vars:
|
|
||||||
PARENT_BRANCH: main
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
test: vitest run src
|
|
||||||
test:dev: vitest src
|
|
||||||
|
|
||||||
integrate:
|
|
||||||
deps: [test]
|
|
||||||
preconditions:
|
|
||||||
- sh: git is-clean
|
|
||||||
msg: checkout not clean
|
|
||||||
- sh: git diff-ls {{.PARENT_BRANCH}} | grep test
|
|
||||||
msg: no tests were added
|
|
||||||
- sh: git diff-ls {{.PARENT_BRANCH}} | grep CHANGELOG.yml
|
|
||||||
msg: no changelog entry detected
|
|
||||||
cmds:
|
|
||||||
- git checkout {{.PARENT_BRANCH}}
|
|
||||||
- git weld -
|
|
@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
to: src/command/<%= name %>.js
|
|
||||||
---
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
// DO SOMETHING
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: '<%= name %>',
|
|
||||||
desc : 'TODO',
|
|
||||||
builder: (yargs) => {
|
|
||||||
yargs
|
|
||||||
},
|
|
||||||
handler,
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
message: |
|
|
||||||
hygen {bold generator new} --name [NAME] --action [ACTION]
|
|
||||||
hygen {bold generator with-prompt} --name [NAME] --action [ACTION]
|
|
||||||
---
|
|
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
|
|
||||||
---
|
|
||||||
---
|
|
||||||
to: app/hello.js
|
|
||||||
---
|
|
||||||
const hello = ```
|
|
||||||
Hello!
|
|
||||||
This is your first hygen template.
|
|
||||||
|
|
||||||
Learn what it can do here:
|
|
||||||
|
|
||||||
https://github.com/jondot/hygen
|
|
||||||
```
|
|
||||||
|
|
||||||
console.log(hello)
|
|
||||||
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
|
|
||||||
---
|
|
||||||
---
|
|
||||||
to: app/hello.js
|
|
||||||
---
|
|
||||||
const hello = ```
|
|
||||||
Hello!
|
|
||||||
This is your first prompt based hygen template.
|
|
||||||
|
|
||||||
Learn what it can do here:
|
|
||||||
|
|
||||||
https://github.com/jondot/hygen
|
|
||||||
```
|
|
||||||
|
|
||||||
console.log(hello)
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
to: _templates/<%= name %>/<%= action || 'new' %>/prompt.js
|
|
||||||
---
|
|
||||||
|
|
||||||
// see types of prompts:
|
|
||||||
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
||||||
//
|
|
||||||
module.exports = [
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
name: 'message',
|
|
||||||
message: "What's your message?"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
setup: <%= name %>
|
|
||||||
force: true # this is because mostly, people init into existing folders is safe
|
|
||||||
---
|
|
26
package.json
26
package.json
@ -1,20 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "changelord",
|
"name": "changelord",
|
||||||
"version": "0.2.0",
|
"version": "0.0.1",
|
||||||
"description": "cli-based changelog manager",
|
"description": "cli-based changelog manager",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/changelord.js",
|
"main": "src/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"changelord": "./src/changelord.js"
|
"changelord": "./src/changelord.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://git.babyl.ca/yanick/changelord.js.git"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://git.babyl.ca/yanick/changelord.js/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://git.babyl.ca/yanick/changelord.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
@ -24,24 +16,12 @@
|
|||||||
"author": "Yanick Champoux <yanick@babyl.ca> (http://techblog.babyl.ca/)",
|
"author": "Yanick Champoux <yanick@babyl.ca> (http://techblog.babyl.ca/)",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sindresorhus/slugify": "^2.2.1",
|
|
||||||
"@yanick/updeep-remeda": "^2.2.0",
|
|
||||||
"ajv": "^8.12.0",
|
|
||||||
"consola": "^3.1.0",
|
"consola": "^3.1.0",
|
||||||
"filenamify": "^6.0.0",
|
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"globby": "^13.1.4",
|
|
||||||
"markdown-utils": "^1.0.0",
|
|
||||||
"nanoid": "^4.0.2",
|
|
||||||
"remeda": "^1.14.0",
|
|
||||||
"semver": "^7.5.0",
|
|
||||||
"simple-git": "^3.18.0",
|
|
||||||
"yaml": "^2.2.2",
|
"yaml": "^2.2.2",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8"
|
||||||
"typescript": "^5.0.4",
|
|
||||||
"vitest": "^0.31.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
export default {
|
|
||||||
endOfLine: "lf",
|
|
||||||
semi: true,
|
|
||||||
singleQuote: false,
|
|
||||||
tabWidth: 2,
|
|
||||||
trailingComma: "es5",
|
|
||||||
bracketSpacing: true,
|
|
||||||
proseWrap: "always",
|
|
||||||
};
|
|
@ -1,118 +0,0 @@
|
|||||||
export default {
|
|
||||||
type: "object",
|
|
||||||
additionalProperties: false,
|
|
||||||
properties: {
|
|
||||||
change_types: {
|
|
||||||
items: {
|
|
||||||
additionalProperties: false,
|
|
||||||
properties: {
|
|
||||||
keywords: {
|
|
||||||
items: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
type: "array",
|
|
||||||
},
|
|
||||||
level: {
|
|
||||||
enum: ["major", "minor", "patch"],
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
type: "object",
|
|
||||||
},
|
|
||||||
type: "array",
|
|
||||||
},
|
|
||||||
project: {
|
|
||||||
additionalProperties: false,
|
|
||||||
properties: {
|
|
||||||
homepage: {
|
|
||||||
description: "url of the project's homepage",
|
|
||||||
examples: ["https://github.com/yanick/app-changelord"],
|
|
||||||
type: ["string", "null"],
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
description: "name of the project",
|
|
||||||
examples: ["App::Changelord"],
|
|
||||||
type: ["null", "string"],
|
|
||||||
},
|
|
||||||
ticket_url: {
|
|
||||||
description:
|
|
||||||
"perl code that takes a ticket string (e.g. 'GH123') via the `$_` variable and turns it into a link.",
|
|
||||||
examples: [
|
|
||||||
"s!GH(\\d+)!https://github.com/yanick/App-Changelord/issue/$1/",
|
|
||||||
{
|
|
||||||
'/^\\d+$/ ? "https://.../$_"': "undef",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
with_stats: {
|
|
||||||
description: "if true, add git statistics when bumping the version.",
|
|
||||||
},
|
|
||||||
next_directory: {
|
|
||||||
type: "string",
|
|
||||||
description:
|
|
||||||
"directory where the changes for the NEXT release are stashed",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
type: "object",
|
|
||||||
},
|
|
||||||
releases: {
|
|
||||||
items: {
|
|
||||||
oneOf: [
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
additionalProperties: false,
|
|
||||||
properties: {
|
|
||||||
changes: {
|
|
||||||
items: {
|
|
||||||
$ref: "#/$defs/change",
|
|
||||||
},
|
|
||||||
type: "array",
|
|
||||||
},
|
|
||||||
date: {
|
|
||||||
type: ["null", "string"],
|
|
||||||
},
|
|
||||||
version: {
|
|
||||||
type: ["null", "string"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
type: "object",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
type: "array",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
$defs: {
|
|
||||||
change: {
|
|
||||||
oneOf: [
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
additionalProperties: false,
|
|
||||||
properties: {
|
|
||||||
commit: {
|
|
||||||
type: ["string", "null"],
|
|
||||||
},
|
|
||||||
desc: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
ticket: {
|
|
||||||
type: ["string", "null"],
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: ["string", "null"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ["desc"],
|
|
||||||
type: "object",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
59
src/changelog-schema.yml
Normal file
59
src/changelog-schema.yml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
project:
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
homepage:
|
||||||
|
type: [ string, 'null' ]
|
||||||
|
description: url of the project's homepage
|
||||||
|
examples:
|
||||||
|
- https://github.com/yanick/app-changelord
|
||||||
|
name:
|
||||||
|
type: [ 'null', string ]
|
||||||
|
description: name of the project
|
||||||
|
examples:
|
||||||
|
- App::Changelord
|
||||||
|
ticket_url:
|
||||||
|
type: string
|
||||||
|
description: perl code that takes a ticket string (e.g. 'GH123') via the `$_` variable and turns it into a link.
|
||||||
|
examples:
|
||||||
|
- s!GH(\d+)!https://github.com/yanick/App-Changelord/issue/$1/
|
||||||
|
- /^\d+$/ ? "https://.../$_" : undef
|
||||||
|
with_stats:
|
||||||
|
description: if true, add git statistics when bumping the version.
|
||||||
|
change_types:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
keywords:
|
||||||
|
type: array
|
||||||
|
items: { type: string }
|
||||||
|
level: { enum: [ major, minor, patch ] }
|
||||||
|
title: { type: string }
|
||||||
|
releases:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: object
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
version: { type: [ 'null', string ] }
|
||||||
|
date: { type: ['null',string] }
|
||||||
|
changes: { type: 'array', items: { $ref: '#/$defs/change' } }
|
||||||
|
$defs:
|
||||||
|
change:
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: object
|
||||||
|
required: [ desc ]
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
desc: { type: string }
|
||||||
|
ticket: { type: [ string, 'null' ] }
|
||||||
|
type: { type: [ string, 'null' ] }
|
||||||
|
commit: { type: [ string, 'null' ] }
|
@ -1,151 +1,26 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { hideBin } from "yargs/helpers";
|
import { hideBin } from 'yargs/helpers';
|
||||||
import yargs from "yargs";
|
import yargs from 'yargs';
|
||||||
import { join } from "path";
|
import { join } from 'path';
|
||||||
import yaml from "yaml";
|
|
||||||
import fs from "fs-extra";
|
|
||||||
import consola from "consola";
|
|
||||||
import u from "@yanick/updeep-remeda";
|
|
||||||
import { once } from "remeda";
|
|
||||||
import simpleGit from "simple-git";
|
|
||||||
import Ajv from "ajv";
|
|
||||||
import { nanoid } from "nanoid";
|
|
||||||
import slugify from "@sindresorhus/slugify";
|
|
||||||
|
|
||||||
import print from "./command/print.js";
|
import print from './command/print.js'
|
||||||
import init from "./command/init.js";
|
import init from './command/init.js'
|
||||||
import schema from "./command/schema.js";
|
import schema from './command/schema.js';
|
||||||
import add from "./command/add.js";
|
import consola from 'consola';
|
||||||
import cut from "./command/cut.js";
|
|
||||||
import upcoming, { next_release } from "./command/upcoming.js";
|
|
||||||
import latest, { latest_version } from "./command/latest-version.js";
|
|
||||||
import validate from "./command/validate.js";
|
|
||||||
import git_gather from "./command/git-gather.js";
|
|
||||||
import schemaV1 from "./changelog-schema.js";
|
|
||||||
import { globby } from "globby";
|
|
||||||
import { flatMap } from "remeda";
|
|
||||||
|
|
||||||
consola.raw = (...args) => console.log(...args);
|
consola.raw = (...args) => console.log(...args);
|
||||||
|
|
||||||
yargs(hideBin(process.argv))
|
yargs(hideBin(process.argv))
|
||||||
.middleware((config) => {
|
.config({
|
||||||
config.git = once(simpleGit);
|
consola
|
||||||
config.consola = consola;
|
|
||||||
config.changelog = once(() =>
|
|
||||||
fs
|
|
||||||
.readFile(config.source, "utf-8")
|
|
||||||
.then(yaml.parse)
|
|
||||||
.then(async (doc) => {
|
|
||||||
if (!doc.project.next_directory) return doc;
|
|
||||||
|
|
||||||
const changes = await globby([
|
|
||||||
doc.project.next_directory + "/*.yml",
|
|
||||||
doc.project.next_directory + "/*.yaml",
|
|
||||||
])
|
|
||||||
.then((files) =>
|
|
||||||
Promise.all(
|
|
||||||
files.map((f) => fs.readFile(f, "utf-8").then(yaml.parse))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then((r) => r.flat());
|
|
||||||
|
|
||||||
if (changes.length)
|
|
||||||
doc.releases
|
|
||||||
.find((r) => r.version === "NEXT")
|
|
||||||
.changes.push(...changes);
|
|
||||||
|
|
||||||
return doc;
|
|
||||||
})
|
})
|
||||||
.then((doc) => {
|
.default('source', join( process.cwd(), 'CHANGELOG.yml' ))
|
||||||
const ajv = new Ajv();
|
.describe('source', 'changelog source')
|
||||||
const validate = ajv.compile(schemaV1);
|
|
||||||
const valid = validate(doc);
|
|
||||||
if (valid) return doc;
|
|
||||||
|
|
||||||
config.consola.error("invalid changelog: ", validate.errors);
|
|
||||||
throw "changelog is invalid";
|
|
||||||
})
|
|
||||||
);
|
|
||||||
config.delete_next_dir_entries = async () => {
|
|
||||||
const changelog = await config.changelog();
|
|
||||||
return globby([
|
|
||||||
changelog.project.next_directory + "/*.yml",
|
|
||||||
changelog.project.next_directory + "/*.yaml",
|
|
||||||
]).then((files) => Promise.all(files.map((f) => fs.remove(f))));
|
|
||||||
};
|
|
||||||
config.save_changelog = async (changelog) => {
|
|
||||||
if (!changelog) changelog = await config.changelog();
|
|
||||||
return fs.writeFile(config.source, yaml.stringify(changelog));
|
|
||||||
};
|
|
||||||
config.next_release = next_release.bind(config);
|
|
||||||
config.latest_version = latest_version.bind(config);
|
|
||||||
return config;
|
|
||||||
})
|
|
||||||
.middleware((argv, yargs) => {
|
|
||||||
argv.yargs = yargs;
|
|
||||||
|
|
||||||
argv.add_to_next = async (entry) => {
|
|
||||||
const dir = await argv.changelog().then((c) => c.project.next_directory);
|
|
||||||
|
|
||||||
if (dir) {
|
|
||||||
await fs.ensureDir(dir);
|
|
||||||
const filename = join(
|
|
||||||
dir,
|
|
||||||
[
|
|
||||||
new Date().toISOString(),
|
|
||||||
entry.ticket,
|
|
||||||
entry.feat,
|
|
||||||
slugify(entry.desc, {
|
|
||||||
separator: "_",
|
|
||||||
}).slice(0, 10),
|
|
||||||
]
|
|
||||||
.filter((x) => x)
|
|
||||||
.join("-") + ".yml"
|
|
||||||
);
|
|
||||||
argv.consola.info(`writing change to ${filename}`);
|
|
||||||
if (fs.existsSync(filename)) {
|
|
||||||
argv.consola.error(`file ${filename} already exist`);
|
|
||||||
yargs.exit(1);
|
|
||||||
}
|
|
||||||
if (Object.keys(entry).length === 1) {
|
|
||||||
entry = entry.desc;
|
|
||||||
}
|
|
||||||
return fs.writeFile(filename, yaml.stringify([entry]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const changelog = await argv.changelog();
|
|
||||||
|
|
||||||
let next = changelog.releases.find(u.matches({ version: "NEXT" }));
|
|
||||||
if (!next) {
|
|
||||||
changelog.releases.unshift(base_next_version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(entry).length === 1) {
|
|
||||||
entry = entry.desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
next.changes.push(entry);
|
|
||||||
|
|
||||||
return argv.save_changelog();
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.default("source", join(process.cwd(), "CHANGELOG.yml"))
|
|
||||||
.describe("source", "changelog source")
|
|
||||||
.command(init)
|
|
||||||
.command(add)
|
|
||||||
.command(print)
|
|
||||||
.command(cut)
|
|
||||||
.command(schema)
|
|
||||||
.command(upcoming)
|
|
||||||
.command({
|
.command({
|
||||||
...upcoming,
|
...print,
|
||||||
command: "next",
|
command: '$0',
|
||||||
desc: 'alias for "upcoming"',
|
|
||||||
})
|
})
|
||||||
.command(latest)
|
.command(init)
|
||||||
.command(git_gather)
|
.command(schema)
|
||||||
.command(validate)
|
.command(print).help().parse();
|
||||||
.strictCommands()
|
|
||||||
.help()
|
|
||||||
.parse();
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
import fs from "fs-extra";
|
|
||||||
import yaml from "yaml";
|
|
||||||
import u from "@yanick/updeep-remeda";
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
if (!config.change)
|
|
||||||
throw new Error("can't add a change without a description");
|
|
||||||
|
|
||||||
const entry = {
|
|
||||||
desc: config.change.join(" "),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (config.ticket) entry.ticket = config.ticket;
|
|
||||||
if (config.type) entry.type = config.type;
|
|
||||||
|
|
||||||
config.consola.start(`adding '${entry.desc}' to the changelog`);
|
|
||||||
|
|
||||||
await config.add_to_next(entry);
|
|
||||||
|
|
||||||
config.consola.success("done!");
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: "add [change...]",
|
|
||||||
desc: "add a change to the NEXT release",
|
|
||||||
builder: (yargs) => {
|
|
||||||
yargs
|
|
||||||
.string("ticket")
|
|
||||||
.describe("ticket", "ticket associated with the change")
|
|
||||||
.string("type")
|
|
||||||
.describe("type", "type of change");
|
|
||||||
},
|
|
||||||
handler,
|
|
||||||
};
|
|
@ -1,83 +0,0 @@
|
|||||||
import yaml from "yaml";
|
|
||||||
import fs from "fs-extra";
|
|
||||||
import u from "@yanick/updeep-remeda";
|
|
||||||
import semverInc from "semver/functions/inc.js";
|
|
||||||
import { simpleGit } from "simple-git";
|
|
||||||
|
|
||||||
import { base_next_version } from "../utils.js";
|
|
||||||
|
|
||||||
const code_churn = async (previous_version) => {
|
|
||||||
previous_version = previous_version
|
|
||||||
? "v" + previous_version.version
|
|
||||||
: "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; // empty tree sha1
|
|
||||||
|
|
||||||
return simpleGit().diff(["--shortstat", previous_version, "HEAD"]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
config.consola.start("cutting the next version...");
|
|
||||||
|
|
||||||
const changelog = await config.changelog();
|
|
||||||
|
|
||||||
const next = changelog.releases.find(u.matches({ version: "NEXT" }));
|
|
||||||
|
|
||||||
if (!next) throw new Error("no changes since last version, aborting");
|
|
||||||
|
|
||||||
const previous_version = changelog.releases.find(
|
|
||||||
({ version }) => version !== "NEXT"
|
|
||||||
);
|
|
||||||
|
|
||||||
next.date = new Date().toISOString().replace(/T.*/, "");
|
|
||||||
|
|
||||||
const type_to_level = (type = "") =>
|
|
||||||
changelog.change_types.find((t) => t.keywords.includes(type)).level;
|
|
||||||
|
|
||||||
const bump_level = (types) =>
|
|
||||||
types.includes("major")
|
|
||||||
? "major"
|
|
||||||
: types.includes("minor")
|
|
||||||
? "minor"
|
|
||||||
: "patch";
|
|
||||||
|
|
||||||
const bumper = bump_level(
|
|
||||||
next.changes.map(({ type }) => type_to_level(type))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (changelog.project?.with_stats) {
|
|
||||||
next.changes.push({
|
|
||||||
type: "stats",
|
|
||||||
desc: "code churn:" + (await code_churn(previous_version)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
next.version = semverInc(
|
|
||||||
previous_version ? previous_version.version : "0.0.0",
|
|
||||||
bumper
|
|
||||||
);
|
|
||||||
|
|
||||||
// add a new NEXT
|
|
||||||
changelog.releases.unshift(base_next_version);
|
|
||||||
|
|
||||||
if (config.dry) {
|
|
||||||
config.consola.info("running in dry mode, not saving\n", next);
|
|
||||||
} else {
|
|
||||||
await config.save_changelog(changelog);
|
|
||||||
if (changelog.project?.next_directory) {
|
|
||||||
config.consola.info(
|
|
||||||
`removing files in ${changelog.project.next_directory}`
|
|
||||||
);
|
|
||||||
await config.delete_next_dir_entries();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.consola.success(`version ${next.version} is cut!`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: "cut",
|
|
||||||
desc: "cut the next version",
|
|
||||||
builder: (yargs) => {
|
|
||||||
yargs.boolean("dry");
|
|
||||||
},
|
|
||||||
handler,
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
import { test, expect, vi } from "vitest";
|
|
||||||
import cut from "./cut.js";
|
|
||||||
|
|
||||||
test("add a new NEXT", async () => {
|
|
||||||
const changelog = {
|
|
||||||
releases: [{ version: "NEXT", changes: [] }, { version: "1.0.0" }],
|
|
||||||
};
|
|
||||||
|
|
||||||
const noop = () => {};
|
|
||||||
const config = {
|
|
||||||
consola: {
|
|
||||||
start: noop,
|
|
||||||
success: noop,
|
|
||||||
},
|
|
||||||
changelog: () => changelog,
|
|
||||||
save_changelog: noop,
|
|
||||||
};
|
|
||||||
|
|
||||||
await cut.handler(config);
|
|
||||||
|
|
||||||
expect(changelog.releases[0].version).toBe("NEXT");
|
|
||||||
expect(changelog.releases).toHaveLength(3);
|
|
||||||
});
|
|
@ -1,55 +0,0 @@
|
|||||||
import simpleGit from "simple-git";
|
|
||||||
import { prop, compact, pickBy } from "remeda";
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
const next = await config.next_release();
|
|
||||||
const seen_sha1s = compact(next?.changes.map(prop("commit")));
|
|
||||||
const seen_descs = next?.changes.map((change) =>
|
|
||||||
typeof change === "string" ? change : change.desc
|
|
||||||
);
|
|
||||||
|
|
||||||
const git = config.git();
|
|
||||||
|
|
||||||
const { version } = await config.latest_version();
|
|
||||||
|
|
||||||
let { all: commits } = await git.log({
|
|
||||||
from: "v" + version,
|
|
||||||
});
|
|
||||||
|
|
||||||
config.consola.start(`gathering changes since v${version}`);
|
|
||||||
|
|
||||||
commits = commits.filter(({ hash }) => !seen_sha1s.includes(hash));
|
|
||||||
|
|
||||||
const regex = new RegExp(
|
|
||||||
(await config.changelog().project?.commit_regex) ??
|
|
||||||
/^(?<type>[^: ]+):\s*(?<desc>.*?)(\[(?<ticket>[^\]]+)\])?$/
|
|
||||||
);
|
|
||||||
|
|
||||||
const changes = commits
|
|
||||||
.map((commit) => [commit, commit.message.match(regex)])
|
|
||||||
.filter((x) => x[1])
|
|
||||||
.filter((x) => !seen_descs.includes(x[1].groups.desc))
|
|
||||||
.map(([commit, res]) =>
|
|
||||||
pickBy({ ...res.groups, commit: commit.hash }, (x) => x)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (changes.length === 0) {
|
|
||||||
config.consola.success("no changes detected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const change of changes) {
|
|
||||||
config.consola.info(`${change.type}: ${change.desc}`);
|
|
||||||
config.add_to_next(change);
|
|
||||||
}
|
|
||||||
config.consola.success("done");
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: "git-gather",
|
|
||||||
desc: "gather change entries from git commits",
|
|
||||||
builder: (yargs) => {
|
|
||||||
yargs;
|
|
||||||
},
|
|
||||||
handler,
|
|
||||||
};
|
|
@ -1,28 +0,0 @@
|
|||||||
import { test, expect, vi } from "vitest";
|
|
||||||
import gather from "./git-gather.js";
|
|
||||||
|
|
||||||
test("no changes detected", async () => {
|
|
||||||
const changelog = {
|
|
||||||
releases: [{ version: "NEXT", changes: [] }, { version: "1.0.0" }],
|
|
||||||
};
|
|
||||||
|
|
||||||
const noop = () => {};
|
|
||||||
const config = {
|
|
||||||
consola: {
|
|
||||||
start: noop,
|
|
||||||
success: vi.fn(),
|
|
||||||
},
|
|
||||||
changelog: () => changelog,
|
|
||||||
next_release: () => ({
|
|
||||||
changes: [],
|
|
||||||
}),
|
|
||||||
latest_version: () => ({ version: "1.2.3" }),
|
|
||||||
git: () => ({
|
|
||||||
log: () => ({ all: [] }),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
await gather.handler(config);
|
|
||||||
|
|
||||||
expect(config.consola.success).toHaveBeenCalledWith("no changes detected");
|
|
||||||
});
|
|
@ -1,51 +1,50 @@
|
|||||||
import fs from "fs-extra";
|
import fs from 'fs-extra';
|
||||||
import { consola } from "consola";
|
import { consola } from 'consola';
|
||||||
import { stringify } from "yaml";
|
import { stringify } from 'yaml';
|
||||||
|
|
||||||
const change_types = [
|
const change_types = [
|
||||||
{ title: "", level: "minor", keywords: [""] },
|
{ title: 'Features' , level: 'minor', keywords: [ 'feat' ] } ,
|
||||||
{ title: "Features", level: "minor", keywords: ["feat"] },
|
{ title : 'Bug fixes' , level : 'patch', keywords : [ 'fix' ] },
|
||||||
{ title: "Bug fixes", level: "patch", keywords: ["fix"] },
|
{ title : 'Package maintenance' , level : 'patch', keywords : [ 'chore', 'maint', 'refactor' ] },
|
||||||
{
|
{ title : 'Statistics' , level : 'patch', keywords : [ 'stats' ] },
|
||||||
title: "Package maintenance",
|
];
|
||||||
level: "patch",
|
|
||||||
keywords: ["chore", "maint", "refactor"],
|
|
||||||
},
|
|
||||||
{ title: "Statistics", level: "patch", keywords: ["stats"] },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const base_changelog = {
|
|
||||||
|
const base_changelog = {
|
||||||
project: {
|
project: {
|
||||||
name: null,
|
name: null,
|
||||||
homepage: null,
|
homepage: null,
|
||||||
with_stats: true,
|
with_stats: true,
|
||||||
|
ticket_url: null,
|
||||||
},
|
},
|
||||||
releases: [{ version: "NEXT", changes: [] }],
|
releases: [
|
||||||
|
{ version: 'NEXT', changes: [] }
|
||||||
|
],
|
||||||
change_types,
|
change_types,
|
||||||
};
|
};
|
||||||
|
|
||||||
const handler = async (config) => {
|
const handler = async (config) => {
|
||||||
if (await fs.pathExists(config.source)) {
|
if( await fs.pathExists(config.source) ) {
|
||||||
consola.error(`${config.source} already exist, aborting.`);
|
consola.error(`${config.source} already exist, aborting.`);
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
consola.start(`creating ${config.source}...`);
|
consola.start(`creating ${config.source}...`);
|
||||||
|
|
||||||
await fs.writeFile(config.source, stringify(base_changelog));
|
await fs.writeFile( config.source, stringify(base_changelog) );
|
||||||
|
|
||||||
|
consola.success('done!');
|
||||||
|
|
||||||
consola.success("done!");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
command: "init",
|
command: 'init',
|
||||||
desc: "initialize new changelog source file",
|
desc : 'initialize new changelog source file',
|
||||||
builder: (yargs) => {
|
builder: (yargs) => {
|
||||||
yargs
|
yargs.boolean('json')
|
||||||
.boolean("json")
|
.boolean('next')
|
||||||
.boolean("next")
|
.default('json',false)
|
||||||
.default("json", false)
|
.default('next',true);
|
||||||
.default("next", true);
|
|
||||||
},
|
},
|
||||||
handler,
|
handler,
|
||||||
};
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import yaml from "yaml";
|
|
||||||
import fs from "fs-extra";
|
|
||||||
|
|
||||||
export async function latest_version() {
|
|
||||||
const changelog = await this.changelog();
|
|
||||||
|
|
||||||
return changelog.releases.find(({ version }) => version !== "NEXT");
|
|
||||||
}
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
const latest_version = config.latest_version()?.version ?? "0.0.0";
|
|
||||||
|
|
||||||
if (config.json) {
|
|
||||||
config.consola.raw(latest_version);
|
|
||||||
} else {
|
|
||||||
config.consola.raw(latest_version.version);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: "latest-version",
|
|
||||||
desc: "output the latest version present in the changelog",
|
|
||||||
builder: (yargs) => {
|
|
||||||
yargs
|
|
||||||
.boolean("json")
|
|
||||||
.describe("json", "output latest version entry as json");
|
|
||||||
},
|
|
||||||
handler,
|
|
||||||
};
|
|
@ -1,135 +1,16 @@
|
|||||||
import * as R from "remeda";
|
|
||||||
import fs from "fs-extra";
|
|
||||||
import yaml from "yaml";
|
|
||||||
import mkd from "markdown-utils";
|
|
||||||
|
|
||||||
const render_header = (source) => {
|
const handler = (...args) => {
|
||||||
let header = "# Changelog";
|
console.log('hi!',args);
|
||||||
|
|
||||||
let name = source.project?.name;
|
|
||||||
|
|
||||||
const links = {};
|
|
||||||
|
|
||||||
if (source?.project?.homepage) {
|
|
||||||
links.homepage = source?.project?.homepage;
|
|
||||||
name = `[${name}][homepage]`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name) header += ` for ${name}`;
|
|
||||||
|
|
||||||
return { header, links };
|
|
||||||
};
|
|
||||||
|
|
||||||
function render_links(links) {
|
|
||||||
return Object.entries(links)
|
|
||||||
.map(([name, url]) => ` [${name}]: ${url}`)
|
|
||||||
.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
const render_change = (config, source) => (change) => {
|
|
||||||
let body = change.desc;
|
|
||||||
let links = {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
body,
|
|
||||||
links,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const render_release = (config, source) => (release) => {
|
|
||||||
let links = {};
|
|
||||||
|
|
||||||
if (typeof release === "string")
|
|
||||||
return {
|
|
||||||
body: release,
|
|
||||||
links,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (release.version === "NEXT" && !config.next)
|
|
||||||
return {
|
|
||||||
body: "",
|
|
||||||
links,
|
|
||||||
};
|
|
||||||
|
|
||||||
let body = "## " + release.version;
|
|
||||||
|
|
||||||
if (release.date) {
|
|
||||||
body += " " + release.date;
|
|
||||||
}
|
|
||||||
|
|
||||||
body += "\n\n";
|
|
||||||
|
|
||||||
const type_map = Object.fromEntries(
|
|
||||||
source.change_types.flatMap((entry) =>
|
|
||||||
entry.keywords.map((k) => [k, entry])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const changes = release.changes.map((change) =>
|
|
||||||
typeof change === "string" ? { desc: change, type: "" } : change
|
|
||||||
);
|
|
||||||
|
|
||||||
const unknown = R.uniq(
|
|
||||||
changes
|
|
||||||
.map(R.prop("type"))
|
|
||||||
.map((t) => t ?? "")
|
|
||||||
.filter((type) => !type_map[type])
|
|
||||||
);
|
|
||||||
|
|
||||||
if (unknown.length) {
|
|
||||||
throw new Error(
|
|
||||||
"unknown change types encountered: " +
|
|
||||||
unknown.map((t) => `'${t}'`).join(", ")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const change_type of source.change_types) {
|
|
||||||
const type_changes = changes.filter(({ type }) =>
|
|
||||||
change_type.keywords.includes(type)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (type_changes.length === 0) continue;
|
|
||||||
|
|
||||||
if (change_type.title) body += "\n" + mkd.h3(change_type.title) + "\n\n";
|
|
||||||
|
|
||||||
for (const c of type_changes) {
|
|
||||||
const res = render_change(config, source)(c);
|
|
||||||
body += mkd.li(res.body, 1) + "\n";
|
|
||||||
links = { ...links, ...res.links };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { body, links };
|
|
||||||
};
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
const source = await config.changelog();
|
|
||||||
|
|
||||||
let output = "";
|
|
||||||
|
|
||||||
let { header, links } = render_header(source);
|
|
||||||
|
|
||||||
output += header + "\n\n";
|
|
||||||
|
|
||||||
for (const res of source.releases.map(render_release(config, source))) {
|
|
||||||
output += res.body + "\n\n";
|
|
||||||
links = { ...links, ...res.links };
|
|
||||||
}
|
|
||||||
|
|
||||||
output += "\n\n\n\n" + render_links(links);
|
|
||||||
|
|
||||||
config.consola.raw(output);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
command: "print",
|
command: 'print',
|
||||||
desc: "render the changelog",
|
desc : 'render the changelog',
|
||||||
builder: (yargs) => {
|
builder: (yargs) => {
|
||||||
yargs
|
yargs.boolean('json')
|
||||||
//.boolean('json')
|
.boolean('next')
|
||||||
.boolean("next")
|
.default('json',false)
|
||||||
// .default('json',false)
|
.default('next',true);
|
||||||
.default("next", true);
|
|
||||||
},
|
},
|
||||||
handler,
|
handler,
|
||||||
};
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import { test, expect, vi } from 'vitest';
|
|
||||||
import { render_release } from './print.js';
|
|
||||||
import { base_changelog } from './init.js';
|
|
||||||
|
|
||||||
test( 'render_release a string', () => {
|
|
||||||
const {body} = render_release({})("as is");
|
|
||||||
expect(body).toEqual('as is');
|
|
||||||
});
|
|
||||||
|
|
||||||
test( 'render_release', () => {
|
|
||||||
const consola = { error: vi.fn() };
|
|
||||||
const res= render_release({consola},base_changelog)({
|
|
||||||
version: '1.2.3',
|
|
||||||
date: 'today',
|
|
||||||
changes: [
|
|
||||||
"this",
|
|
||||||
"that",
|
|
||||||
]
|
|
||||||
});
|
|
||||||
expect(res.body).toContain('# 1.2.3 today');
|
|
||||||
expect(res.body).toContain('* this');
|
|
||||||
});
|
|
@ -1,9 +1,12 @@
|
|||||||
import fs from "fs-extra";
|
import fs from "fs-extra";
|
||||||
import yaml from "yaml";
|
|
||||||
import schemaV1 from "../changelog-schema.js";
|
|
||||||
|
|
||||||
const handler = async ({ consola }) => {
|
const handler = async ({consola}) => {
|
||||||
consola.raw(yaml.stringify(schemaV1));
|
consola.raw(
|
||||||
|
await fs.readFile(
|
||||||
|
new URL("../changelog-schema.yml", import.meta.url),
|
||||||
|
"utf-8"
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import u from "@yanick/updeep-remeda";
|
|
||||||
import fs from "fs-extra";
|
|
||||||
import yaml from "yaml";
|
|
||||||
import { render_release } from "./print.js";
|
|
||||||
|
|
||||||
export async function next_release() {
|
|
||||||
const source = await this.changelog();
|
|
||||||
return (
|
|
||||||
source.releases.find(u.matches({ version: "NEXT" })) ?? {
|
|
||||||
version: "NEXT",
|
|
||||||
changes: [],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handler = async (config) => {
|
|
||||||
const source = await config.changelog();
|
|
||||||
|
|
||||||
const { body } = render_release(
|
|
||||||
{ ...config, next: true },
|
|
||||||
source
|
|
||||||
)(await config.next_release());
|
|
||||||
|
|
||||||
config.consola.raw("\n" + body);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: "upcoming",
|
|
||||||
desc: "output the changes in NEXT",
|
|
||||||
handler,
|
|
||||||
};
|
|
@ -1,29 +0,0 @@
|
|||||||
import { test, expect, vi } from "vitest";
|
|
||||||
import upcoming from "./upcoming.js";
|
|
||||||
|
|
||||||
test("basic", async () => {
|
|
||||||
const changelog = {
|
|
||||||
releases: [{ version: "NEXT", changes: [] }, { version: "1.0.0" }],
|
|
||||||
change_types: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const noop = () => {};
|
|
||||||
const config = {
|
|
||||||
consola: {
|
|
||||||
start: noop,
|
|
||||||
raw: vi.fn(),
|
|
||||||
},
|
|
||||||
changelog: () => changelog,
|
|
||||||
next_release: () => ({
|
|
||||||
changes: [],
|
|
||||||
}),
|
|
||||||
latest_version: () => ({ version: "1.2.3" }),
|
|
||||||
git: () => ({
|
|
||||||
log: () => ({ all: [] }),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
await upcoming.handler(config);
|
|
||||||
|
|
||||||
expect(config.consola.raw).toHaveBeenCalled();
|
|
||||||
});
|
|
@ -1,16 +0,0 @@
|
|||||||
const handler = async (config) => {
|
|
||||||
config.consola.start("validating changelog...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await config.changelog();
|
|
||||||
config.consola.success("valid!");
|
|
||||||
} catch (e) {
|
|
||||||
config.yargs.exit(1, "changelog is invalid :-(");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
command: "validate",
|
|
||||||
desc: "validate the changelog against its json schema",
|
|
||||||
handler,
|
|
||||||
};
|
|
@ -1,16 +0,0 @@
|
|||||||
import { test, expect, vi } from "vitest";
|
|
||||||
import validate from "./validate.js";
|
|
||||||
|
|
||||||
test("basic", async () => {
|
|
||||||
const success = vi.fn();
|
|
||||||
const noop = () => true;
|
|
||||||
await validate.handler({
|
|
||||||
changelog: () => ({}),
|
|
||||||
consola: {
|
|
||||||
start: noop,
|
|
||||||
success,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(success).toHaveBeenCalled();
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
export const base_next_version = {
|
|
||||||
version: "NEXT",
|
|
||||||
changes: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.freeze(base_next_version);
|
|
Loading…
Reference in New Issue
Block a user