Skip to content

Instantly share code, notes, and snippets.

@level120
Last active February 8, 2023 08:42
Show Gist options
  • Select an option

  • Save level120/e0401bea4005d3a748d4dc9fd2bdf694 to your computer and use it in GitHub Desktop.

Select an option

Save level120/e0401bea4005d3a748d4dc9fd2bdf694 to your computer and use it in GitHub Desktop.
Change log generator - powershell version
# Based on https://medium.com/@Jeef/creating-a-git-submodule-change-log-for-ci-db60c90f821c
# Input Parameter
param([String] $script:BeginCommitOrTag, [String] $script:EndCommitOrTag, [String] $script:Branch)
function Get-RootPath {
<#
.SYNOPSIS
입력 파라미터의 Path 기준으로 *.sln 파일이 있는 위치까지 상향 탐색합니다.
.OUTPUTS
[String] *.sln 파일이 있는 Path(없으면 빈 문자열) 반환
#>
param (
[String] $BasePath
)
if ((Get-ChildItem -Path $BasePath -Filter *.sln).count -gt 0) {
return $BasePath
}
$ParentPath = (Get-Item $BasePath).Parent.FullName
if ([string]::IsNullOrWhiteSpace($ParentPath)) {
return ''
}
return Get-RootPath -BasePath $ParentPath
}
function Get-TimestampBy {
<#
.SYNOPSIS
현재 작업 디렉토리를 기준으로 입력 파라미터의 결과에서 시간 값만 반환합니다(git show).
.OUTPUTS
[String] "yyyy-MM-dd HH:mm:ss" 형태의 시간 문자열
#>
param (
[String] $CommitOrTag
)
if ([string]::IsNullOrWhiteSpace($CommitOrTag)) {
return ''
}
return (git show -s --format=%ci $CommitOrTag) | ForEach-Object {
if ($_ -match "\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} *") {
$_.split('+')[0].Trim()
}
}
}
function Get-SubModules {
<#
.SYNOPSIS
현재 작업 디렉토리를 기준으로 .gitmodules에 등록된 SubModule을 반환합니다.
.OUTPUTS
SubModule Name
#>
return (git config --file=.gitmodules -l) | ForEach-Object {
$local:submodule_infos = $_.split('=')[0].split('.')
if ($submodule_infos.length -gt 3) {
$submodule_infos[1..($submodule_infos.length - 2)] -join '.'
}
else {
$submodule_infos[1]
}
} | Sort-Object -Unique
}
function Get-Printable {
<#
.SYNOPSIS
현재 작업 디렉토리를 기준으로 변경점이 있는지 확인하여 그 결과를 반환합니다.
.OUTPUTS
[Bool] 타입의 결과
#>
git fetch -q -p --all | Out-Null
if ([string]::IsNullOrWhiteSpace($End)) {
return (git log --pretty=`"%s`" --after `"$Begin`").Count -gt 0
}
else {
return (git log --pretty=`"%s`" --after `"$Begin`" --before=`"$End`").Count -gt 0
}
}
function Write-LogRecursively {
<#
.SYNOPSIS
SubModule의 Log를 출력합니다.
#>
param (
[String] $SubmoduleName
)
$local:SubmodulePath = (git config --file=.gitmodules --get submodule.$SubmoduleName.path)
$local:SubmoduleBranch = (git config --file=.gitmodules --get submodule.$SubmoduleName.branch)
# When branch not found
if ([string]::IsNullOrWhiteSpace($SubmoduleBranch)) {
$SubmoduleBranch = "HEAD"
}
$local:Location = $pwd.Path
Set-Location $SubmodulePath
if (Get-Printable) {
Write-BranchInfo -RepoName $SubmoduleName -BranchName $SubmoduleBranch
Write-Log
}
Set-Location $Location
}
function Write-LogCurrently {
<#
.SYNOPSIS
현 위치(솔루션 프로젝트)의 Log를 출력합니다.
#>
param (
[String] $BranchName
)
# When branch not found
if ([string]::IsNullOrWhiteSpace($BranchName)) {
$BranchName = "HEAD"
}
$local:ProjectName = (git config --get remote.origin.url).split('/')[-1]
Write-BranchInfo -RepoName $ProjectName -BranchName $BranchName
Write-Log
}
function Write-Log {
<#
.SYNOPSIS
git log를 이용해 해당 Repo의 Log 출력합니다.
#>
# When use "Write-Host", newline character ignore
if ([string]::IsNullOrWhiteSpace($End)) {
Write-Output (git log --pretty=`"tformat:* `(%h`) %s `(%ae`)`" --after=`"$Begin`")
}
else {
Write-Output (git log --pretty=`"tformat:* `(%h`) %s `(%ae`)`" --after=`"$Begin`" --before=`"$End`")
}
}
function Write-BranchInfo {
<#
.SYNOPSIS
해당 위치의 Title 출력 부분, [ RepoName : Branch ] 형태로 출력합니다.
#>
param (
[String] $RepoName,
[String] $BranchName
)
Write-Host ""
Write-Host "[ " -NoNewline
Write-Host $RepoName -NoNewline -ForegroundColor Green
Write-Host " : " -NoNewline
Write-Host $BranchName -NoNewline -ForegroundColor Blue
Write-Host " ]"
}
function Update-Initialize {
<#
.SYNOPSIS
*.sln 파일이 있는 솔루션 폴더 기준 Initialize
#>
# Update recently
if ([string]::IsNullOrWhiteSpace($Branch)) {
git pull | out-null
}
else {
git switch $Branch | out-null
git pull | out-null
}
}
# Set locale
$env:LC_ALL='C.UTF-8'
[System.Console]::InputEncoding = [System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8
## Main
# 시작 tag(또는 commit) 없으면 종료
if ([string]::IsNullOrWhiteSpace($BeginCommitOrTag)) {
Write-Error -Message "Please set begin commit or tag" -Category InvalidArgument
Write-Error -Message "$ $($MyInvocation.MyCommand.Name) BEGIN_COMMIT_OR_TAG [END_COMMIT_OR_TAG] [BRANCH_NAME]" -Category InvalidArgument
exit
}
# Script Path로부터 Script의 Directory로 분리한 뒤 RootPath 탐색
[String] $local:BasePath = Get-RootPath -BasePath (Split-Path $MyInvocation.MyCommand.Path)
# *.sln 파일이 있는 BasePath를 찾지 못한 경우 종료
if ([string]::IsNullOrWhiteSpace($BasePath)) {
Write-Error -Message "Solution file not found." -Category InvalidData
exit
}
# Solution 폴더로 이동
Set-Location $BasePath
Write-Host "# Build Version: $(git describe)" -ForegroundColor DarkYellow
[String] $script:Begin = Get-TimestampBy -CommitOrTag $BeginCommitOrTag
[String] $script:End = Get-TimestampBy -CommitOrTag $EndCommitOrTag
# 시작 tag(또는 commit)의 Timestamp를 찾을 수 없는 경우 종료
if ([string]::IsNullOrWhiteSpace($Begin)) {
Write-Error -Message "Invalid begin tag or commit hash." -Category InvalidData
exit
}
# Solution 폴더 기준 최신화(git pull)
Update-Initialize
# Log 탐색해서 출력 부
Write-LogCurrently -BranchName $Branch
Get-SubModules | ForEach-Object { Write-LogRecursively -SubmoduleName $_ }
@level120
Copy link
Author

powershell .\changelog_generator.ps1 FROM_TAG TO_TAG BRANCH

example1: powershell .\changelog_generator.ps1 1.0
example2: powershell .\changelog_generator.ps1 1.0 1.1
example3: powershell .\changelog_generator.ps1 1.0 1.1 develop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment