3 people like it.
Like the snippet!
Release Notes parser
See: https://github.com/fsharp/FAKE/issues/171
This is a parser for RELEASE_NOTES.md files for F# projects. Handles both simple and more complex file formats described in the link above.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
|
open System
open System.IO
open System.Text.RegularExpressions
// set paths here
let dir = @"..\dev\FSharpScripts\fsharp_comunity_code_sprint\"
let simple_notes = dir + @"RELEASE_NOTES_simple.md"
let complex_notes = dir + @"RELEASE_NOTES_complex.md"
let nugetRegex = Regex(@"([0-9]+.)+[0-9]+(-[a-zA-Z]+)?") // e.g: match "4.1.22-beta"
let assemblyRegex = Regex(@"([0-9]+.)+[0-9]+") // e.g: match "0.13.2"
/// Parse simple release notes sequence
let parseSimpleReleaseNotes (text:seq<string>) =
let lastLine = text |> Seq.last
let assemblyVersion, nugetVersion = assemblyRegex.Match(lastLine), nugetRegex.Match(lastLine)
if not assemblyVersion.Success then
failwith "Unable to parse valid Assembly version from release notes."
let notes = lastLine.Substring(nugetVersion.Index + nugetVersion.Length).Trim([|' '; '-'|]);
assemblyVersion.Value, nugetVersion.Value, [notes]
/// Parse "complex" release notes text sequence
let parseComplexReleaseNotes (text:seq<string>) =
let indexOfLastBlock = // index of last block that begings with {#}+
text
|> Seq.fold (fun (index, ctr) str ->
if String.IsNullOrEmpty(str) then (index, ctr + 1)
elif str.Trim().[0] = '#' then (index + ctr, 1)
else (index, ctr + 1)) (0, 0)
|> fst
let lastBlock = text |> Seq.skip indexOfLastBlock
let blockHeader = lastBlock |> Seq.head
let notes =
lastBlock
|> Seq.skip 1
|> Seq.map (fun str -> str.Trim([|' '; '*'|]))
|> Seq.toList
let assemblyVersion, nugetVersion = assemblyRegex.Match(blockHeader), nugetRegex.Match(blockHeader)
if not assemblyVersion.Success then
failwith "Unable to parse valid Assembly version from release notes."
assemblyVersion.Value, nugetVersion.Value, notes
/// Parse a Release Notes File - Either simple or "complex" format
/// See: https://github.com/fsharp/FAKE/issues/171
/// <param name="filePath">The path to the release notes file</param>
/// <returns> (assembly_version, nuget_version, [release_notes]) </returns>
let parseReleaseNotes filePath =
let text = // read file and trim leading & trailing blank lines
let data = File.ReadLines(filePath)
let num_real_lines =
data
|> Seq.fold (fun (line_count, blank_count) str ->
if String.IsNullOrEmpty(str.Trim()) then
line_count, blank_count + 1
else line_count + 1 + blank_count, 0) (0, 0)
|> fst
data
|> Seq.take num_real_lines // drop trailing empty lines
|> Seq.skipWhile (fun str -> String.IsNullOrWhiteSpace(str.Trim())) // drop leading empty lines
if text |> Seq.isEmpty then failwith "Empty Realease file."
let (|Simple|Complex|Invalid|) c =
match c with
|'*' -> Simple
|'#' -> Complex
|_ -> Invalid
let firstNonEmptyChar = (text |> Seq.head).Trim([|'-'; ' '|]).[0]
match firstNonEmptyChar with
|Simple -> parseSimpleReleaseNotes text // parse simple release notes type
|Complex -> parseComplexReleaseNotes text // parse complex release notes type
|Invalid -> failwith "Invalid Release Notes format."
|
namespace System
namespace System.IO
namespace System.Text
namespace System.Text.RegularExpressions
val dir : string
Full name: Script.dir
val simple_notes : string
Full name: Script.simple_notes
val complex_notes : string
Full name: Script.complex_notes
val nugetRegex : Regex
Full name: Script.nugetRegex
Multiple items
type Regex =
new : pattern:string -> Regex + 1 overload
member GetGroupNames : unit -> string[]
member GetGroupNumbers : unit -> int[]
member GroupNameFromNumber : i:int -> string
member GroupNumberFromName : name:string -> int
member IsMatch : input:string -> bool + 1 overload
member Match : input:string -> Match + 2 overloads
member Matches : input:string -> MatchCollection + 1 overload
member Options : RegexOptions
member Replace : input:string * replacement:string -> string + 5 overloads
...
Full name: System.Text.RegularExpressions.Regex
--------------------
Regex(pattern: string) : unit
Regex(pattern: string, options: RegexOptions) : unit
val assemblyRegex : Regex
Full name: Script.assemblyRegex
val parseSimpleReleaseNotes : text:seq<string> -> string * string * string list
Full name: Script.parseSimpleReleaseNotes
Parse simple release notes sequence
val text : seq<string>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
val lastLine : string
module Seq
from Microsoft.FSharp.Collections
val last : source:seq<'T> -> 'T
Full name: Microsoft.FSharp.Collections.Seq.last
val assemblyVersion : Match
val nugetVersion : Match
Regex.Match(input: string) : Match
Regex.Match(input: string, startat: int) : Match
Regex.Match(input: string, beginning: int, length: int) : Match
val not : value:bool -> bool
Full name: Microsoft.FSharp.Core.Operators.not
property Group.Success: bool
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val notes : string
String.Substring(startIndex: int) : string
String.Substring(startIndex: int, length: int) : string
property Capture.Index: int
property Capture.Length: int
property Capture.Value: string
val parseComplexReleaseNotes : text:seq<string> -> string * string * string list
Full name: Script.parseComplexReleaseNotes
Parse "complex" release notes text sequence
val indexOfLastBlock : int
val fold : folder:('State -> 'T -> 'State) -> state:'State -> source:seq<'T> -> 'State
Full name: Microsoft.FSharp.Collections.Seq.fold
val index : int
val ctr : int
val str : string
Multiple items
type String =
new : value:char -> string + 7 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 2 overloads
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
member GetHashCode : unit -> int
...
Full name: System.String
--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
String.IsNullOrEmpty(value: string) : bool
String.Trim() : string
String.Trim([<ParamArray>] trimChars: char []) : string
val fst : tuple:('T1 * 'T2) -> 'T1
Full name: Microsoft.FSharp.Core.Operators.fst
val lastBlock : seq<string>
val skip : count:int -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.skip
val blockHeader : string
val head : source:seq<'T> -> 'T
Full name: Microsoft.FSharp.Collections.Seq.head
val notes : string list
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
Full name: Microsoft.FSharp.Collections.Seq.map
val toList : source:seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.Seq.toList
val parseReleaseNotes : filePath:string -> string * string * string list
Full name: Script.parseReleaseNotes
Parse a Release Notes File - Either simple or "complex" format
See: https://github.com/fsharp/FAKE/issues/171
<param name="filePath">The path to the release notes file</param>
<returns> (assembly_version, nuget_version, [release_notes]) </returns>
val filePath : string
val data : Collections.Generic.IEnumerable<string>
type File =
static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
static member AppendAllText : path:string * contents:string -> unit + 1 overload
static member AppendText : path:string -> StreamWriter
static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
static member Create : path:string -> FileStream + 3 overloads
static member CreateText : path:string -> StreamWriter
static member Decrypt : path:string -> unit
static member Delete : path:string -> unit
static member Encrypt : path:string -> unit
static member Exists : path:string -> bool
...
Full name: System.IO.File
File.ReadLines(path: string) : Collections.Generic.IEnumerable<string>
File.ReadLines(path: string, encoding: Text.Encoding) : Collections.Generic.IEnumerable<string>
val num_real_lines : int
val line_count : int
val blank_count : int
val take : count:int -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.take
val skipWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.skipWhile
String.IsNullOrWhiteSpace(value: string) : bool
val isEmpty : source:seq<'T> -> bool
Full name: Microsoft.FSharp.Collections.Seq.isEmpty
val c : char
val firstNonEmptyChar : char
active recognizer Simple: char -> Choice<unit,unit,unit>
active recognizer Complex: char -> Choice<unit,unit,unit>
active recognizer Invalid: char -> Choice<unit,unit,unit>
More information