mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
tools: instantly generate the entire changelog in changelog_helper.v
This commit is contained in:
parent
44c78ed761
commit
cf7d6cd648
2 changed files with 185 additions and 61 deletions
|
@ -1,3 +1,5 @@
|
|||
## V 0.4.5 TODO
|
||||
|
||||
## V 0.4.4
|
||||
*9 January 2024*
|
||||
|
||||
|
|
|
@ -15,30 +15,47 @@ enum Category {
|
|||
db
|
||||
native
|
||||
cgen
|
||||
js_backend
|
||||
comptime
|
||||
tools
|
||||
compiler_internals
|
||||
examples
|
||||
vfmt
|
||||
os_support
|
||||
}
|
||||
|
||||
/*
|
||||
#### Improvements in the language
|
||||
const category_titles = '#### Improvements in the language
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
#### Checker improvements/fixes
|
||||
|
||||
#### Parser improvements
|
||||
|
||||
#### Compiler internals
|
||||
|
||||
#### Standard library
|
||||
|
||||
#### Web
|
||||
|
||||
#### ORM
|
||||
|
||||
#### Database drivers
|
||||
|
||||
#### Native backend
|
||||
|
||||
#### C backend
|
||||
|
||||
#### JavaScript backend
|
||||
|
||||
#### vfmt
|
||||
|
||||
#### Tools
|
||||
|
||||
#### Operating System support
|
||||
|
||||
#### Examples
|
||||
*/
|
||||
'
|
||||
|
||||
struct Line {
|
||||
category Category
|
||||
|
@ -48,22 +65,63 @@ struct Line {
|
|||
const log_txt = 'log.txt'
|
||||
|
||||
struct App {
|
||||
version string // e.g. "0.4.5"
|
||||
total_lines int
|
||||
mut:
|
||||
result string // resulting CHANGELOG.md
|
||||
counter int
|
||||
}
|
||||
|
||||
const is_interactive = false
|
||||
|
||||
// Instantly updates CHANGELOG.md without confirming each line
|
||||
fn no_interactive(version string) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if !os.exists(log_txt) {
|
||||
os.execute(git_log_cmd + ' > ' + log_txt)
|
||||
println('log.txt generated, remove unnecessary commits from it and run the tool again')
|
||||
mut version := ''
|
||||
|
||||
if os.args.len == 2 && os.args[1].starts_with('0.') {
|
||||
version = os.args[1]
|
||||
// no_interactive(version)
|
||||
// return
|
||||
} else {
|
||||
println('Usage: v run tools/changelog_helper.v 0.4.5')
|
||||
return
|
||||
}
|
||||
lines := os.read_lines(log_txt)!
|
||||
changelog_txt := os.read_file('CHANGELOG.md')!.to_lower()
|
||||
if !os.exists(log_txt) {
|
||||
os.execute(git_log_cmd + ' > ' + log_txt)
|
||||
println('log.txt generated')
|
||||
// println('log.txt generated, remove unnecessary commits from it and run the tool again')
|
||||
// return
|
||||
}
|
||||
mut lines := os.read_lines(log_txt)!
|
||||
// Trim everything before current version, commit "(tag: 0.4.4) V 0.4.4"
|
||||
mut prev_version := (version.replace('.', '').int() - 1).str()
|
||||
prev_version = '0.${prev_version[0].ascii_str()}.${prev_version[1].ascii_str()}'
|
||||
println('prev version=${prev_version}')
|
||||
for i, line in lines {
|
||||
if line == ('V ${prev_version}') {
|
||||
lines = lines[..i].clone()
|
||||
break
|
||||
}
|
||||
}
|
||||
os.write_file(log_txt, lines.join('\n'))!
|
||||
if true {
|
||||
// return
|
||||
}
|
||||
mut app := &App{
|
||||
total_lines: lines.len
|
||||
}
|
||||
// Write categories at the top first
|
||||
app.result = os.read_file('CHANGELOG.md')!.replace_once('V ${version} TODO', 'V ${version}\n' +
|
||||
category_titles)
|
||||
os.write_file('CHANGELOG.md', app.result)!
|
||||
changelog_txt := os.read_file('CHANGELOG.md')!.to_lower()
|
||||
if true {
|
||||
// println(changelog_txt)
|
||||
// return
|
||||
}
|
||||
// mut counter := 0 // to display how many commits are left
|
||||
for line in lines {
|
||||
s := line.trim_space()
|
||||
|
@ -81,7 +139,11 @@ fn main() {
|
|||
continue
|
||||
}
|
||||
|
||||
app.process_line(line)!
|
||||
app.process_line(line.trim_space())!
|
||||
}
|
||||
println('writing changelog.md')
|
||||
if !is_interactive {
|
||||
os.write_file('CHANGELOG.md', app.result)!
|
||||
}
|
||||
println('done.')
|
||||
}
|
||||
|
@ -96,11 +158,19 @@ fn (mut app App) process_line(text string) ! {
|
|||
}
|
||||
prefix := text[..semicolon_pos]
|
||||
// Get category based on keywords in the commit message/prefix
|
||||
mut category := Category.improvements
|
||||
mut category := Category.examples
|
||||
if text.contains('checker:') {
|
||||
category = .checker
|
||||
} else if text.contains('cgen:') {
|
||||
} else if is_examples(text) {
|
||||
// Always skip examples and typos fixes
|
||||
category = .examples
|
||||
return
|
||||
} else if is_os_support(text) {
|
||||
category = .os_support
|
||||
} else if is_cgen(text) {
|
||||
category = .cgen
|
||||
} else if is_js_backend(text) {
|
||||
category = .js_backend
|
||||
} else if is_db(text) {
|
||||
category = .db
|
||||
} else if is_stdlib(text) {
|
||||
|
@ -121,9 +191,6 @@ fn (mut app App) process_line(text string) ! {
|
|||
category = .native
|
||||
} else if is_vfmt(text) {
|
||||
category = .vfmt
|
||||
} else if is_examples(text) {
|
||||
// TODO maybe always skip these as well?
|
||||
category = .examples
|
||||
} else if text.contains('docs:') || text.contains('doc:') {
|
||||
// Always skip docs
|
||||
delete_processed_line_from_log(text)!
|
||||
|
@ -133,6 +200,7 @@ fn (mut app App) process_line(text string) ! {
|
|||
else {
|
||||
return
|
||||
}
|
||||
println('process_line: cat=${category} "${text}"')
|
||||
|
||||
// Trim everything to the left of `:` for some commits (e.g. `checker: `)
|
||||
mut s := text
|
||||
|
@ -140,66 +208,71 @@ fn (mut app App) process_line(text string) ! {
|
|||
// if true {
|
||||
// exit(0)
|
||||
//}
|
||||
if semicolon_pos < 15 && prefix in ['checker', 'cgen'] {
|
||||
if (semicolon_pos < 15
|
||||
&& prefix in ['checker', 'cgen', 'parser', 'v.parser', 'ast', 'jsgen', 'v.gen.js', 'fmt', 'vfmt'])
|
||||
|| (semicolon_pos < 30 && prefix.contains(', ')) {
|
||||
s = '- ' + text[semicolon_pos + 2..].capitalize()
|
||||
}
|
||||
|
||||
// Get input from the user
|
||||
print('\033[H\033[J')
|
||||
println('${app.counter} / ${app.total_lines}')
|
||||
// println('\n')
|
||||
println(text)
|
||||
input := os.input('${category}? ')
|
||||
println("INPUT='${input}'")
|
||||
match input {
|
||||
'' {
|
||||
println('GOT ENTER')
|
||||
line := Line{category, s}
|
||||
save_line(line)!
|
||||
}
|
||||
'n', '0', 'no' {
|
||||
// Ignore commit
|
||||
println('ignored.')
|
||||
}
|
||||
's', 'skip' {
|
||||
// Skip
|
||||
println('skipped.')
|
||||
return
|
||||
}
|
||||
'c', 'change' {
|
||||
// Change category
|
||||
for {
|
||||
print_category_hint()
|
||||
custom_category := os.input('${category} ?').int()
|
||||
if custom_category == 0 {
|
||||
println('wrong category')
|
||||
} else {
|
||||
unsafe {
|
||||
line := Line{Category(custom_category - 1), s}
|
||||
save_line(line)!
|
||||
if is_interactive {
|
||||
// Get input from the user
|
||||
print('\033[H\033[J')
|
||||
println('${app.counter} / ${app.total_lines}')
|
||||
// println('\n')
|
||||
println(text)
|
||||
input := os.input('${category}? ')
|
||||
println("INPUT='${input}'")
|
||||
match input {
|
||||
'' {
|
||||
println('GOT ENTER')
|
||||
line := Line{category, s}
|
||||
save_line_interactive(line)!
|
||||
}
|
||||
'n', '0', 'no' {
|
||||
// Ignore commit
|
||||
println('ignored.')
|
||||
}
|
||||
's', 'skip' {
|
||||
// Skip
|
||||
println('skipped.')
|
||||
return
|
||||
}
|
||||
'c', 'change' {
|
||||
// Change category
|
||||
for {
|
||||
print_category_hint()
|
||||
custom_category := os.input('${category} ?').int()
|
||||
if custom_category == 0 {
|
||||
println('wrong category')
|
||||
} else {
|
||||
unsafe {
|
||||
line := Line{Category(custom_category - 1), s}
|
||||
save_line_interactive(line)!
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
else {}
|
||||
app.counter++
|
||||
} else {
|
||||
line := Line{category, s}
|
||||
app.save_line(line)!
|
||||
}
|
||||
app.counter++
|
||||
// Don't forget to remove the line we just processed from log.txt
|
||||
delete_processed_line_from_log(text)!
|
||||
}
|
||||
|
||||
fn save_line(line Line) ! {
|
||||
println('save line ${line}')
|
||||
mut txt := os.read_file('CHANGELOG.md')!
|
||||
fn (mut app App) save_line(line Line) ! {
|
||||
// println('save line ${line}')
|
||||
app.result = line.write_at_category(app.result) or { return error('') }
|
||||
}
|
||||
|
||||
// match line.category {
|
||||
//.checker {
|
||||
fn save_line_interactive(line Line) ! {
|
||||
println('save line interactive ${line}')
|
||||
mut txt := os.read_file('CHANGELOG.md')!
|
||||
txt = line.write_at_category(txt) or { return error('') }
|
||||
// println(txt.limit(1000))
|
||||
//}
|
||||
// else {}
|
||||
//}
|
||||
os.write_file('CHANGELOG.md', txt)!
|
||||
}
|
||||
|
||||
|
@ -214,11 +287,13 @@ const category_map = {
|
|||
.db: '#### Database drivers'
|
||||
.native: '#### Native backend'
|
||||
.cgen: '#### C backend'
|
||||
.js_backend: '#### JavaScript backend'
|
||||
.comptime: '#### Comptime'
|
||||
.tools: '#### Tools'
|
||||
.compiler_internals: '#### Compiler internals'
|
||||
.examples: '#### Examples'
|
||||
.vfmt: '#### vfmt'
|
||||
.os_support: '#### Operating System'
|
||||
}
|
||||
|
||||
fn (l Line) write_at_category(txt string) ?string {
|
||||
|
@ -276,6 +351,7 @@ const db_strings = [
|
|||
const improvements_strings = [
|
||||
'all:',
|
||||
'v:',
|
||||
'coroutines:',
|
||||
]
|
||||
|
||||
const parser_strings = [
|
||||
|
@ -293,7 +369,7 @@ const stdlib_strings = [
|
|||
'math:',
|
||||
'math.big',
|
||||
'crypto',
|
||||
'sokol:',
|
||||
'sokol',
|
||||
'os:',
|
||||
'rand:',
|
||||
'math:',
|
||||
|
@ -309,6 +385,10 @@ const stdlib_strings = [
|
|||
'readline',
|
||||
'cli:',
|
||||
'eventbus:',
|
||||
'encoding.',
|
||||
'bitfield:',
|
||||
'io:',
|
||||
'log:',
|
||||
]
|
||||
|
||||
fn is_stdlib(text string) bool {
|
||||
|
@ -327,6 +407,25 @@ fn is_orm(text string) bool {
|
|||
return is_xxx(text, orm_strings)
|
||||
}
|
||||
|
||||
const cgen_strings = [
|
||||
'cgen:',
|
||||
'v.gen.c:',
|
||||
]
|
||||
|
||||
fn is_cgen(text string) bool {
|
||||
return is_xxx(text, cgen_strings)
|
||||
}
|
||||
|
||||
const js_backend_strings = [
|
||||
'js:',
|
||||
'v.gen.js:',
|
||||
'jsgen:',
|
||||
]
|
||||
|
||||
fn is_js_backend(text string) bool {
|
||||
return is_xxx(text, js_backend_strings)
|
||||
}
|
||||
|
||||
const internal_strings = [
|
||||
'scanner:',
|
||||
'transformer:',
|
||||
|
@ -348,6 +447,10 @@ const examples_strings = [
|
|||
'tests',
|
||||
'readme:',
|
||||
'.md:',
|
||||
'typos',
|
||||
' typo',
|
||||
'cleanup',
|
||||
'clean up',
|
||||
]
|
||||
|
||||
fn is_examples(text string) bool {
|
||||
|
@ -362,6 +465,7 @@ const tools_strings = [
|
|||
'gitignore',
|
||||
'benchmark',
|
||||
'v.help:',
|
||||
'vtest',
|
||||
]
|
||||
|
||||
fn is_tools(text string) bool {
|
||||
|
@ -374,6 +478,7 @@ fn is_parser(text string) bool {
|
|||
|
||||
const web_strings = [
|
||||
'vweb:',
|
||||
'x.vweb:',
|
||||
'websocket:',
|
||||
'picoev:',
|
||||
'mbedtls',
|
||||
|
@ -404,6 +509,23 @@ fn is_vfmt(text string) bool {
|
|||
return is_xxx(text, vfmt_strings)
|
||||
}
|
||||
|
||||
const os_support_strings = [
|
||||
'FreeBSD',
|
||||
'freebsd',
|
||||
'OpenBSD',
|
||||
'openbsd',
|
||||
'macOS',
|
||||
'macos',
|
||||
'Windows',
|
||||
'windows',
|
||||
'Linux',
|
||||
'linux',
|
||||
]
|
||||
|
||||
fn is_os_support(text string) bool {
|
||||
return is_xxx(text, os_support_strings)
|
||||
}
|
||||
|
||||
fn is_xxx(text string, words []string) bool {
|
||||
for s in words {
|
||||
if text.contains(s) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue