Initial commit
This commit is contained in:
commit
8f254ca247
|
@ -0,0 +1,3 @@
|
||||||
|
dist/
|
||||||
|
lib/
|
||||||
|
node_modules/
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"plugins": ["jest", "@typescript-eslint"],
|
||||||
|
"extends": ["plugin:github/es6"],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 9,
|
||||||
|
"sourceType": "module",
|
||||||
|
"project": "./tsconfig.json"
|
||||||
|
},
|
||||||
|
"rules": {},
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es6": true,
|
||||||
|
"jest/globals": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
# Dependency directory
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# OS metadata
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Ignore built ts files
|
||||||
|
__tests__/runner/*
|
||||||
|
lib/**/*
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
.idea
|
|
@ -0,0 +1,3 @@
|
||||||
|
dist/
|
||||||
|
lib/
|
||||||
|
node_modules/
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 GitHub, Inc. and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Git Flow releases using GitHub actions
|
||||||
|
|
||||||
|
This GitHub action helps you in automating a Git Flow like release process.
|
||||||
|
|
||||||
|
## What does it do for me?
|
||||||
|
|
||||||
|
This action is designed to listen on the `IssueEvent` "opened".
|
||||||
|
Given an issue with the title "Release version x.y.z", the action will branch of a release branch from the current development branch, update the changelog according to the new version and open a pull request against master.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Define a new workflow like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: "Create a release PR"
|
||||||
|
on:
|
||||||
|
issues: opened
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release-pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: startsWith(github.event.issue.title, "Release version") # only run for issues with a specific title
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Extract version from issue title
|
||||||
|
run: |
|
||||||
|
TITLE=${{ github.event.issue.title }}
|
||||||
|
VERSION=${TITLE#Release version }
|
||||||
|
|
||||||
|
echo "::set-env name=RELEASE_VERSION::$VERSION"
|
||||||
|
|
||||||
|
- name: Create release branch
|
||||||
|
run: git checkout -b release/${{ env.RELEASE_VERSION }}
|
||||||
|
|
||||||
|
- name: Update changelog
|
||||||
|
uses: thomaseizinger/update-changelog-for-release@v1
|
||||||
|
with:
|
||||||
|
version: ${{ env.RELEASE_VERSION }}
|
||||||
|
|
||||||
|
# This step will differ depending on your project setup
|
||||||
|
- name: Bump version in package.json
|
||||||
|
run: yarn version --new-version ${{ env.RELEASE_VERSION }}
|
||||||
|
|
||||||
|
- name: Commit changelog and manifest files
|
||||||
|
run: |
|
||||||
|
git add CHANGELOG.md package.json
|
||||||
|
git commit --message "Prepare release ${{ env.RELEASE_VERSION }}"
|
||||||
|
|
||||||
|
- name: Push new branch
|
||||||
|
run: git push origin release/${{ env.RELEASE_VERSION }}
|
||||||
|
|
||||||
|
- name: Create pull request
|
||||||
|
uses: thomaseizinger/create-pull-request@v1
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: release/${{ env.RELEASE_VERSION }}
|
||||||
|
base: master
|
||||||
|
reviewers: ${{ github.event.issue.user.login }}
|
||||||
|
body: |
|
||||||
|
Resolves #${{ github.event.issue.number }}
|
||||||
|
```
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.3.0] - 2019-12-06
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Our main theme is now blue instead of red.
|
||||||
|
|
||||||
|
## [0.2.0] - 2019-09-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- First feature that is gonna make us money.
|
||||||
|
- Quite a few bugs, sorry in advance!
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Reworked the login system. You have to provide a password now!
|
||||||
|
|
||||||
|
## [0.1.0] - 2019-09-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Initial release :tada:
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/foo/bar/compare/0.3.0...HEAD
|
||||||
|
|
||||||
|
[0.3.0]: https://github.com/foo/bar/compare/0.2.0...0.3.0
|
||||||
|
|
||||||
|
[0.2.0]: https://github.com/foo/bar/compare/0.1.0...0.2.0
|
||||||
|
|
||||||
|
[0.1.0]: https://github.com/foo/bar/compare/1625533e04119e8496b14d5e18786f150b4fce4d...0.1.0
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Our main theme is now blue instead of red.
|
||||||
|
|
||||||
|
## [0.2.0] - 2019-09-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- First feature that is gonna make us money.
|
||||||
|
- Quite a few bugs, sorry in advance!
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Reworked the login system. You have to provide a password now!
|
||||||
|
|
||||||
|
## [0.1.0] - 2019-09-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Initial release :tada:
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/foo/bar/compare/0.2.0...HEAD
|
||||||
|
|
||||||
|
[0.2.0]: https://github.com/foo/bar/compare/0.1.0...0.2.0
|
||||||
|
|
||||||
|
[0.1.0]: https://github.com/foo/bar/compare/1625533e04119e8496b14d5e18786f150b4fce4d...0.1.0
|
|
@ -0,0 +1,25 @@
|
||||||
|
import formatDate from "../src/formatDate";
|
||||||
|
|
||||||
|
it("should format a date with a single digit day correctly", function() {
|
||||||
|
const date = new Date(Date.parse("Dec 09 2019"));
|
||||||
|
|
||||||
|
const formatted = formatDate(date);
|
||||||
|
|
||||||
|
expect(formatted).toEqual("2019-12-09");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should format a date with a double digit day correctly", function() {
|
||||||
|
const date = new Date(Date.parse("Dec 16 2019"));
|
||||||
|
|
||||||
|
const formatted = formatDate(date);
|
||||||
|
|
||||||
|
expect(formatted).toEqual("2019-12-16");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should format a date with a single digit month correctly", function() {
|
||||||
|
const date = new Date(Date.parse("Jan 09 2019"));
|
||||||
|
|
||||||
|
const formatted = formatDate(date);
|
||||||
|
|
||||||
|
expect(formatted).toEqual("2019-01-09");
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
import updateChangelog from "../src/updateChangelog";
|
||||||
|
import { read } from "to-vfile";
|
||||||
|
|
||||||
|
it("should update the changelog correctly", async function() {
|
||||||
|
const before = await read("./__tests__/fixtures/CHANGELOG.1.md", {
|
||||||
|
encoding: "utf-8"
|
||||||
|
});
|
||||||
|
const expected = await read("./__tests__/fixtures/CHANGELOG.1.expected.md", {
|
||||||
|
encoding: "utf-8"
|
||||||
|
});
|
||||||
|
|
||||||
|
const actual = await updateChangelog(before, "0.3.0", "2019-12-06");
|
||||||
|
|
||||||
|
const actualContent = actual.toString("utf-8");
|
||||||
|
const expectedContent = expected.toString("utf-8");
|
||||||
|
|
||||||
|
expect(actualContent).toEqual(expectedContent);
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
name: 'Keep A Changelog - New Release'
|
||||||
|
description: 'Automatically update your CHANGELOG.md for a new release. Built for the keepachangelog.com format.'
|
||||||
|
author: 'Thomas Eizinger'
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'The version of the new release'
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'dist/index.js'
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
||||||
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
testRunner: 'jest-circus/runner',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"name": "keep-a-changelog-new-release-action",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "A GitHub action for updating your Keep-A-Changelog CHANGELOG.md for new releases",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --mode production",
|
||||||
|
"compile": "tsc",
|
||||||
|
"format": "prettier --write **/*.ts",
|
||||||
|
"format-check": "prettier --check **/*.ts",
|
||||||
|
"lint": "eslint src/**/*.ts",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/thomaseizinger/keep-a-changelog-new-release.git"
|
||||||
|
},
|
||||||
|
"author": "Thomas Eizinger",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.2.0",
|
||||||
|
"remark-parse": "^7.0.2",
|
||||||
|
"remark-stringify": "^7.0.4",
|
||||||
|
"unified": "^8.4.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^24.0.23",
|
||||||
|
"@types/node": "^12.7.12",
|
||||||
|
"@types/unist": "^2.0.3",
|
||||||
|
"@types/vfile": "^4.0.0",
|
||||||
|
"@typescript-eslint/parser": "^2.8.0",
|
||||||
|
"eslint": "^5.16.0",
|
||||||
|
"eslint-plugin-github": "^2.0.0",
|
||||||
|
"eslint-plugin-jest": "^22.21.0",
|
||||||
|
"jest": "^24.9.0",
|
||||||
|
"jest-circus": "^24.9.0",
|
||||||
|
"js-yaml": "^3.13.1",
|
||||||
|
"prettier": "^1.19.1",
|
||||||
|
"to-vfile": "^6.0.0",
|
||||||
|
"ts-jest": "^24.2.0",
|
||||||
|
"ts-loader": "^6.2.1",
|
||||||
|
"typescript": "^3.7.3",
|
||||||
|
"webpack": "^4.41.2",
|
||||||
|
"webpack-cli": "^3.3.10"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
export default function formatDate(date: Date): string {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
let month = `${date.getMonth() + 1}`; // JS month is 0 indexed
|
||||||
|
let day = `${date.getDate()}`;
|
||||||
|
|
||||||
|
if (month.length === 1) {
|
||||||
|
month = `0${month}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (day.length === 1) {
|
||||||
|
day = `0${day}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { getInput, setFailed } from "@actions/core";
|
||||||
|
import { read, write } from "to-vfile";
|
||||||
|
import updateChangelog from "./updateChangelog";
|
||||||
|
import formatDate from "./formatDate";
|
||||||
|
|
||||||
|
async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const version = getInput("version");
|
||||||
|
const today = formatDate(new Date());
|
||||||
|
const changelog = await read("CHANGELOG.md", { encoding: "utf-8" });
|
||||||
|
|
||||||
|
const newChangelog = await updateChangelog(changelog, version, today);
|
||||||
|
|
||||||
|
await write(newChangelog, { encoding: "utf-8" });
|
||||||
|
} catch (error) {
|
||||||
|
setFailed(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
|
@ -0,0 +1,271 @@
|
||||||
|
import unified, { Transformer } from "unified";
|
||||||
|
import markdown from "remark-parse";
|
||||||
|
import stringify from "remark-stringify";
|
||||||
|
import vFile, { VFile } from "vfile";
|
||||||
|
import { Node, Position } from "unist";
|
||||||
|
import { version } from "punycode";
|
||||||
|
|
||||||
|
type MarkdownRootNode = {
|
||||||
|
type: "root";
|
||||||
|
children: MarkdownNode[];
|
||||||
|
};
|
||||||
|
|
||||||
|
interface HeadingNode {
|
||||||
|
type: "heading";
|
||||||
|
depth: number;
|
||||||
|
children: MarkdownNode[];
|
||||||
|
position: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DefinitionNode {
|
||||||
|
type: "definition";
|
||||||
|
identifier: string;
|
||||||
|
label: string;
|
||||||
|
url: string;
|
||||||
|
position?: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ListNode {
|
||||||
|
type: "list";
|
||||||
|
ordered: boolean;
|
||||||
|
start: any;
|
||||||
|
spread: boolean;
|
||||||
|
url: string;
|
||||||
|
children: object[];
|
||||||
|
position: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParagraphNode {
|
||||||
|
type: "paragraph";
|
||||||
|
children: object[];
|
||||||
|
position: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LinkReferenceNode {
|
||||||
|
type: "linkReference";
|
||||||
|
identifier: string;
|
||||||
|
label: string;
|
||||||
|
referenceType: string;
|
||||||
|
children: TextNode[];
|
||||||
|
position?: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TextNode {
|
||||||
|
type: "text";
|
||||||
|
value: string;
|
||||||
|
position?: Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MarkdownNode =
|
||||||
|
| HeadingNode
|
||||||
|
| DefinitionNode
|
||||||
|
| ListNode
|
||||||
|
| ParagraphNode
|
||||||
|
| LinkReferenceNode
|
||||||
|
| TextNode;
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
version: string;
|
||||||
|
releaseDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function releaseTransformation({ version, releaseDate }: Options) {
|
||||||
|
return transformer as Transformer;
|
||||||
|
|
||||||
|
function transformer(tree: MarkdownRootNode, file: VFile) {
|
||||||
|
const previousVersion = determinePreviousVersion(tree);
|
||||||
|
convertUnreleasedSectionToNewRelease(tree, version, releaseDate);
|
||||||
|
addEmptyUnreleasedSection(tree);
|
||||||
|
updateCompareUrls(tree, version, previousVersion);
|
||||||
|
|
||||||
|
return tree as Node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function determinePreviousVersion(tree: MarkdownRootNode): string {
|
||||||
|
const children = tree.children;
|
||||||
|
|
||||||
|
const versions = children.filter(
|
||||||
|
node => node.type === "heading" && node.depth === 2
|
||||||
|
);
|
||||||
|
|
||||||
|
let unreleasedSection = versions.shift();
|
||||||
|
|
||||||
|
let previousRelease = versions.shift() as HeadingNode | undefined;
|
||||||
|
|
||||||
|
if (!previousRelease) {
|
||||||
|
throw new Error("Could not determine the release prior to this one!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkReference = previousRelease.children[0];
|
||||||
|
|
||||||
|
if (!linkReference || linkReference.type !== "linkReference") {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid changelog format, previous version is not a link reference"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkReferenceTextNode = linkReference.children[0];
|
||||||
|
|
||||||
|
if (!linkReferenceTextNode) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid changelog format, link reference does not have a text"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkReferenceTextNode.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertUnreleasedSectionToNewRelease(
|
||||||
|
tree: MarkdownRootNode,
|
||||||
|
version: string,
|
||||||
|
releaseDate: string
|
||||||
|
) {
|
||||||
|
const children = tree.children;
|
||||||
|
|
||||||
|
// the unreleased section should always be at the top
|
||||||
|
const unreleasedSection = children.find(
|
||||||
|
node => node.type === "heading" && node.depth === 2
|
||||||
|
) as HeadingNode | undefined;
|
||||||
|
|
||||||
|
if (!unreleasedSection) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid changelog format, could not find Unreleased section"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const child = unreleasedSection.children.shift();
|
||||||
|
|
||||||
|
if (
|
||||||
|
!child ||
|
||||||
|
unreleasedSection.children.length > 0 ||
|
||||||
|
child.type !== "linkReference"
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid changelog format, Unreleased section should only be a link reference"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = ` - ${releaseDate}`;
|
||||||
|
|
||||||
|
const newReleaseSection: [LinkReferenceNode, TextNode] = [
|
||||||
|
{
|
||||||
|
type: "linkReference",
|
||||||
|
identifier: version,
|
||||||
|
label: version,
|
||||||
|
referenceType: "shortcut",
|
||||||
|
position: child.position,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
value: version
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
value: value
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
unreleasedSection.children = newReleaseSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEmptyUnreleasedSection(tree: MarkdownRootNode) {
|
||||||
|
const children = tree.children;
|
||||||
|
|
||||||
|
const firstHeadingSectionIndex = children.findIndex(
|
||||||
|
node => node.type === "heading" && node.depth === 2
|
||||||
|
);
|
||||||
|
|
||||||
|
const beforeFirstHeading = children.slice(0, firstHeadingSectionIndex);
|
||||||
|
const afterFirstHeading = children.slice(firstHeadingSectionIndex);
|
||||||
|
|
||||||
|
tree.children = [
|
||||||
|
...beforeFirstHeading,
|
||||||
|
{
|
||||||
|
type: "heading",
|
||||||
|
depth: 2,
|
||||||
|
position: {} as Position,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "linkReference",
|
||||||
|
identifier: "unreleased",
|
||||||
|
label: "Unreleased",
|
||||||
|
referenceType: "shortcut",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
value: "Unreleased"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...afterFirstHeading
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCompareUrls(
|
||||||
|
tree: MarkdownRootNode,
|
||||||
|
newVersion: string,
|
||||||
|
previousVersion: string
|
||||||
|
) {
|
||||||
|
const children = tree.children;
|
||||||
|
|
||||||
|
const firstDefinitionNodeIndex = children.findIndex(
|
||||||
|
node => node.type === "definition"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (firstDefinitionNodeIndex === -1) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid changelog format, unable to find definitions section"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const beforeFirstDefinition = children.slice(0, firstDefinitionNodeIndex);
|
||||||
|
const definitions = children.slice(firstDefinitionNodeIndex);
|
||||||
|
|
||||||
|
const firstDefinition = definitions.shift() as DefinitionNode;
|
||||||
|
|
||||||
|
const unreleasedCompareUrl = firstDefinition.url.replace(
|
||||||
|
previousVersion,
|
||||||
|
newVersion
|
||||||
|
);
|
||||||
|
const previousVersionCompareUrl = firstDefinition.url.replace(
|
||||||
|
"HEAD",
|
||||||
|
newVersion
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.children = [
|
||||||
|
...beforeFirstDefinition,
|
||||||
|
{
|
||||||
|
type: "definition",
|
||||||
|
identifier: "unreleased",
|
||||||
|
url: unreleasedCompareUrl,
|
||||||
|
label: "Unreleased"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "definition",
|
||||||
|
identifier: newVersion,
|
||||||
|
url: previousVersionCompareUrl,
|
||||||
|
label: newVersion
|
||||||
|
},
|
||||||
|
...definitions
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function updateChangelog(
|
||||||
|
file: VFile,
|
||||||
|
version: string,
|
||||||
|
releaseDate: string
|
||||||
|
): Promise<VFile> {
|
||||||
|
return await unified()
|
||||||
|
.use(markdown)
|
||||||
|
.use(releaseTransformation, {
|
||||||
|
version,
|
||||||
|
releaseDate
|
||||||
|
})
|
||||||
|
.use(stringify)
|
||||||
|
.process(file);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
"./types"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
declare module 'to-vfile' {
|
||||||
|
import {VFile} from "vfile";
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
encoding: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function read(path: string, options: Options): Promise<VFile>;
|
||||||
|
function write(file: VFile, options: Options): Promise<void>;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/index.ts',
|
||||||
|
target: 'node',
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
compilerOptions: {
|
||||||
|
noEmit: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [ '.tsx', '.ts', '.js' ],
|
||||||
|
// see https://stackoverflow.com/a/59267337/2489334
|
||||||
|
alias: {
|
||||||
|
'universal-user-agent': path.resolve(__dirname, 'node_modules/universal-user-agent/dist-node/index.js')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: 'index.js',
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
},
|
||||||
|
};
|
Loading…
Reference in New Issue