Skip to content

Commit

Permalink
two step release process
Browse files Browse the repository at this point in the history
  • Loading branch information
Theodus committed Apr 22, 2017
1 parent 643e2b1 commit 2da093c
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 128 deletions.
19 changes: 5 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,6 @@ changelog-tool release CHANGELOG.md 0.13.1
All notable changes to the Pony compiler and standard library will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a CHANGELOG](http://keepachangelog.com/).
## [unreleased] - unreleased
### Fixed
### Added
### Changed
## [0.13.1] - 2017-04-14
### Added
Expand All @@ -77,3 +63,8 @@ All notable changes to the Pony compiler and standard library will be documented
```

Note that a new unreleased area has been added to the top of the changelog and only the `Added` section of the previous unreleased area has been included in the 0.13.1 release since the other two sections had no entries.

An empty unreleased section may then be added with the command
```bash
changelog-tool unreleased CHANGELOG.md -e
```
47 changes: 30 additions & 17 deletions changelog.pony
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
use ".deps/sylvanc/peg"

class Changelog
let unreleased: Release
let unreleased: (Release | None)
let released: Array[Release]

new create(ast: AST) ? =>
let children = ast.children.values()
unreleased = Release(children.next() as AST)
released = Array[Release](ast.size() - 1)
for child in children do
released.push(Release(child as AST))
released = Array[Release](ast.size())
if ast.size() > 0 then
unreleased = try Release(children.next() as AST) end
for child in children do
released.push(Release(child as AST))
end
else
unreleased = None
end

new _create(unreleased': Release, released': Array[Release]) =>
new _create(unreleased': (Release | None), released': Array[Release]) =>
(unreleased, released) = (unreleased', released')

fun ref create_release(version: String, date: String): Changelog^ ? =>
unreleased.heading = "## [" + version + "] - " + date
match unreleased
| let r: Release =>
r.heading = "## [" + version + "] - " + date

if (unreleased.fixed as Section).entries == "" then
unreleased.fixed = None
end
if (unreleased.added as Section).entries == "" then
unreleased.added = None
end
if (unreleased.changed as Section).entries == "" then
unreleased.changed = None
if (r.fixed as Section).entries == "" then
r.fixed = None
end
if (r.added as Section).entries == "" then
r.added = None
end
if (r.changed as Section).entries == "" then
r.changed = None
end

_create(None, released.>unshift(r))
else this
end

_create(Release._unreleased(), released.>unshift(unreleased))
fun ref create_unreleased(): Changelog^ =>
if unreleased is None then _create(Release._unreleased(), released)
else this
end

fun string(): String iso^ =>
let str = (recover String end)
.>append(_Util.changelog_heading())
.>append("\n")
.>append(unreleased.string())
if unreleased isnt None then str.append(unreleased.string()) end
for release in released.values() do
str.append(release.string())
end
Expand Down
2 changes: 1 addition & 1 deletion changelog_parser.pony
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ primitive ChangelogParser
fun apply(): Parser val =>
recover
let heading = L(_Util.changelog_heading())
-heading * -L("\n").many1() * release(false) * release().many()
-heading * -L("\n").many1() * release(false).opt() * release().many()
end

fun release(released: Bool = true): Parser val =>
Expand Down
76 changes: 76 additions & 0 deletions changelog_tool.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use "files"
use "time"
use ".deps/sylvanc/peg"

class ChangelogTool
let _env: Env
let _filename: String
let _filepath: FilePath

new create(env: Env, filename: String, filepath: FilePath) =>
(_env, _filename, _filepath) = (env, filename, filepath)

fun verify() =>
_env.out.print("verifying " + _filename + "...")
try
let ast = _parse()
_env.out.print(_filename + " is a valid changelog")
end

fun release(version: String, edit: Bool) =>
try
_check_version(version)
let date = Date(Time.seconds()).format("%Y-%m-%d")
let changelog: String = Changelog(_parse())
.create_release(version, date)
.string()
_edit_or_print(edit, changelog)
else
_env.err.print("unable to perform release prep")
end

fun _check_version(version: String) ? =>
// chack if version is valid
let source = Source.from_string(version)
match recover val ChangelogParser.version().parse(source) end
| (_, let t: Token) => None
else
_env.err.print("invalid version number: '" + version + "'")
error
end

fun unreleased(edit: Bool) =>
try
let changelog: String = Changelog(_parse())
.create_unreleased()
.string()
_edit_or_print(edit, changelog)
else
_env.out.print("error")
end

fun _edit_or_print(edit: Bool, s: String) =>
if edit then
with file = File(_filepath) do
file
.>write(s)
.>flush()
end
else
_env.out.print(s)
end

fun _parse(): AST ? =>
let source = Source(FilePath(_env.root as AmbientAuth, _filename))
match recover val ChangelogParser().parse(source) end
| (_, let ast: AST) =>
//_env.out.print(recover val Printer(ast) end)
ast
| (let offset: USize, let r: Parser val) =>
let e = recover val SyntaxError(source, offset, r) end
_env.err.writev(PegFormatError.console(e))
error
else
_env.err.print("unable to parse file: " + _filename)
error
end
114 changes: 18 additions & 96 deletions main.pony
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
use "files"
use "options"
use "time"
use ".deps/sylvanc/peg"

/*
1. have a part that can validate a changelog file
2. have a part that can remove entries after validating
we want to use part 1 when CI runs
to not allow “invalid” changelogs through
because otherwise removal will go boom
also
look now our CHANGELOG is a langauge
lulz
*/

actor Main
let _env: Env
var _filename: String = ""

new create(env: Env) =>
_env = env
// TODO use the new cli package
// https://github.com/ponylang/ponyc/issues/1737
let options = Options(_env.args)
let options = Options(env.args)
.>add("edit", "e", None)

try
Expand All @@ -38,7 +14,7 @@ actor Main
match option
| ("edit", None) => edit = true
| let err: ParseError =>
err.report(_env.err)
err.report(env.err)
error
end
end
Expand All @@ -48,88 +24,34 @@ actor Main
args.push(arg.clone())
end

_filename = args(2)
let filename = args(2)
let filepath =
try
FilePath(env.root as AmbientAuth, filename)
else
env.err.print("unable to open: " + filename)
return
end
let tool = ChangelogTool(env, filename, filepath)

match args(1)
| "verify" => verify()
| "release" => release(args(3), edit)
| "verify" => tool.verify()
| "release" => tool.release(args(3), edit)
| "unreleased" => tool.unreleased(edit)
else error
end
else
_env.out.print(
env.out.print(
"""
changelog-tool COMMAND <changelog file> [...]
Commands:
verify Verify that the given changelog is valid.
release Print a changelog that is prepared for release.
Example: `changelog-tool release CHANGELOG.md 0.13.1`
unreleased Add unreleased section to changelog if none exists.
Options:
--edit, -e Edit the changelog file (release only).
--edit, -e Edit the changelog file (release and unreleased only).
""")
return
end

fun verify() =>
_env.out.print("verifying " + _filename + "...")
try
let ast = parse()
_env.out.print(_filename + " is a valid changelog")
end

fun release(version: String, edit: Bool) =>
try
check_version(version)
let ast = parse()
let date = Date(Time.seconds()).format("%Y-%m-%d")
let changelog = Changelog(ast)
.create_release(version, date)
let changelog_str: String = changelog.string()

if edit then
with
file = File(FilePath(_env.root as AmbientAuth, _filename))
do
file
.>write(changelog_str)
.>flush()
end
else
_env.out.print(changelog_str)
end
else
_env.err.print("unable to perform release prep")
end

fun check_version(version: String) ? =>
// chack if version is valid
let source = Source.from_string(version)
match recover val ChangelogParser.version().parse(source) end
| (_, let t: Token) => None
else
_env.err.print("invalid version number: '" + version + "'")
error
end

fun parse(): AST ? =>
try
let source = Source(FilePath(_env.root as AmbientAuth, _filename))
match
recover val
ChangelogParser().parse(source)
end
| (_, let ast: AST) =>
//_env.out.print(recover val Printer(ast) end)
ast
| (let offset: USize, let r: Parser val) =>
let e = recover val SyntaxError(source, offset, r) end
_env.err.writev(PegFormatError.console(e))
error
else
_env.err.print("unable to parse file: " + _filename)
error
end
else
_env.err.print("unable to open: " + _filename)
error
end

0 comments on commit 2da093c

Please sign in to comment.