Giter Site home page Giter Site logo

keep-a-changelog's Introduction

Changelog

Keep a Changelog library for Node & Deno

Deno package to parse and generate changelogs following the keepachangelog format.

Usage in Node

import { parser } from "keep-a-changelog";
import fs from "fs";

//Parse a changelog file
const changelog = parser(fs.readFileSync("CHANGELOG.md", "UTF-8"));

//Generate the new changelog string
console.log(changelog.toString());

Usage in Deno

import { parser } from "https://deno.land/x/[email protected]/mod.ts";

//Parse a changelog file
const changelog = parser(await Deno.readTextFile("CHANGELOG.md"));

//Generate the new changelog string
console.log(changelog.toString());

Create a new changelog

import {
  Changelog,
  Release,
} from "https://deno.land/x/[email protected]/mod.ts";

const changelog = new Changelog("My project")
  .addRelease(
    new Release("0.1.0", "2017-12-06")
      .added("New awesome feature")
      .added("New other awesome feature")
      .fixed("Bug #3")
      .removed("Drop support for X"),
  )
  .addRelease(
    new Release("0.2.0", "2017-12-09")
      .security("Fixed security vulnerability")
      .deprecated("Feature X is deprecated"),
  );

console.log(changelog.toString());

Custom output format

By default, the output format of the markdown is "compact", that removes the space after the headings. You can change it to follow the markdownlint rules:

const changelog = new Changelog();
changelog.format = "markdownlint";

Custom tag names

By default, the tag names are v + version number. For example, the tag for the version 2.4.9 is v2.4.9. To change this behavior, set a new tagNameBuilder:

const changelog = new Changelog();
changelog.tagNameBuilder = (release) => `version-${release.version}`;

Custom compare links

By default, compare links are build compliant with GitHub format. To change this behavior, set a new compareLinkBuilder:

const changelog = new Changelog();
changelog.url = "https://bitbucket.org/oscarotero/keep-a-changelog";
changelog.compareLinkBuilder = (previous, release) =>
  `${this.url}/branches/compare/${release.version}%0D${previous.version}`;

Custom Change Types

By default and according to the keepachangelog format, the change types are Added, Changed, Deprecated, Removed, Fixed, and Security.

In case you'd like add another type, you need to extend the Release class to support new types. Additionally, you have to tell the parser that it should create instances of your new extended Release in order to parse your changelog correctly.

For example, we would like to add a type Maintenance. Extend the provided Release class:

class CustomRelease extends Release {
  constructor(version, date, description) {
    super(version, date, description);
    // add whatever types you want - in lowercase
    const newChangeTypes = [
      ["maintenance", []],
    ];

    this.changes = new Map([...this.changes, ...newChangeTypes]);
  }
  // for convenience, add a new method to add change of type 'maintanance'
  maintenance(change) {
    return this.addChange("maintenance", change);
  }
}

And once you want to use the parser:

const releaseCreator = (ver, date, desc) => new CustomRelease(ver, date, desc);
const changelog = parser(changelogTextContent, { releaseCreator });

Cli

This library provides the changelog command to normalize the changelog format. It reads the CHANGELOG.md file and override it with the new format:

Install the library as script

Deno:

deno install --allow-read --allow-write -fr --name changelog https://deno.land/x/changelog/bin.ts

Node:

npm install keep-a-changelog -g

Run the script:

changelog

To use other file name:

changelog --file=History.md

To generate an empty new CHANGELOG.md file:

changelog --init

You can release automatically the latest "Unreleased" version:

changelog --release

If your "Unreleased" section has no version, you can specify it as an argument:

changelog --release 2.0.0

And return the latest released version:

changelog --latest-release
> 2.0.0

Available options:

Option Description
--format The output format for the generated markdown. It can be markdownlint or compact. The default value is compact.
--file The markdown file of the changelog. The default value is CHANGELOG.md.
--url The base url used to build the diff urls of the different releases. It is taken from the existing diff urls in the markdown. If no urls are found, try to catch it using the url of the git remote repository.
--https Set to false to use http instead https in the url (--https=false).
--init Init a new empty changelog file.
--latest-release Print the latest release version.
--release Updated the latest unreleased version with the current date. Use --release=X.Y.Z to set a number if the version doesn't have it.
--create Create a new Unreleased version. Use --create=X.Y.Z to specify a version number or just --create for a version without number.
--quiet Do not output error messages
--head Customize the head reference

keep-a-changelog's People

Contributors

cliffano avatar codyjroberts avatar dekpient avatar glandos avatar jhogendorn avatar nowells avatar oscarotero avatar trivialkettle avatar wareczek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

keep-a-changelog's Issues

Option to fail the changelog command if parsing fails

Hi! Thanks for this tool.

We're using the changelog command to ensure our CHANGELOG.md is formatted properly. At the moment, if the file cannot be parsed, it just prints out the error in red. It'd be nice to have an option so it exits with non-zero code. That way we can run the command as part of our CI builds.

I'm good to contribute if you're happy with the idea.

Cheers!

Newline after headings

I prefer to have newline after headings, but this package removes one. Could that be an option to keep or even enforce?

Compare links enforcing `v` tag prefix.

Hi @oscarotero ,

I'm wondering what's the reason for enforcing v prefix prior to the version number when generating compare link at https://github.com/oscarotero/keep-a-changelog/blob/master/src/Release.js#L149 .

        if (!this.version) {
            return `[Unreleased]: ${changelog.url}/compare/v${next.version}...HEAD`;
        }

        if (!this.date) {
            return `[${this.version}]: ${changelog.url}/compare/v${next.version}...HEAD`;
        }

        return `[${this.version}]: ${changelog.url}/compare/v${next.version}...v${this.version}`;

Could this be a keep-a-changelog or semver requirement by any chance?

My use case scenarios are a) the tag is exactly the version value, and b) the tag has a custom prefix then the version value. I'm totally fine if, for scenario b), the custom prefix has to be considered as the version.

Any thoughts on how to best tackle this?

Laxer parsing of release description

Currently, the following entry fails to parse:

## [Unreleased]
This is a brand new releases with:
- Configuration is now done within the Web client, for authorized users.
### Added
- New configuration screen

It seems that the description can only be a <p> tag as parsed. Could it be anything before the first matching change type?

Quality of life

Hello, I recently found this project today, and it was really helpful in my O.S.S projects with Deno, thanks.

However, when installing it I did find some bugs.

The first one is the Deno URL. It should be https://deno.land/x/[email protected]/mod.ts but it has a typo in the readme. it's missing the v in the version number.

The second thing is not a bug but more of a request. Could you please change the access modifiers on some of the classes to private? Its hard to tell which ones are usage functions vs variables.

Example:

export default class Release {
  changelog?: Changelog;
  version?: Semver;
  date?: Date;
  description: string;
  changes: Map<string, Change[]>;
 }
 All these methods can be assessed for no reason and other util functions on the class. It would make it more simple to script the change logs if some were set to private or protected, thanks.

Compile error using Deno 1.11

Thanks for this great library, we were trying to use it with Deno 1.11 and saw the following error:

Check https://raw.githubusercontent.com/oscarotero/keep-a-changelog/deno/bin.js
error: TS2339 [ERROR]: Property 'operator' does not exist on type 'never'.
    if (high!.operator === comp || high!.operator === ecomp) {
              ~~~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1744:15

TS2339 [ERROR]: Property 'operator' does not exist on type 'never'.
    if (high!.operator === comp || high!.operator === ecomp) {
                                         ~~~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1744:42

TS2339 [ERROR]: Property 'operator' does not exist on type 'never'.
      (!low!.operator || low!.operator === comp) &&
             ~~~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1751:14

TS2339 [ERROR]: Property 'operator' does not exist on type 'never'.
      (!low!.operator || low!.operator === comp) &&
                              ~~~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1751:31

TS2339 [ERROR]: Property 'semver' does not exist on type 'never'.
      ltefn(version, low!.semver)
                          ~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1752:27

TS2339 [ERROR]: Property 'operator' does not exist on type 'never'.
    } else if (low!.operator === ecomp && ltfn(version, low!.semver)) {
                    ~~~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1755:21

TS2339 [ERROR]: Property 'semver' does not exist on type 'never'.
    } else if (low!.operator === ecomp && ltfn(version, low!.semver)) {
                                                             ~~~~~~
    at https://deno.land/x/[email protected]/mod.ts:1755:62

Found 7 errors.

It removes the link to the first version

The example changelog here links to the first version, too. The link is to:

[0.0.1]: https://github.com/olivierlacan/keep-a-changelog/releases/tag/v0.0.1

This package removes such link.

--release doesn't do what I expect

I'd like to run a command which releases the Unreleased section.

e.g. before:

## [Unreleased]
### Added
- feature1
- feature2

after:

## [Unreleased]

## [1.2.3] - 2021-03-01
### Added
- feature1
- feature2

yarn changelog --release doesn't seem to do this. My changelog gets normalized, but nothing else seems to happen.

Parsing issue with multi-line links

Scenario

I'm using both keep-a-changelog and Prettier, with a CHANGELOG.md file, and I've hit an issue between them:

  1. keep-a-changelog parses CHANGELOG.md and generates links at the bottom of the file, as expected. Those links are longer than the printWidth we've set for Prettier.
[2.0.0]: https://my-very-long-url/v1.2.3..v2.0.0
[1.2.3]: https://my-very-long-url/v1.2.2..v1.2.3
  1. Prettier runs and wraps long lines -- including the links at the bottom
[2.0.0]:
  https://my-very-long-url/v1.2.3..v2.0.0
[1.2.3]:
  https://my-very-long-url/v1.2.2..v1.2.3
  1. The next time keep-a-changelog parses the changelog, it doesn't recognize those links because they aren't on a single line: they're tokenized as paragraphs and indented appropriately. At that point it looks like the document has no links at all, so all h2's in the changelog get de-linked.

Possible solution

Adding our changelog to .prettierignore did avoid this, as did disabling it with proseWrap (suggested in their issue #4709), but the line-wrap is handy for the rest of the document so I'd prefer to keep it.

Locally, I was able to resolve this by having keep-a-changelog's parser recognize multi-line links:

// src/parser.js:137
if (line.match(/^\[.*\]\:$/)) {
  const nextLine = allLines[index + 1]
  if (nextLine && nextLine.match(/\s*http.*$/)) {
    // We found a multi-line link: treat it like a single line
    allLines[index + 1] = ''
    return ['link', [line.trim() + nextLine.trim()]];
  }
}

(I just split the 'link' regex into two parts, and updated the loop to .map((line, index, allLines))

That worked very well for my use case. My questions are:

  1. Is there a better way to do this, while keeping Prettier? I played around with prettier-ignore and a few other options, but the above solution worked best for me.
  2. Would this change work for other projects, generally? I'm happy to submit a PR if you think it'd be beneficial.

Altering Types of changes

Great tool!

I understand it supports the Types of changes based on https://keepachangelog.com/en/1.0.0/
However, I think that a change of those "Types of changes" could be beneficial to many users. For example some could add a "Upgrade" type or anything else...
Well, it was discussed a while back here brightcove/kacl#6 But with no additional initiative it seems...

Is this something that would be considered?

Solution proposals:

  1. probably the easiest: don't change implementation. the Release class can be extended. Just cover it by a test and mention in documentation, so people can rely on it.
  2. based on point 1. - Have an Additional class ReleaseBase that could e.g. accept another parameter in constructor to define the types. Additionaly, ReleaseBase does not include methods like added, changed etc. Release class would extend ReleaseBase . It still doesn't introduce any breaking changes.
  3. Change the current Release class to accept optional parameter for types (in constructor). No way to add new methods for specific change types.
  4. Have an additional method in Release class setTypes. That just doesn't seem right

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.