From c2b9ae29371f142fe7f2da694f893f1365170bc2 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Tue, 26 Oct 2021 13:23:07 +0200 Subject: fix(changelog): don't show more than 40 commits (#10345) Fixes #10345 --- tools/changelog.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/changelog.sh b/tools/changelog.sh index 7329a9526..ebdffba0a 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -400,7 +400,7 @@ function main { # commit if $since is unset, in short hash form. command git rev-list --abbrev-commit --abbrev=7 ${since:+$since..}$until | while read hash; do # Truncate list on versions with a lot of commits - if [[ -z "$since" ]] && (( ++read_commits > 35 )); then + if (( ++read_commits > 40 )); then truncate=1 break fi -- cgit v1.2.3-70-g09d2 From 9c8131e417a15fccb15615e3b03ce44a53678fe0 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Tue, 26 Oct 2021 18:24:29 +0200 Subject: perf(changelog): use a single `git log` command to get all commit messages --- tools/changelog.sh | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'tools') diff --git a/tools/changelog.sh b/tools/changelog.sh index ebdffba0a..13cfb9530 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -1,5 +1,8 @@ #!/usr/bin/env zsh +cd "$ZSH" +setopt extendedglob + ############################## # CHANGELOG SCRIPT CONSTANTS # ############################## @@ -114,15 +117,8 @@ function parse-commit { fi } - # Ignore commit if it is a merge commit - if [[ $(command git show -s --format=%p $1 | wc -w) -gt 1 ]]; then - return - fi - # Parse commit with hash $1 - local hash="$1" subject body warning rhash - subject="$(command git show -s --format=%s $hash)" - body="$(command git show -s --format=%b $hash)" + local hash="$1" subject="$2" body="$3" warning rhash # Commits following Conventional Commits (https://www.conventionalcommits.org/) # have the following format, where parts between [] are optional: @@ -384,7 +380,8 @@ function main { # Commit classification arrays local -A commits subjects scopes breaking reverts local truncate=0 read_commits=0 - local hash version tag + local version tag + local hash refs subject body # Get the first version name: # 1) try tag-like version, or @@ -396,17 +393,40 @@ function main { || version=$(command git symbolic-ref --quiet --short $until 2>/dev/null) \ || version=$(command git rev-parse --short $until 2>/dev/null) - # Get commit list from $until commit until $since commit, or until root - # commit if $since is unset, in short hash form. - command git rev-list --abbrev-commit --abbrev=7 ${since:+$since..}$until | while read hash; do + # Get commit list from $until commit until $since commit, or until root commit if $since is unset + local range=${since:+$since..}$until + + # Git log options + # -z: commits are delimited by null bytes + # --format: [7-char hash][ref names][subject][body] + # --abbrev=7: force commit hashes to be 7 characters long + # --no-merges: merge commits are omitted + local SEP="0mZmAgIcSeP" + local -a raw_commits + raw_commits=(${(0)"$(command git log -z \ + --format="%h${SEP}%D${SEP}%s${SEP}%b" --abbrev=7 \ + --no-merges $range)"}) + + local raw_commit + local -a raw_fields + for raw_commit in $raw_commits; do # Truncate list on versions with a lot of commits if (( ++read_commits > 40 )); then truncate=1 break fi + # Read the commit fields (@ is needed to keep empty values) + raw_fields=("${(@ps:$SEP:)raw_commit}") + hash="${raw_fields[1]}" + refs="${raw_fields[2]}" + subject="${raw_fields[3]}" + body="${raw_fields[4]}" + # If we find a new release (exact tag) - if tag=$(command git describe --exact-match --tags $hash 2>/dev/null); then + if [[ "$refs" = *tag:\ * ]]; then + # Parse tag name (needs: setopt extendedglob) + tag="${${refs##*tag: }%%,# *}" # Output previous release display-release # Reinitialize commit storage @@ -420,7 +440,7 @@ function main { read_commits=1 fi - parse-commit "$hash" + parse-commit "$hash" "$subject" "$body" done display-release @@ -431,8 +451,6 @@ function main { fi } -cd "$ZSH" - # Use raw output if stdout is not a tty if [[ ! -t 1 && -z "$3" ]]; then main "$1" "$2" --raw -- cgit v1.2.3-70-g09d2 From 140bfa84320d6f0a9c3b429c1c6be41878e60352 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Tue, 26 Oct 2021 18:26:02 +0200 Subject: fix(changelog): go back to ignoring commits from merged branches --- tools/changelog.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/changelog.sh b/tools/changelog.sh index 13cfb9530..5c3159732 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -401,17 +401,18 @@ function main { # --format: [7-char hash][ref names][subject][body] # --abbrev=7: force commit hashes to be 7 characters long # --no-merges: merge commits are omitted + # --first-parent: commits from merged branches are omitted local SEP="0mZmAgIcSeP" local -a raw_commits raw_commits=(${(0)"$(command git log -z \ --format="%h${SEP}%D${SEP}%s${SEP}%b" --abbrev=7 \ - --no-merges $range)"}) + --no-merges --first-parent $range)"}) local raw_commit local -a raw_fields for raw_commit in $raw_commits; do # Truncate list on versions with a lot of commits - if (( ++read_commits > 40 )); then + if [[ -z "$since" ]] && (( ++read_commits > 35 )); then truncate=1 break fi -- cgit v1.2.3-70-g09d2 From 0267cb89eba6dc9f2744bfba73ada391a6582249 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Tue, 26 Oct 2021 18:59:39 +0200 Subject: perf(changelog): use regex-match instead of `sed` to parse commit subjects --- tools/changelog.sh | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/changelog.sh b/tools/changelog.sh index 5c3159732..3641179e2 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -52,10 +52,15 @@ function parse-commit { # make a breaking change function commit:type { - local type="$(sed -E 's/^([a-zA-Z_\-]+)(\(.+\))?!?: .+$/\1/' <<< "$1")" + local type + + # Parse commit type from the subject + if [[ "$1" =~ '^([a-zA-Z_\-]+)(\(.+\))?!?: .+$' ]]; then + type="${match[1]}" + fi # If $type doesn't appear in $TYPES array mark it as 'other' - if [[ -n "${(k)TYPES[(i)$type]}" ]]; then + if [[ -n "$type" && -n "${(k)TYPES[(i)$type]}" ]]; then echo $type else echo other @@ -66,17 +71,18 @@ function parse-commit { local scope # Try to find scope in "type():" format - scope=$(sed -nE 's/^[a-zA-Z_\-]+\((.+)\)!?: .+$/\1/p' <<< "$1") - if [[ -n "$scope" ]]; then - echo "$scope" + if [[ "$1" =~ '^[a-zA-Z_\-]+\((.+)\)!?: .+$' ]]; then + echo "${match[1]}" return fi # If no scope found, try to find it in ":" format - # Make sure it's not a type before printing it - scope=$(sed -nE 's/^([a-zA-Z_\-]+): .+$/\1/p' <<< "$1") - if [[ -z "${(k)TYPES[(i)$scope]}" ]]; then - echo "$scope" + if [[ "$1" =~ '^([a-zA-Z_\-]+): .+$' ]]; then + scope="${match[1]}" + # Make sure it's not a type before printing it + if [[ -z "${(k)TYPES[(i)$scope]}" ]]; then + echo "$scope" + fi fi } @@ -84,7 +90,11 @@ function parse-commit { # Only display the relevant part of the commit, i.e. if it has the format # type[(scope)!]: subject, where the part between [] is optional, only # displays subject. If it doesn't match the format, returns the whole string. - sed -E 's/^[a-zA-Z_\-]+(\(.+\))?!?: (.+)$/\2/' <<< "$1" + if [[ "$1" =~ '^[a-zA-Z_\-]+(\(.+\))?!?: (.+)$' ]]; then + echo "${match[2]}" + else + echo "$1" + fi } # Return subject if the body or subject match the breaking change format -- cgit v1.2.3-70-g09d2 From 4b3a5c54117fa8af12878d1b659c14214cb4bbec Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Tue, 26 Oct 2021 20:54:39 +0200 Subject: fix(changelog): fix percent escapes in `printf` calls --- tools/changelog.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'tools') diff --git a/tools/changelog.sh b/tools/changelog.sh index 3641179e2..e32d503b1 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -201,9 +201,9 @@ function display-release { #* Uses $hash from outer scope local hash="${1:-$hash}" case "$output" in - raw) printf "$hash" ;; - text) printf "\e[33m$hash\e[0m" ;; # red - md) printf "[\`$hash\`](https://github.com/ohmyzsh/ohmyzsh/commit/$hash)" ;; + raw) printf '%s' "$hash" ;; + text) printf '\e[33m%s\e[0m' "$hash" ;; # red + md) printf '[`%s`](https://github.com/ohmyzsh/ohmyzsh/commit/%s)' "$hash" ;; esac } @@ -215,16 +215,16 @@ function display-release { case "$output" in raw) case "$level" in - 1) printf "$header\n$(printf '%.0s=' {1..${#header}})\n\n" ;; - 2) printf "$header\n$(printf '%.0s-' {1..${#header}})\n\n" ;; - *) printf "$header:\n\n" ;; + 1) printf '%s\n%s\n\n' "$header" "$(printf '%.0s=' {1..${#header}})" ;; + 2) printf '%s\n%s\n\n' "$header" "$(printf '%.0s-' {1..${#header}})" ;; + *) printf '%s:\n\n' "$header" ;; esac ;; text) case "$level" in - 1|2) printf "\e[1;4m$header\e[0m\n\n" ;; # bold, underlined - *) printf "\e[1m$header:\e[0m\n\n" ;; # bold + 1|2) printf '\e[1;4m%s\e[0m\n\n' "$header" ;; # bold, underlined + *) printf '\e[1m%s:\e[0m\n\n' "$header" ;; # bold esac ;; - md) printf "$(printf '%.0s#' {1..${level}}) $header\n\n" ;; + md) printf '%s %s\n\n' "$(printf '%.0s#' {1..${level}})" "$header" ;; esac } @@ -250,8 +250,8 @@ function display-release { # Print [scope] case "$output" in - raw|md) printf "[$scope]${padding} " ;; - text) printf "[\e[38;5;9m$scope\e[0m]${padding} " ;; # red 9 + raw|md) printf '[%s]%s ' "$scope" "$padding";; + text) printf '[\e[38;5;9m%s\e[0m]%s ' "$scope" "$padding";; # red 9 esac } @@ -264,7 +264,7 @@ function display-release { subject="${(U)subject:0:1}${subject:1}" case "$output" in - raw) printf "$subject" ;; + raw) printf '%s' "$subject" ;; # In text mode, highlight (#) and dim text between `backticks` text) sed -E $'s|#([0-9]+)|\e[32m#\\1\e[0m|g;s|`([^`]+)`|`\e[2m\\1\e[0m`|g' <<< "$subject" ;; # In markdown mode, link to (#) issues @@ -277,8 +277,8 @@ function display-release { local type="${1:-${TYPES[$type]:-${(C)type}}}" [[ -z "$type" ]] && return 0 case "$output" in - raw|md) printf "$type: " ;; - text) printf "\e[4m$type\e[24m: " ;; # underlined + raw|md) printf '%s: ' "$type" ;; + text) printf '\e[4m%s\e[24m: ' "$type" ;; # underlined esac } @@ -292,7 +292,7 @@ function display-release { (( $#breaking != 0 )) || return 0 case "$output" in - text) fmt:header "\e[31mBREAKING CHANGES" 3 ;; + text) printf '\e[31m'; fmt:header "BREAKING CHANGES" 3 ;; raw) fmt:header "BREAKING CHANGES" 3 ;; md) fmt:header "BREAKING CHANGES ⚠" 3 ;; esac -- cgit v1.2.3-70-g09d2 From 1dba1120410280699c6a97a5252bab24681b46b8 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Wed, 27 Oct 2021 10:12:23 +0200 Subject: fix(changelog): fix for `${(@ps:$sep:)var}` construct in zsh < 5.0.8 In recent zsh versions, `${(@ps:$sep:)var}` where $sep is a variable containing a separator string and $var is a string with multiple values separated by $sep, the `p` flag makes zsh correctly expand $sep before splitting $var. In versions older than 5.0.8, this doesn't happen, so we use `eval` to get the same effect. --- tools/changelog.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/changelog.sh b/tools/changelog.sh index e32d503b1..664f34608 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -428,7 +428,7 @@ function main { fi # Read the commit fields (@ is needed to keep empty values) - raw_fields=("${(@ps:$SEP:)raw_commit}") + eval "raw_fields=(\"\${(@ps:$SEP:)raw_commit}\")" hash="${raw_fields[1]}" refs="${raw_fields[2]}" subject="${raw_fields[3]}" -- cgit v1.2.3-70-g09d2 From 7a2cb106258aa7a18bcd53e45df96c4871a03d5e Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Fri, 5 Nov 2021 19:47:29 +0100 Subject: fix(updater): stop update if connection unavailable --- tools/check_for_upgrade.sh | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/check_for_upgrade.sh b/tools/check_for_upgrade.sh index 157b0cce2..8264762b6 100644 --- a/tools/check_for_upgrade.sh +++ b/tools/check_for_upgrade.sh @@ -54,14 +54,27 @@ function is_update_available() { [[ "$repo" = ohmyzsh/ohmyzsh ]] || return 0 local api_url="https://api.github.com/repos/${repo}/commits/${branch}" - # Get local and remote HEADs and compare them. If we can't get either assume there are updates - local local_head remote_head + # Get local HEAD. If this fails assume there are updates + local local_head local_head=$(git -C "$ZSH" rev-parse $branch 2>/dev/null) || return 0 - remote_head=$(curl -fsSL -H 'Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null) \ - || remote_head=$(wget -O- --header='Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null) \ - || remote_head=$(HTTP_ACCEPT='Accept: application/vnd.github.v3.sha' fetch -o - $api_url 2>/dev/null) \ - || return 0 + # Get remote HEAD. If we can't get it assume there are updates unless there is no connection: + # - curl: 6 (could not resolve) or 7 (could not connect) + # - wget: 4 (network unreachable) + # - fetch: 1 (no route to host) + local remote_head ret + remote_head=$( + curl -fsSL -H 'Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null || { + [[ $? -eq 6 || $? -eq 7 ]] && exit 1 + } || wget -O- --header='Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null || { + [[ $? -eq 4 ]] && exit 1 + } || HTTP_ACCEPT='Accept: application/vnd.github.v3.sha' fetch -o - $api_url 2>/dev/null || { + [[ $? -eq 1 ]] && exit 1 + } || exit 0 + ) + + # If can't fetch remote HEAD, return exit code + ret=$?; [[ -n "$remote_head" ]] || return $ret # Compare local and remote HEADs [[ "$local_head" != "$remote_head" ]] -- cgit v1.2.3-70-g09d2