mirror of
https://github.com/taiki-e/install-action.git
synced 2026-04-27 01:20:28 +00:00
Format shell scripts with indent_size = 2 to match scripts in CI config
This commit is contained in:
@@ -11,7 +11,7 @@ indent_style = space
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.{json,md,rb,yml,yaml}]
|
[*.{json,md,rb,sh,yml,yaml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.{js,yml,yaml}]
|
[*.{js,yml,yaml}]
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ trap -- 's=$?; printf >&2 "%s\n" "${0##*/}:${LINENO}: \`${BASH_COMMAND}\` exit w
|
|||||||
cd -- "$(dirname -- "$0")"/../..
|
cd -- "$(dirname -- "$0")"/../..
|
||||||
|
|
||||||
bail() {
|
bail() {
|
||||||
printf >&2 'error: %s\n' "$*"
|
printf >&2 'error: %s\n' "$*"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -z "${CI:-}" ]]; then
|
if [[ -z "${CI:-}" ]]; then
|
||||||
bail "this script is intended to call from release workflow on CI"
|
bail "this script is intended to call from release workflow on CI"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git config user.name 'Taiki Endo'
|
git config user.name 'Taiki Endo'
|
||||||
@@ -21,28 +21,28 @@ set -x
|
|||||||
|
|
||||||
has_update=''
|
has_update=''
|
||||||
for manifest in manifests/*.json; do
|
for manifest in manifests/*.json; do
|
||||||
git add -N "${manifest}"
|
git add -N "${manifest}"
|
||||||
if ! git diff --exit-code -- "${manifest}"; then
|
if ! git diff --exit-code -- "${manifest}"; then
|
||||||
name="${manifest##*/}"
|
name="${manifest##*/}"
|
||||||
name="${name%.*}"
|
name="${name%.*}"
|
||||||
git stash
|
git stash
|
||||||
old_version=$(jq -r '.latest.version' "${manifest}")
|
old_version=$(jq -r '.latest.version' "${manifest}")
|
||||||
git stash pop
|
git stash pop
|
||||||
new_version=$(jq -r '.latest.version' "${manifest}")
|
new_version=$(jq -r '.latest.version' "${manifest}")
|
||||||
if [[ "${old_version}" != "${new_version}" ]]; then
|
if [[ "${old_version}" != "${new_version}" ]]; then
|
||||||
# TODO: If there is a line about updating the same tool in the "Unreleased" section, replace it.
|
# TODO: If there is a line about updating the same tool in the "Unreleased" section, replace it.
|
||||||
msg="Update \`${name}@latest\` to ${new_version}"
|
msg="Update \`${name}@latest\` to ${new_version}"
|
||||||
sed -Ei "s/^## \\[Unreleased\\]/## [Unreleased]\\n\\n- ${msg}./" CHANGELOG.md
|
sed -Ei "s/^## \\[Unreleased\\]/## [Unreleased]\\n\\n- ${msg}./" CHANGELOG.md
|
||||||
git add "${manifest}" CHANGELOG.md
|
git add "${manifest}" CHANGELOG.md
|
||||||
else
|
else
|
||||||
msg="Update ${name} manifest"
|
msg="Update ${name} manifest"
|
||||||
git add "${manifest}"
|
git add "${manifest}"
|
||||||
fi
|
|
||||||
git commit -m "${msg}"
|
|
||||||
has_update=1
|
|
||||||
fi
|
fi
|
||||||
|
git commit -m "${msg}"
|
||||||
|
has_update=1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -n "${has_update}" ]] && [[ -n "${GITHUB_OUTPUT:-}" ]]; then
|
if [[ -n "${has_update}" ]] && [[ -n "${GITHUB_OUTPUT:-}" ]]; then
|
||||||
printf 'success=false\n' >>"${GITHUB_OUTPUT}"
|
printf 'success=false\n' >>"${GITHUB_OUTPUT}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -8,181 +8,181 @@ cd -- "$(dirname -- "$0")"/../..
|
|||||||
# They don't provide prebuilt binaries for musl or old glibc host.
|
# They don't provide prebuilt binaries for musl or old glibc host.
|
||||||
# version `GLIBC_2.34' not found
|
# version `GLIBC_2.34' not found
|
||||||
glibc_pre_2_34_incompat=(
|
glibc_pre_2_34_incompat=(
|
||||||
cargo-cyclonedx
|
cargo-cyclonedx
|
||||||
cargo-spellcheck
|
cargo-spellcheck
|
||||||
wait-for-them
|
wait-for-them
|
||||||
xbuild
|
xbuild
|
||||||
)
|
)
|
||||||
# version `GLIBC_2.31' not found
|
# version `GLIBC_2.31' not found
|
||||||
glibc_pre_2_31_incompat=(
|
glibc_pre_2_31_incompat=(
|
||||||
"${glibc_pre_2_34_incompat[@]}"
|
"${glibc_pre_2_34_incompat[@]}"
|
||||||
cargo-sort
|
cargo-sort
|
||||||
espup
|
espup
|
||||||
zola
|
zola
|
||||||
)
|
)
|
||||||
# version `GLIBC_2.28' not found
|
# version `GLIBC_2.28' not found
|
||||||
glibc_pre_2_28_incompat=(
|
glibc_pre_2_28_incompat=(
|
||||||
"${glibc_pre_2_31_incompat[@]}"
|
"${glibc_pre_2_31_incompat[@]}"
|
||||||
wasmtime
|
wasmtime
|
||||||
)
|
)
|
||||||
# version `GLIBC_2.27' not found
|
# version `GLIBC_2.27' not found
|
||||||
glibc_pre_2_27_incompat=(
|
glibc_pre_2_27_incompat=(
|
||||||
"${glibc_pre_2_28_incompat[@]}"
|
"${glibc_pre_2_28_incompat[@]}"
|
||||||
cargo-watch
|
cargo-watch
|
||||||
mdbook-linkcheck
|
mdbook-linkcheck
|
||||||
protoc
|
protoc
|
||||||
valgrind
|
valgrind
|
||||||
)
|
)
|
||||||
# version `GLIBC_2.17' not found
|
# version `GLIBC_2.17' not found
|
||||||
glibc_pre_2_17_incompat=(
|
glibc_pre_2_17_incompat=(
|
||||||
"${glibc_pre_2_27_incompat[@]}"
|
"${glibc_pre_2_27_incompat[@]}"
|
||||||
deepsource
|
deepsource
|
||||||
)
|
)
|
||||||
musl_incompat=(
|
musl_incompat=(
|
||||||
"${glibc_pre_2_17_incompat[@]}"
|
"${glibc_pre_2_17_incompat[@]}"
|
||||||
)
|
)
|
||||||
win2019_gnu_incompat=(
|
win2019_gnu_incompat=(
|
||||||
cargo-spellcheck
|
cargo-spellcheck
|
||||||
)
|
)
|
||||||
|
|
||||||
incompat_tools=()
|
incompat_tools=()
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
'') version=latest ;;
|
'') version=latest ;;
|
||||||
major.minor.patch | major.minor | major)
|
major.minor.patch | major.minor | major)
|
||||||
version="$1"
|
version="$1"
|
||||||
# Specifying the version of valgrind and cargo-binstall is not supported.
|
# Specifying the version of valgrind and cargo-binstall is not supported.
|
||||||
incompat_tools+=(valgrind cargo-binstall)
|
incompat_tools+=(valgrind cargo-binstall)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
printf 'tool=%s\n', "$1"
|
printf 'tool=%s\n', "$1"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
runner="${2:-}"
|
runner="${2:-}"
|
||||||
bash="${3:-}"
|
bash="${3:-}"
|
||||||
case "$(uname -s)" in
|
case "$(uname -s)" in
|
||||||
Linux)
|
Linux)
|
||||||
host_os=linux
|
host_os=linux
|
||||||
ldd_version=$(ldd --version 2>&1 || true)
|
ldd_version=$(ldd --version 2>&1 || true)
|
||||||
if grep -Fq musl <<<"${ldd_version}"; then
|
if grep -Fq musl <<<"${ldd_version}"; then
|
||||||
incompat_tools+=("${musl_incompat[@]}")
|
incompat_tools+=("${musl_incompat[@]}")
|
||||||
else
|
else
|
||||||
host_glibc_version=$(grep -E "GLIBC|GNU libc" <<<"${ldd_version}" | sed "s/.* //g")
|
host_glibc_version=$(grep -E "GLIBC|GNU libc" <<<"${ldd_version}" | sed "s/.* //g")
|
||||||
higher_glibc_version=$(sort -Vu <<<"2.34"$'\n'"${host_glibc_version}" | tail -1)
|
higher_glibc_version=$(sort -Vu <<<"2.34"$'\n'"${host_glibc_version}" | tail -1)
|
||||||
|
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
||||||
|
higher_glibc_version=$(sort -Vu <<<"2.31"$'\n'"${host_glibc_version}" | tail -1)
|
||||||
|
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
||||||
|
higher_glibc_version=$(sort -Vu <<<"2.28"$'\n'"${host_glibc_version}" | tail -1)
|
||||||
|
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
||||||
|
higher_glibc_version=$(sort -Vu <<<"2.27"$'\n'"${host_glibc_version}" | tail -1)
|
||||||
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
||||||
higher_glibc_version=$(sort -Vu <<<"2.31"$'\n'"${host_glibc_version}" | tail -1)
|
higher_glibc_version=$(sort -Vu <<<"2.17"$'\n'"${host_glibc_version}" | tail -1)
|
||||||
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
||||||
higher_glibc_version=$(sort -Vu <<<"2.28"$'\n'"${host_glibc_version}" | tail -1)
|
incompat_tools+=("${glibc_pre_2_17_incompat[@]}")
|
||||||
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
else
|
||||||
higher_glibc_version=$(sort -Vu <<<"2.27"$'\n'"${host_glibc_version}" | tail -1)
|
incompat_tools+=("${glibc_pre_2_27_incompat[@]}")
|
||||||
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
fi
|
||||||
higher_glibc_version=$(sort -Vu <<<"2.17"$'\n'"${host_glibc_version}" | tail -1)
|
else
|
||||||
if [[ "${higher_glibc_version}" != "${host_glibc_version}" ]]; then
|
incompat_tools+=("${glibc_pre_2_28_incompat[@]}")
|
||||||
incompat_tools+=("${glibc_pre_2_17_incompat[@]}")
|
|
||||||
else
|
|
||||||
incompat_tools+=("${glibc_pre_2_27_incompat[@]}")
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
incompat_tools+=("${glibc_pre_2_28_incompat[@]}")
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
incompat_tools+=("${glibc_pre_2_31_incompat[@]}")
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
incompat_tools+=("${glibc_pre_2_34_incompat[@]}")
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
incompat_tools+=("${glibc_pre_2_31_incompat[@]}")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
incompat_tools+=("${glibc_pre_2_34_incompat[@]}")
|
||||||
fi
|
fi
|
||||||
if ! type -P snap >/dev/null; then
|
fi
|
||||||
incompat_tools+=(valgrind)
|
fi
|
||||||
|
if ! type -P snap >/dev/null; then
|
||||||
|
incompat_tools+=(valgrind)
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
Darwin) host_os=macos ;;
|
||||||
|
MINGW* | MSYS* | CYGWIN* | Windows_NT)
|
||||||
|
host_os=windows
|
||||||
|
case "${bash}" in
|
||||||
|
msys64 | cygwin)
|
||||||
|
if [[ "${runner}" == "windows-2019" ]]; then
|
||||||
|
incompat_tools+=("${win2019_gnu_incompat[@]}")
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
Darwin) host_os=macos ;;
|
esac
|
||||||
MINGW* | MSYS* | CYGWIN* | Windows_NT)
|
;;
|
||||||
host_os=windows
|
*) bail "unrecognized OS type '$(uname -s)'" ;;
|
||||||
case "${bash}" in
|
|
||||||
msys64 | cygwin)
|
|
||||||
if [[ "${runner}" == "windows-2019" ]]; then
|
|
||||||
incompat_tools+=("${win2019_gnu_incompat[@]}")
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*) bail "unrecognized OS type '$(uname -s)'" ;;
|
|
||||||
esac
|
esac
|
||||||
# See main.sh
|
# See main.sh
|
||||||
case "$(uname -m)" in
|
case "$(uname -m)" in
|
||||||
aarch64 | arm64) host_arch=aarch64 ;;
|
aarch64 | arm64) host_arch=aarch64 ;;
|
||||||
xscale | arm | armv*l) bail "32-bit Arm runner is not supported yet by this action; if you need support for this platform, please submit an issue at <https://github.com/taiki-e/install-action>" ;;
|
xscale | arm | armv*l) bail "32-bit Arm runner is not supported yet by this action; if you need support for this platform, please submit an issue at <https://github.com/taiki-e/install-action>" ;;
|
||||||
*) host_arch=x86_64 ;;
|
*) host_arch=x86_64 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
tools=()
|
tools=()
|
||||||
for manifest in tools/codegen/base/*.json; do
|
for manifest in tools/codegen/base/*.json; do
|
||||||
tool_name="${manifest##*/}"
|
tool_name="${manifest##*/}"
|
||||||
tool_name="${tool_name%.*}"
|
tool_name="${tool_name%.*}"
|
||||||
# cross -V requires rustc
|
# cross -V requires rustc
|
||||||
if [[ "${tool_name}" == "cross" ]] && ! type -P rustc >/dev/null; then
|
if [[ "${tool_name}" == "cross" ]] && ! type -P rustc >/dev/null; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
case "${host_os}" in
|
||||||
|
linux*)
|
||||||
|
if [[ "${host_arch}" != "x86_64" ]] && [[ "$(jq -r ".platform.${host_arch}_${host_os}_gnu" "${manifest}")" == "null" ]] && [[ "$(jq -r ".platform.${host_arch}_${host_os}_musl" "${manifest}")" == "null" ]]; then
|
||||||
continue
|
continue
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ "$(jq -r ".platform.x86_64_${host_os}" "${manifest}")" == "null" ]] && [[ "$(jq -r ".platform.${host_arch}_${host_os}" "${manifest}")" == "null" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
for incompat in ${incompat_tools[@]+"${incompat_tools[@]}"}; do
|
||||||
|
if [[ "${incompat}" == "${tool_name}" ]]; then
|
||||||
|
tool_name=''
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
case "${host_os}" in
|
done
|
||||||
linux*)
|
if [[ -n "${tool_name}" ]]; then
|
||||||
if [[ "${host_arch}" != "x86_64" ]] && [[ "$(jq -r ".platform.${host_arch}_${host_os}_gnu" "${manifest}")" == "null" ]] && [[ "$(jq -r ".platform.${host_arch}_${host_os}_musl" "${manifest}")" == "null" ]]; then
|
if [[ "${version}" != "latest" ]]; then
|
||||||
continue
|
latest_version=$(jq -r '.latest.version' "manifests/${tool_name}.json")
|
||||||
fi
|
case "${version}" in
|
||||||
;;
|
major.minor.patch) tool_name+="@${latest_version}" ;;
|
||||||
*)
|
major.minor) tool_name+="@${latest_version%.*}" ;;
|
||||||
if [[ "$(jq -r ".platform.x86_64_${host_os}" "${manifest}")" == "null" ]] && [[ "$(jq -r ".platform.${host_arch}_${host_os}" "${manifest}")" == "null" ]]; then
|
major) tool_name+="@${latest_version%%.*}" ;;
|
||||||
continue
|
*) exit 1 ;;
|
||||||
fi
|
esac
|
||||||
;;
|
|
||||||
esac
|
|
||||||
for incompat in ${incompat_tools[@]+"${incompat_tools[@]}"}; do
|
|
||||||
if [[ "${incompat}" == "${tool_name}" ]]; then
|
|
||||||
tool_name=''
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ -n "${tool_name}" ]]; then
|
|
||||||
if [[ "${version}" != "latest" ]]; then
|
|
||||||
latest_version=$(jq -r '.latest.version' "manifests/${tool_name}.json")
|
|
||||||
case "${version}" in
|
|
||||||
major.minor.patch) tool_name+="@${latest_version}" ;;
|
|
||||||
major.minor) tool_name+="@${latest_version%.*}" ;;
|
|
||||||
major) tool_name+="@${latest_version%%.*}" ;;
|
|
||||||
*) exit 1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
if [[ "${tool_name}" != *"@0" ]] && [[ "${tool_name}" != *"@0.0" ]]; then
|
|
||||||
tools+=("${tool_name}")
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
if [[ "${tool_name}" != *"@0" ]] && [[ "${tool_name}" != *"@0.0" ]]; then
|
||||||
|
tools+=("${tool_name}")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
if [[ "${version}" != "latest" ]]; then
|
if [[ "${version}" != "latest" ]]; then
|
||||||
tools_tmp=()
|
tools_tmp=()
|
||||||
for tool in "${tools[@]}"; do
|
for tool in "${tools[@]}"; do
|
||||||
tools_tmp+=("${tool}")
|
tools_tmp+=("${tool}")
|
||||||
done
|
done
|
||||||
tools=("${tools_tmp[@]}")
|
tools=("${tools_tmp[@]}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Not manifest-based
|
# Not manifest-based
|
||||||
case "${host_os}" in
|
case "${host_os}" in
|
||||||
linux*)
|
linux*)
|
||||||
# Installing snap to container is difficult...
|
# Installing snap to container is difficult...
|
||||||
# Specifying the version of valgrind is not supported.
|
# Specifying the version of valgrind is not supported.
|
||||||
if type -P snap >/dev/null && [[ "${version}" == "latest" ]]; then
|
if type -P snap >/dev/null && [[ "${version}" == "latest" ]]; then
|
||||||
tools+=(valgrind)
|
tools+=(valgrind)
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
# cargo-watch/watchexec-cli is supported by cargo-binstall (through quickinstall)
|
# cargo-watch/watchexec-cli is supported by cargo-binstall (through quickinstall)
|
||||||
case "${version}" in
|
case "${version}" in
|
||||||
latest) tools+=(cargo-watch watchexec-cli) ;;
|
latest) tools+=(cargo-watch watchexec-cli) ;;
|
||||||
major.minor.patch) tools+=(cargo-watch@8.5.2 watchexec-cli@2.1.2) ;;
|
major.minor.patch) tools+=(cargo-watch@8.5.2 watchexec-cli@2.1.2) ;;
|
||||||
major.minor) tools+=(cargo-watch@8.5 watchexec-cli@2.1) ;;
|
major.minor) tools+=(cargo-watch@8.5 watchexec-cli@2.1) ;;
|
||||||
major) tools+=(cargo-watch@8 watchexec-cli@2) ;;
|
major) tools+=(cargo-watch@8 watchexec-cli@2) ;;
|
||||||
*) exit 1 ;;
|
*) exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# sort and dedup
|
# sort and dedup
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ cd -- "$(dirname -- "$0")"/..
|
|||||||
# ./tools/manifest.sh [PACKAGE [VERSION_REQ]]
|
# ./tools/manifest.sh [PACKAGE [VERSION_REQ]]
|
||||||
|
|
||||||
if [[ $# -gt 0 ]]; then
|
if [[ $# -gt 0 ]]; then
|
||||||
cargo run --manifest-path tools/codegen/Cargo.toml --release -- "$@"
|
cargo run --manifest-path tools/codegen/Cargo.toml --release -- "$@"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for manifest in tools/codegen/base/*.json; do
|
for manifest in tools/codegen/base/*.json; do
|
||||||
package="${manifest##*/}"
|
package="${manifest##*/}"
|
||||||
package="${package%.*}"
|
package="${package%.*}"
|
||||||
cargo run --manifest-path tools/codegen/Cargo.toml --release -- "${package}" latest
|
cargo run --manifest-path tools/codegen/Cargo.toml --release -- "${package}" latest
|
||||||
done
|
done
|
||||||
|
|||||||
138
tools/publish.sh
138
tools/publish.sh
@@ -14,18 +14,18 @@ cd -- "$(dirname -- "$0")"/..
|
|||||||
# - parse-changelog <https://github.com/taiki-e/parse-changelog>
|
# - parse-changelog <https://github.com/taiki-e/parse-changelog>
|
||||||
|
|
||||||
retry() {
|
retry() {
|
||||||
for i in {1..10}; do
|
for i in {1..10}; do
|
||||||
if "$@"; then
|
if "$@"; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
sleep "${i}"
|
sleep "${i}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
"$@"
|
"$@"
|
||||||
}
|
}
|
||||||
bail() {
|
bail() {
|
||||||
printf >&2 'error: %s\n' "$*"
|
printf >&2 'error: %s\n' "$*"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
version="${1:?}"
|
version="${1:?}"
|
||||||
@@ -34,15 +34,15 @@ tag_prefix="v"
|
|||||||
tag="${tag_prefix}${version}"
|
tag="${tag_prefix}${version}"
|
||||||
changelog="CHANGELOG.md"
|
changelog="CHANGELOG.md"
|
||||||
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z\.-]+)?(\+[0-9A-Za-z\.-]+)?$ ]]; then
|
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z\.-]+)?(\+[0-9A-Za-z\.-]+)?$ ]]; then
|
||||||
bail "invalid version format '${version}'"
|
bail "invalid version format '${version}'"
|
||||||
fi
|
fi
|
||||||
if [[ $# -gt 1 ]]; then
|
if [[ $# -gt 1 ]]; then
|
||||||
bail "invalid argument '$2'"
|
bail "invalid argument '$2'"
|
||||||
fi
|
fi
|
||||||
if { sed --help 2>&1 || true; } | grep -Eq -e '-i extension'; then
|
if { sed --help 2>&1 || true; } | grep -Eq -e '-i extension'; then
|
||||||
in_place=(-i '')
|
in_place=(-i '')
|
||||||
else
|
else
|
||||||
in_place=(-i)
|
in_place=(-i)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure there is no uncommitted change.
|
# Make sure there is no uncommitted change.
|
||||||
@@ -51,67 +51,67 @@ git diff --exit-code --staged
|
|||||||
|
|
||||||
# Make sure the same release has not been created in the past.
|
# Make sure the same release has not been created in the past.
|
||||||
if gh release view "${tag}" &>/dev/null; then
|
if gh release view "${tag}" &>/dev/null; then
|
||||||
bail "tag '${tag}' has already been created and pushed"
|
bail "tag '${tag}' has already been created and pushed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure that the release was created from an allowed branch.
|
# Make sure that the release was created from an allowed branch.
|
||||||
if ! git branch | grep -Eq '\* main$'; then
|
if ! git branch | grep -Eq '\* main$'; then
|
||||||
bail "current branch is not 'main'"
|
bail "current branch is not 'main'"
|
||||||
fi
|
fi
|
||||||
if ! git remote -v | grep -F origin | grep -Eq 'github\.com[:/]taiki-e/'; then
|
if ! git remote -v | grep -F origin | grep -Eq 'github\.com[:/]taiki-e/'; then
|
||||||
bail "cannot publish a new release from fork repository"
|
bail "cannot publish a new release from fork repository"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
release_date=$(date -u '+%Y-%m-%d')
|
release_date=$(date -u '+%Y-%m-%d')
|
||||||
tags=$(git --no-pager tag | { grep -E "^${tag_prefix}[0-9]+" || true; })
|
tags=$(git --no-pager tag | { grep -E "^${tag_prefix}[0-9]+" || true; })
|
||||||
if [[ -n "${tags}" ]]; then
|
if [[ -n "${tags}" ]]; then
|
||||||
# Make sure the same release does not exist in changelog.
|
# Make sure the same release does not exist in changelog.
|
||||||
if grep -Eq "^## \\[${version//./\\.}\\]" "${changelog}"; then
|
if grep -Eq "^## \\[${version//./\\.}\\]" "${changelog}"; then
|
||||||
bail "release ${version} already exist in ${changelog}"
|
bail "release ${version} already exist in ${changelog}"
|
||||||
fi
|
fi
|
||||||
if grep -Eq "^\\[${version//./\\.}\\]: " "${changelog}"; then
|
if grep -Eq "^\\[${version//./\\.}\\]: " "${changelog}"; then
|
||||||
bail "link to ${version} already exist in ${changelog}"
|
bail "link to ${version} already exist in ${changelog}"
|
||||||
fi
|
fi
|
||||||
# Update changelog.
|
# Update changelog.
|
||||||
remote_url=$(grep -E '^\[Unreleased\]: https://' "${changelog}" | sed -E 's/^\[Unreleased\]: //; s/\.\.\.HEAD$//')
|
remote_url=$(grep -E '^\[Unreleased\]: https://' "${changelog}" | sed -E 's/^\[Unreleased\]: //; s/\.\.\.HEAD$//')
|
||||||
prev_tag="${remote_url#*/compare/}"
|
prev_tag="${remote_url#*/compare/}"
|
||||||
remote_url="${remote_url%/compare/*}"
|
remote_url="${remote_url%/compare/*}"
|
||||||
sed -E "${in_place[@]}" \
|
sed -E "${in_place[@]}" \
|
||||||
-e "s/^## \\[Unreleased\\]/## [Unreleased]\\n\\n## [${version}] - ${release_date}/" \
|
-e "s/^## \\[Unreleased\\]/## [Unreleased]\\n\\n## [${version}] - ${release_date}/" \
|
||||||
-e "s#^\[Unreleased\]: https://.*#[Unreleased]: ${remote_url}/compare/${tag}...HEAD\\n[${version}]: ${remote_url}/compare/${prev_tag}...${tag}#" "${changelog}"
|
-e "s#^\[Unreleased\]: https://.*#[Unreleased]: ${remote_url}/compare/${tag}...HEAD\\n[${version}]: ${remote_url}/compare/${prev_tag}...${tag}#" "${changelog}"
|
||||||
if ! grep -Eq "^## \\[${version//./\\.}\\] - ${release_date}$" "${changelog}"; then
|
if ! grep -Eq "^## \\[${version//./\\.}\\] - ${release_date}$" "${changelog}"; then
|
||||||
bail "failed to update ${changelog}"
|
bail "failed to update ${changelog}"
|
||||||
fi
|
fi
|
||||||
if ! grep -Eq "^\\[${version//./\\.}\\]: " "${changelog}"; then
|
if ! grep -Eq "^\\[${version//./\\.}\\]: " "${changelog}"; then
|
||||||
bail "failed to update ${changelog}"
|
bail "failed to update ${changelog}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Make sure the release exists in changelog.
|
# Make sure the release exists in changelog.
|
||||||
if ! grep -Eq "^## \\[${version//./\\.}\\] - ${release_date}$" "${changelog}"; then
|
if ! grep -Eq "^## \\[${version//./\\.}\\] - ${release_date}$" "${changelog}"; then
|
||||||
bail "release ${version} does not exist in ${changelog} or has wrong release date"
|
bail "release ${version} does not exist in ${changelog} or has wrong release date"
|
||||||
fi
|
fi
|
||||||
if ! grep -Eq "^\\[${version//./\\.}\\]: " "${changelog}"; then
|
if ! grep -Eq "^\\[${version//./\\.}\\]: " "${changelog}"; then
|
||||||
bail "link to ${version} does not exist in ${changelog}"
|
bail "link to ${version} does not exist in ${changelog}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure that a valid release note for this version exists.
|
# Make sure that a valid release note for this version exists.
|
||||||
# https://github.com/taiki-e/parse-changelog
|
# https://github.com/taiki-e/parse-changelog
|
||||||
changes=$(parse-changelog "${changelog}" "${version}")
|
changes=$(parse-changelog "${changelog}" "${version}")
|
||||||
if [[ -z "${changes}" ]]; then
|
if [[ -z "${changes}" ]]; then
|
||||||
bail "changelog for ${version} has no body"
|
bail "changelog for ${version} has no body"
|
||||||
fi
|
fi
|
||||||
printf '============== CHANGELOG ==============\n'
|
printf '============== CHANGELOG ==============\n'
|
||||||
printf '%s\n' "${changes}"
|
printf '%s\n' "${changes}"
|
||||||
printf '=======================================\n'
|
printf '=======================================\n'
|
||||||
|
|
||||||
if [[ -n "${tags}" ]]; then
|
if [[ -n "${tags}" ]]; then
|
||||||
# Create a release commit.
|
# Create a release commit.
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
git add "${changelog}"
|
git add "${changelog}"
|
||||||
git commit -m "Release ${version}"
|
git commit -m "Release ${version}"
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
@@ -124,8 +124,8 @@ major_version_tag="v${version%%.*}"
|
|||||||
git checkout -b "${major_version_tag}"
|
git checkout -b "${major_version_tag}"
|
||||||
retry git push origin refs/heads/"${major_version_tag}"
|
retry git push origin refs/heads/"${major_version_tag}"
|
||||||
if git --no-pager tag | grep -Eq "^${major_version_tag}$"; then
|
if git --no-pager tag | grep -Eq "^${major_version_tag}$"; then
|
||||||
git tag -d "${major_version_tag}"
|
git tag -d "${major_version_tag}"
|
||||||
retry git push --delete origin refs/tags/"${major_version_tag}"
|
retry git push --delete origin refs/tags/"${major_version_tag}"
|
||||||
fi
|
fi
|
||||||
git tag "${major_version_tag}"
|
git tag "${major_version_tag}"
|
||||||
retry git push origin --tags
|
retry git push origin --tags
|
||||||
@@ -134,8 +134,8 @@ git branch -d "${major_version_tag}"
|
|||||||
|
|
||||||
tools=()
|
tools=()
|
||||||
for tool in tools/codegen/base/*.json; do
|
for tool in tools/codegen/base/*.json; do
|
||||||
tool="${tool##*/}"
|
tool="${tool##*/}"
|
||||||
tools+=("${tool%.*}")
|
tools+=("${tool%.*}")
|
||||||
done
|
done
|
||||||
# Alias
|
# Alias
|
||||||
tools+=(nextest)
|
tools+=(nextest)
|
||||||
@@ -143,18 +143,18 @@ tools+=(nextest)
|
|||||||
tools+=(valgrind)
|
tools+=(valgrind)
|
||||||
|
|
||||||
for tool in "${tools[@]}"; do
|
for tool in "${tools[@]}"; do
|
||||||
git checkout -b "${tool}"
|
git checkout -b "${tool}"
|
||||||
sed -E "${in_place[@]}" "s/required: true/required: false/g" action.yml
|
sed -E "${in_place[@]}" "s/required: true/required: false/g" action.yml
|
||||||
sed -E "${in_place[@]}" "s/# default: #publish:tool/default: ${tool}/g" action.yml
|
sed -E "${in_place[@]}" "s/# default: #publish:tool/default: ${tool}/g" action.yml
|
||||||
git add action.yml
|
git add action.yml
|
||||||
git commit -m "${tool}"
|
git commit -m "${tool}"
|
||||||
retry git push origin -f refs/heads/"${tool}"
|
retry git push origin -f refs/heads/"${tool}"
|
||||||
if git --no-pager tag | grep -Eq "^${tool}$"; then
|
if git --no-pager tag | grep -Eq "^${tool}$"; then
|
||||||
git tag -d "${tool}"
|
git tag -d "${tool}"
|
||||||
retry git push --delete origin refs/tags/"${tool}"
|
retry git push --delete origin refs/tags/"${tool}"
|
||||||
fi
|
fi
|
||||||
git tag "${tool}"
|
git tag "${tool}"
|
||||||
retry git push origin --tags
|
retry git push origin --tags
|
||||||
git checkout main
|
git checkout main
|
||||||
git branch -D "${tool}"
|
git branch -D "${tool}"
|
||||||
done
|
done
|
||||||
|
|||||||
758
tools/tidy.sh
758
tools/tidy.sh
@@ -25,464 +25,464 @@ trap 's=$?; echo >&2 "$0: error on line "${LINENO}": ${BASH_COMMAND}"; exit ${s}
|
|||||||
# skipped if the corresponding files do not exist.
|
# skipped if the corresponding files do not exist.
|
||||||
|
|
||||||
check_diff() {
|
check_diff() {
|
||||||
if [[ -n "${CI:-}" ]]; then
|
if [[ -n "${CI:-}" ]]; then
|
||||||
if ! git --no-pager diff --exit-code "$@"; then
|
if ! git --no-pager diff --exit-code "$@"; then
|
||||||
should_fail=1
|
should_fail=1
|
||||||
fi
|
|
||||||
else
|
|
||||||
if ! git --no-pager diff --exit-code "$@" &>/dev/null; then
|
|
||||||
should_fail=1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
if ! git --no-pager diff --exit-code "$@" &>/dev/null; then
|
||||||
|
should_fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
check_config() {
|
check_config() {
|
||||||
if [[ ! -e "$1" ]]; then
|
if [[ ! -e "$1" ]]; then
|
||||||
error "could not found $1 in the repository root"
|
error "could not found $1 in the repository root"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
check_install() {
|
check_install() {
|
||||||
for tool in "$@"; do
|
for tool in "$@"; do
|
||||||
if ! type -P "${tool}" &>/dev/null; then
|
if ! type -P "${tool}" &>/dev/null; then
|
||||||
if [[ "${tool}" == "python3" ]]; then
|
if [[ "${tool}" == "python3" ]]; then
|
||||||
if type -P python &>/dev/null; then
|
if type -P python &>/dev/null; then
|
||||||
continue
|
continue
|
||||||
fi
|
|
||||||
fi
|
|
||||||
error "'${tool}' is required to run this check"
|
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
done
|
fi
|
||||||
|
error "'${tool}' is required to run this check"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
}
|
}
|
||||||
info() {
|
info() {
|
||||||
echo >&2 "info: $*"
|
echo >&2 "info: $*"
|
||||||
}
|
}
|
||||||
error() {
|
error() {
|
||||||
if [[ -n "${GITHUB_ACTIONS:-}" ]]; then
|
if [[ -n "${GITHUB_ACTIONS:-}" ]]; then
|
||||||
echo "::error::$*"
|
echo "::error::$*"
|
||||||
else
|
else
|
||||||
echo >&2 "error: $*"
|
echo >&2 "error: $*"
|
||||||
fi
|
fi
|
||||||
should_fail=1
|
should_fail=1
|
||||||
}
|
}
|
||||||
venv() {
|
venv() {
|
||||||
local bin="$1"
|
local bin="$1"
|
||||||
shift
|
shift
|
||||||
"${venv_bin}/${bin}${exe}" "$@"
|
"${venv_bin}/${bin}${exe}" "$@"
|
||||||
}
|
}
|
||||||
venv_install_yq() {
|
venv_install_yq() {
|
||||||
local py_suffix=''
|
local py_suffix=''
|
||||||
if type -P python3 &>/dev/null; then
|
if type -P python3 &>/dev/null; then
|
||||||
py_suffix='3'
|
py_suffix='3'
|
||||||
fi
|
fi
|
||||||
exe=''
|
exe=''
|
||||||
venv_bin='.venv/bin'
|
venv_bin='.venv/bin'
|
||||||
case "$(uname -s)" in
|
case "$(uname -s)" in
|
||||||
MINGW* | MSYS* | CYGWIN* | Windows_NT)
|
MINGW* | MSYS* | CYGWIN* | Windows_NT)
|
||||||
exe='.exe'
|
exe='.exe'
|
||||||
venv_bin='.venv/Scripts'
|
venv_bin='.venv/Scripts'
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
if [[ ! -d .venv ]]; then
|
if [[ ! -d .venv ]]; then
|
||||||
"python${py_suffix}" -m venv .venv
|
"python${py_suffix}" -m venv .venv
|
||||||
fi
|
fi
|
||||||
if [[ ! -e "${venv_bin}/yq${exe}" ]]; then
|
if [[ ! -e "${venv_bin}/yq${exe}" ]]; then
|
||||||
info "installing yq to ./.venv using pip"
|
info "installing yq to ./.venv using pip"
|
||||||
venv "pip${py_suffix}" install yq
|
venv "pip${py_suffix}" install yq
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $# -gt 0 ]]; then
|
if [[ $# -gt 0 ]]; then
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
USAGE:
|
USAGE:
|
||||||
$0
|
$0
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rust (if exists)
|
# Rust (if exists)
|
||||||
if [[ -n "$(git ls-files '*.rs')" ]]; then
|
if [[ -n "$(git ls-files '*.rs')" ]]; then
|
||||||
info "checking Rust code style"
|
info "checking Rust code style"
|
||||||
check_install cargo jq python3
|
check_install cargo jq python3
|
||||||
check_config .rustfmt.toml
|
check_config .rustfmt.toml
|
||||||
if check_install rustup; then
|
if check_install rustup; then
|
||||||
# `cargo fmt` cannot recognize files not included in the current workspace and modules
|
# `cargo fmt` cannot recognize files not included in the current workspace and modules
|
||||||
# defined inside macros, so run rustfmt directly.
|
# defined inside macros, so run rustfmt directly.
|
||||||
# We need to use nightly rustfmt because we use the unstable formatting options of rustfmt.
|
# We need to use nightly rustfmt because we use the unstable formatting options of rustfmt.
|
||||||
rustc_version=$(rustc -vV | grep '^release:' | cut -d' ' -f2)
|
rustc_version=$(rustc -vV | grep '^release:' | cut -d' ' -f2)
|
||||||
if [[ "${rustc_version}" == *"nightly"* ]] || [[ "${rustc_version}" == *"dev"* ]]; then
|
if [[ "${rustc_version}" == *"nightly"* ]] || [[ "${rustc_version}" == *"dev"* ]]; then
|
||||||
rustup component add rustfmt &>/dev/null
|
rustup component add rustfmt &>/dev/null
|
||||||
info "running \`rustfmt \$(git ls-files '*.rs')\`"
|
info "running \`rustfmt \$(git ls-files '*.rs')\`"
|
||||||
rustfmt $(git ls-files '*.rs')
|
rustfmt $(git ls-files '*.rs')
|
||||||
else
|
else
|
||||||
rustup component add rustfmt --toolchain nightly &>/dev/null
|
rustup component add rustfmt --toolchain nightly &>/dev/null
|
||||||
info "running \`rustfmt +nightly \$(git ls-files '*.rs')\`"
|
info "running \`rustfmt +nightly \$(git ls-files '*.rs')\`"
|
||||||
rustfmt +nightly $(git ls-files '*.rs')
|
rustfmt +nightly $(git ls-files '*.rs')
|
||||||
fi
|
|
||||||
check_diff $(git ls-files '*.rs')
|
|
||||||
fi
|
fi
|
||||||
cast_without_turbofish=$(grep -n -E '\.cast\(\)' $(git ls-files '*.rs') || true)
|
check_diff $(git ls-files '*.rs')
|
||||||
if [[ -n "${cast_without_turbofish}" ]]; then
|
fi
|
||||||
error "please replace \`.cast()\` with \`.cast::<type_name>()\`:"
|
cast_without_turbofish=$(grep -n -E '\.cast\(\)' $(git ls-files '*.rs') || true)
|
||||||
echo "${cast_without_turbofish}"
|
if [[ -n "${cast_without_turbofish}" ]]; then
|
||||||
|
error "please replace \`.cast()\` with \`.cast::<type_name>()\`:"
|
||||||
|
echo "${cast_without_turbofish}"
|
||||||
|
fi
|
||||||
|
# Sync readme and crate-level doc.
|
||||||
|
first='1'
|
||||||
|
for readme in $(git ls-files '*README.md'); do
|
||||||
|
if ! grep -q '^<!-- tidy:crate-doc:start -->' "${readme}"; then
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
# Sync readme and crate-level doc.
|
lib="$(dirname "${readme}")/src/lib.rs"
|
||||||
first='1'
|
if [[ -n "${first}" ]]; then
|
||||||
for readme in $(git ls-files '*README.md'); do
|
first=''
|
||||||
if ! grep -q '^<!-- tidy:crate-doc:start -->' "${readme}"; then
|
info "checking readme and crate-level doc are synchronized"
|
||||||
continue
|
fi
|
||||||
fi
|
if ! grep -q '^<!-- tidy:crate-doc:end -->' "${readme}"; then
|
||||||
lib="$(dirname "${readme}")/src/lib.rs"
|
bail "missing '<!-- tidy:crate-doc:end -->' comment in ${readme}"
|
||||||
if [[ -n "${first}" ]]; then
|
fi
|
||||||
first=''
|
if ! grep -q '^<!-- tidy:crate-doc:start -->' "${lib}"; then
|
||||||
info "checking readme and crate-level doc are synchronized"
|
bail "missing '<!-- tidy:crate-doc:start -->' comment in ${lib}"
|
||||||
fi
|
fi
|
||||||
if ! grep -q '^<!-- tidy:crate-doc:end -->' "${readme}"; then
|
if ! grep -q '^<!-- tidy:crate-doc:end -->' "${lib}"; then
|
||||||
bail "missing '<!-- tidy:crate-doc:end -->' comment in ${readme}"
|
bail "missing '<!-- tidy:crate-doc:end -->' comment in ${lib}"
|
||||||
fi
|
fi
|
||||||
if ! grep -q '^<!-- tidy:crate-doc:start -->' "${lib}"; then
|
new=$(tr <"${readme}" '\n' '\a' | grep -o '<!-- tidy:crate-doc:start -->.*<!-- tidy:crate-doc:end -->' | sed 's/\&/\\\&/g; s/\\/\\\\/g')
|
||||||
bail "missing '<!-- tidy:crate-doc:start -->' comment in ${lib}"
|
new=$(tr <"${lib}" '\n' '\a' | awk -v new="${new}" 'gsub("<!-- tidy:crate-doc:start -->.*<!-- tidy:crate-doc:end -->",new)' | tr '\a' '\n')
|
||||||
fi
|
echo "${new}" >"${lib}"
|
||||||
if ! grep -q '^<!-- tidy:crate-doc:end -->' "${lib}"; then
|
check_diff "${lib}"
|
||||||
bail "missing '<!-- tidy:crate-doc:end -->' comment in ${lib}"
|
done
|
||||||
fi
|
# Make sure that public Rust crates don't contain executables and binaries.
|
||||||
new=$(tr <"${readme}" '\n' '\a' | grep -o '<!-- tidy:crate-doc:start -->.*<!-- tidy:crate-doc:end -->' | sed 's/\&/\\\&/g; s/\\/\\\\/g')
|
executables=''
|
||||||
new=$(tr <"${lib}" '\n' '\a' | awk -v new="${new}" 'gsub("<!-- tidy:crate-doc:start -->.*<!-- tidy:crate-doc:end -->",new)' | tr '\a' '\n')
|
binaries=''
|
||||||
echo "${new}" >"${lib}"
|
metadata=$(cargo metadata --format-version=1 --no-deps)
|
||||||
check_diff "${lib}"
|
has_public_crate=''
|
||||||
done
|
has_root_crate=''
|
||||||
# Make sure that public Rust crates don't contain executables and binaries.
|
venv_install_yq
|
||||||
executables=''
|
for id in $(jq <<<"${metadata}" '.workspace_members[]'); do
|
||||||
binaries=''
|
pkg=$(jq <<<"${metadata}" ".packages[] | select(.id == ${id})")
|
||||||
metadata=$(cargo metadata --format-version=1 --no-deps)
|
publish=$(jq <<<"${pkg}" -r '.publish')
|
||||||
has_public_crate=''
|
manifest_path=$(jq <<<"${pkg}" -r '.manifest_path')
|
||||||
has_root_crate=''
|
if [[ "$(venv tomlq -c '.lints' "${manifest_path}")" == "null" ]]; then
|
||||||
venv_install_yq
|
error "no [lints] table in ${manifest_path} please add '[lints]' with 'workspace = true'"
|
||||||
for id in $(jq <<<"${metadata}" '.workspace_members[]'); do
|
fi
|
||||||
pkg=$(jq <<<"${metadata}" ".packages[] | select(.id == ${id})")
|
# Publishing is unrestricted if null, and forbidden if an empty array.
|
||||||
publish=$(jq <<<"${pkg}" -r '.publish')
|
if [[ "${publish}" == "[]" ]]; then
|
||||||
manifest_path=$(jq <<<"${pkg}" -r '.manifest_path')
|
continue
|
||||||
if [[ "$(venv tomlq -c '.lints' "${manifest_path}")" == "null" ]]; then
|
fi
|
||||||
error "no [lints] table in ${manifest_path} please add '[lints]' with 'workspace = true'"
|
has_public_crate='1'
|
||||||
fi
|
done
|
||||||
|
if [[ -n "${has_public_crate}" ]]; then
|
||||||
|
info "checking public crates don't contain executables and binaries"
|
||||||
|
if [[ -f Cargo.toml ]]; then
|
||||||
|
root_manifest=$(cargo locate-project --message-format=plain --manifest-path Cargo.toml)
|
||||||
|
root_pkg=$(jq <<<"${metadata}" ".packages[] | select(.manifest_path == \"${root_manifest}\")")
|
||||||
|
if [[ -n "${root_pkg}" ]]; then
|
||||||
|
publish=$(jq <<<"${root_pkg}" -r '.publish')
|
||||||
# Publishing is unrestricted if null, and forbidden if an empty array.
|
# Publishing is unrestricted if null, and forbidden if an empty array.
|
||||||
if [[ "${publish}" == "[]" ]]; then
|
if [[ "${publish}" != "[]" ]]; then
|
||||||
continue
|
has_root_crate=1
|
||||||
fi
|
exclude=$(venv tomlq -r '.package.exclude[]' Cargo.toml)
|
||||||
has_public_crate='1'
|
if ! grep <<<"${exclude}" -Eq '^/\.\*$'; then
|
||||||
done
|
error "top-level Cargo.toml of non-virtual workspace should have 'exclude' field with \"/.*\""
|
||||||
if [[ -n "${has_public_crate}" ]]; then
|
fi
|
||||||
info "checking public crates don't contain executables and binaries"
|
if [[ -e tools ]] && ! grep <<<"${exclude}" -Eq '^/tools$'; then
|
||||||
if [[ -f Cargo.toml ]]; then
|
error "top-level Cargo.toml of non-virtual workspace should have 'exclude' field with \"/tools\" if it exists"
|
||||||
root_manifest=$(cargo locate-project --message-format=plain --manifest-path Cargo.toml)
|
fi
|
||||||
root_pkg=$(jq <<<"${metadata}" ".packages[] | select(.manifest_path == \"${root_manifest}\")")
|
if [[ -e target-specs ]] && ! grep <<<"${exclude}" -Eq '^/target-specs$'; then
|
||||||
if [[ -n "${root_pkg}" ]]; then
|
error "top-level Cargo.toml of non-virtual workspace should have 'exclude' field with \"/target-specs\" if it exists"
|
||||||
publish=$(jq <<<"${root_pkg}" -r '.publish')
|
fi
|
||||||
# Publishing is unrestricted if null, and forbidden if an empty array.
|
|
||||||
if [[ "${publish}" != "[]" ]]; then
|
|
||||||
has_root_crate=1
|
|
||||||
exclude=$(venv tomlq -r '.package.exclude[]' Cargo.toml)
|
|
||||||
if ! grep <<<"${exclude}" -Eq '^/\.\*$'; then
|
|
||||||
error "top-level Cargo.toml of non-virtual workspace should have 'exclude' field with \"/.*\""
|
|
||||||
fi
|
|
||||||
if [[ -e tools ]] && ! grep <<<"${exclude}" -Eq '^/tools$'; then
|
|
||||||
error "top-level Cargo.toml of non-virtual workspace should have 'exclude' field with \"/tools\" if it exists"
|
|
||||||
fi
|
|
||||||
if [[ -e target-specs ]] && ! grep <<<"${exclude}" -Eq '^/target-specs$'; then
|
|
||||||
error "top-level Cargo.toml of non-virtual workspace should have 'exclude' field with \"/target-specs\" if it exists"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
for p in $(git ls-files); do
|
|
||||||
# Skip directories.
|
|
||||||
if [[ -d "${p}" ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
# Top-level hidden files/directories and tools/* are excluded from crates.io (ensured by the above check).
|
|
||||||
# TODO: fully respect exclude field in Cargo.toml.
|
|
||||||
case "${p}" in
|
|
||||||
.* | tools/* | target-specs/*) continue ;;
|
|
||||||
*/*) ;;
|
|
||||||
*)
|
|
||||||
# If there is no crate at root, executables at the repository root directory if always okay.
|
|
||||||
if [[ -z "${has_root_crate}" ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if [[ -x "${p}" ]]; then
|
|
||||||
executables+="${p}"$'\n'
|
|
||||||
fi
|
|
||||||
# Use diff instead of file because file treats an empty file as a binary
|
|
||||||
# https://unix.stackexchange.com/questions/275516/is-there-a-convenient-way-to-classify-files-as-binary-or-text#answer-402870
|
|
||||||
if (diff .gitattributes "${p}" || true) | grep -q '^Binary file'; then
|
|
||||||
binaries+="${p}"$'\n'
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ -n "${executables}" ]]; then
|
|
||||||
error "file-permissions-check failed: executables are only allowed to be present in directories that are excluded from crates.io"
|
|
||||||
echo "======================================="
|
|
||||||
echo -n "${executables}"
|
|
||||||
echo "======================================="
|
|
||||||
fi
|
|
||||||
if [[ -n "${binaries}" ]]; then
|
|
||||||
error "file-permissions-check failed: binaries are only allowed to be present in directories that are excluded from crates.io"
|
|
||||||
echo "======================================="
|
|
||||||
echo -n "${binaries}"
|
|
||||||
echo "======================================="
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
for p in $(git ls-files); do
|
||||||
|
# Skip directories.
|
||||||
|
if [[ -d "${p}" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# Top-level hidden files/directories and tools/* are excluded from crates.io (ensured by the above check).
|
||||||
|
# TODO: fully respect exclude field in Cargo.toml.
|
||||||
|
case "${p}" in
|
||||||
|
.* | tools/* | target-specs/*) continue ;;
|
||||||
|
*/*) ;;
|
||||||
|
*)
|
||||||
|
# If there is no crate at root, executables at the repository root directory if always okay.
|
||||||
|
if [[ -z "${has_root_crate}" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [[ -x "${p}" ]]; then
|
||||||
|
executables+="${p}"$'\n'
|
||||||
|
fi
|
||||||
|
# Use diff instead of file because file treats an empty file as a binary
|
||||||
|
# https://unix.stackexchange.com/questions/275516/is-there-a-convenient-way-to-classify-files-as-binary-or-text#answer-402870
|
||||||
|
if (diff .gitattributes "${p}" || true) | grep -q '^Binary file'; then
|
||||||
|
binaries+="${p}"$'\n'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -n "${executables}" ]]; then
|
||||||
|
error "file-permissions-check failed: executables are only allowed to be present in directories that are excluded from crates.io"
|
||||||
|
echo "======================================="
|
||||||
|
echo -n "${executables}"
|
||||||
|
echo "======================================="
|
||||||
|
fi
|
||||||
|
if [[ -n "${binaries}" ]]; then
|
||||||
|
error "file-permissions-check failed: binaries are only allowed to be present in directories that are excluded from crates.io"
|
||||||
|
echo "======================================="
|
||||||
|
echo -n "${binaries}"
|
||||||
|
echo "======================================="
|
||||||
|
fi
|
||||||
|
fi
|
||||||
elif [[ -e .rustfmt.toml ]]; then
|
elif [[ -e .rustfmt.toml ]]; then
|
||||||
error ".rustfmt.toml is unused"
|
error ".rustfmt.toml is unused"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# C/C++ (if exists)
|
# C/C++ (if exists)
|
||||||
if [[ -n "$(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')" ]]; then
|
if [[ -n "$(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')" ]]; then
|
||||||
info "checking C/C++ code style"
|
info "checking C/C++ code style"
|
||||||
check_config .clang-format
|
check_config .clang-format
|
||||||
if check_install clang-format; then
|
if check_install clang-format; then
|
||||||
info "running \`clang-format -i \$(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')\`"
|
info "running \`clang-format -i \$(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')\`"
|
||||||
clang-format -i $(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')
|
clang-format -i $(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')
|
||||||
check_diff $(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')
|
check_diff $(git ls-files '*.c' '*.h' '*.cpp' '*.hpp')
|
||||||
fi
|
fi
|
||||||
elif [[ -e .clang-format ]]; then
|
elif [[ -e .clang-format ]]; then
|
||||||
error ".clang-format is unused"
|
error ".clang-format is unused"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# YAML/JavaScript/JSON (if exists)
|
# YAML/JavaScript/JSON (if exists)
|
||||||
if [[ -n "$(git ls-files '*.yml' '*.yaml' '*.js' '*.json')" ]]; then
|
if [[ -n "$(git ls-files '*.yml' '*.yaml' '*.js' '*.json')" ]]; then
|
||||||
info "checking YAML/JavaScript/JSON code style"
|
info "checking YAML/JavaScript/JSON code style"
|
||||||
check_config .editorconfig
|
check_config .editorconfig
|
||||||
if check_install npm; then
|
if check_install npm; then
|
||||||
info "running \`npx -y prettier -l -w \$(git ls-files '*.yml' '*.yaml' '*.js' '*.json')\`"
|
info "running \`npx -y prettier -l -w \$(git ls-files '*.yml' '*.yaml' '*.js' '*.json')\`"
|
||||||
npx -y prettier -l -w $(git ls-files '*.yml' '*.yaml' '*.js' '*.json')
|
npx -y prettier -l -w $(git ls-files '*.yml' '*.yaml' '*.js' '*.json')
|
||||||
check_diff $(git ls-files '*.yml' '*.yaml' '*.js' '*.json')
|
check_diff $(git ls-files '*.yml' '*.yaml' '*.js' '*.json')
|
||||||
fi
|
fi
|
||||||
# Check GitHub workflows.
|
# Check GitHub workflows.
|
||||||
if [[ -d .github/workflows ]]; then
|
if [[ -d .github/workflows ]]; then
|
||||||
info "checking GitHub workflows"
|
info "checking GitHub workflows"
|
||||||
if check_install jq python3; then
|
if check_install jq python3; then
|
||||||
venv_install_yq
|
venv_install_yq
|
||||||
for workflow in .github/workflows/*.yml; do
|
for workflow in .github/workflows/*.yml; do
|
||||||
# The top-level permissions must be weak as they are referenced by all jobs.
|
# The top-level permissions must be weak as they are referenced by all jobs.
|
||||||
permissions=$(venv yq -c '.permissions' "${workflow}")
|
permissions=$(venv yq -c '.permissions' "${workflow}")
|
||||||
case "${permissions}" in
|
case "${permissions}" in
|
||||||
'{"contents":"read"}' | '{"contents":"none"}') ;;
|
'{"contents":"read"}' | '{"contents":"none"}') ;;
|
||||||
null) error "${workflow}: top level permissions not found; it must be 'contents: read' or weaker permissions" ;;
|
null) error "${workflow}: top level permissions not found; it must be 'contents: read' or weaker permissions" ;;
|
||||||
*) error "${workflow}: only 'contents: read' and weaker permissions are allowed at top level; if you want to use stronger permissions, please set job-level permissions" ;;
|
*) error "${workflow}: only 'contents: read' and weaker permissions are allowed at top level; if you want to use stronger permissions, please set job-level permissions" ;;
|
||||||
esac
|
esac
|
||||||
# Make sure the 'needs' section is not out of date.
|
# Make sure the 'needs' section is not out of date.
|
||||||
if grep -q '# tidy:needs' "${workflow}" && ! grep -Eq '# *needs: \[' "${workflow}"; then
|
if grep -q '# tidy:needs' "${workflow}" && ! grep -Eq '# *needs: \[' "${workflow}"; then
|
||||||
# shellcheck disable=SC2207
|
# shellcheck disable=SC2207
|
||||||
jobs_actual=($(venv yq '.jobs' "${workflow}" | jq -r 'keys_unsorted[]'))
|
jobs_actual=($(venv yq '.jobs' "${workflow}" | jq -r 'keys_unsorted[]'))
|
||||||
unset 'jobs_actual[${#jobs_actual[@]}-1]'
|
unset 'jobs_actual[${#jobs_actual[@]}-1]'
|
||||||
# shellcheck disable=SC2207
|
# shellcheck disable=SC2207
|
||||||
jobs_expected=($(venv yq -r '.jobs."ci-success".needs[]' "${workflow}"))
|
jobs_expected=($(venv yq -r '.jobs."ci-success".needs[]' "${workflow}"))
|
||||||
if [[ "${jobs_actual[*]}" != "${jobs_expected[*]+"${jobs_expected[*]}"}" ]]; then
|
if [[ "${jobs_actual[*]}" != "${jobs_expected[*]+"${jobs_expected[*]}"}" ]]; then
|
||||||
printf -v jobs '%s, ' "${jobs_actual[@]}"
|
printf -v jobs '%s, ' "${jobs_actual[@]}"
|
||||||
sed -i "s/needs: \[.*\] # tidy:needs/needs: [${jobs%, }] # tidy:needs/" "${workflow}"
|
sed -i "s/needs: \[.*\] # tidy:needs/needs: [${jobs%, }] # tidy:needs/" "${workflow}"
|
||||||
check_diff "${workflow}"
|
check_diff "${workflow}"
|
||||||
error "${workflow}: please update 'needs' section in 'ci-success' job"
|
error "${workflow}: please update 'needs' section in 'ci-success' job"
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ -n "$(git ls-files '*.yaml' | (grep -v .markdownlint-cli2.yaml || true))" ]]; then
|
if [[ -n "$(git ls-files '*.yaml' | (grep -v .markdownlint-cli2.yaml || true))" ]]; then
|
||||||
error "please use '.yml' instead of '.yaml' for consistency"
|
error "please use '.yml' instead of '.yaml' for consistency"
|
||||||
git ls-files '*.yaml' | (grep -v .markdownlint-cli2.yaml || true)
|
git ls-files '*.yaml' | (grep -v .markdownlint-cli2.yaml || true)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# TOML (if exists)
|
# TOML (if exists)
|
||||||
if [[ -n "$(git ls-files '*.toml' | (grep -v .taplo.toml || true))" ]]; then
|
if [[ -n "$(git ls-files '*.toml' | (grep -v .taplo.toml || true))" ]]; then
|
||||||
info "checking TOML style"
|
info "checking TOML style"
|
||||||
check_config .taplo.toml
|
check_config .taplo.toml
|
||||||
if check_install npm; then
|
if check_install npm; then
|
||||||
info "running \`npx -y @taplo/cli fmt \$(git ls-files '*.toml')\`"
|
info "running \`npx -y @taplo/cli fmt \$(git ls-files '*.toml')\`"
|
||||||
RUST_LOG=warn npx -y @taplo/cli fmt $(git ls-files '*.toml')
|
RUST_LOG=warn npx -y @taplo/cli fmt $(git ls-files '*.toml')
|
||||||
check_diff $(git ls-files '*.toml')
|
check_diff $(git ls-files '*.toml')
|
||||||
fi
|
fi
|
||||||
elif [[ -e .taplo.toml ]]; then
|
elif [[ -e .taplo.toml ]]; then
|
||||||
error ".taplo.toml is unused"
|
error ".taplo.toml is unused"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Markdown (if exists)
|
# Markdown (if exists)
|
||||||
if [[ -n "$(git ls-files '*.md')" ]]; then
|
if [[ -n "$(git ls-files '*.md')" ]]; then
|
||||||
info "checking Markdown style"
|
info "checking Markdown style"
|
||||||
check_config .markdownlint-cli2.yaml
|
check_config .markdownlint-cli2.yaml
|
||||||
if check_install npm; then
|
if check_install npm; then
|
||||||
info "running \`npx -y markdownlint-cli2 \$(git ls-files '*.md')\`"
|
info "running \`npx -y markdownlint-cli2 \$(git ls-files '*.md')\`"
|
||||||
npx -y markdownlint-cli2 $(git ls-files '*.md')
|
npx -y markdownlint-cli2 $(git ls-files '*.md')
|
||||||
fi
|
fi
|
||||||
elif [[ -e .markdownlint-cli2.yaml ]]; then
|
elif [[ -e .markdownlint-cli2.yaml ]]; then
|
||||||
error ".markdownlint-cli2.yaml is unused"
|
error ".markdownlint-cli2.yaml is unused"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$(git ls-files '*.markdown')" ]]; then
|
if [[ -n "$(git ls-files '*.markdown')" ]]; then
|
||||||
error "please use '.md' instead of '.markdown' for consistency"
|
error "please use '.md' instead of '.markdown' for consistency"
|
||||||
git ls-files '*.markdown'
|
git ls-files '*.markdown'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Shell scripts
|
# Shell scripts
|
||||||
info "checking Shell scripts"
|
info "checking Shell scripts"
|
||||||
if check_install shfmt; then
|
if check_install shfmt; then
|
||||||
check_config .editorconfig
|
check_config .editorconfig
|
||||||
info "running \`shfmt -l -w \$(git ls-files '*.sh')\`"
|
info "running \`shfmt -l -w \$(git ls-files '*.sh')\`"
|
||||||
shfmt -l -w $(git ls-files '*.sh')
|
shfmt -l -w $(git ls-files '*.sh')
|
||||||
check_diff $(git ls-files '*.sh')
|
check_diff $(git ls-files '*.sh')
|
||||||
fi
|
fi
|
||||||
if check_install shellcheck; then
|
if check_install shellcheck; then
|
||||||
check_config .shellcheckrc
|
check_config .shellcheckrc
|
||||||
info "running \`shellcheck \$(git ls-files '*.sh')\`"
|
info "running \`shellcheck \$(git ls-files '*.sh')\`"
|
||||||
if ! shellcheck $(git ls-files '*.sh'); then
|
if ! shellcheck $(git ls-files '*.sh'); then
|
||||||
should_fail=1
|
should_fail=1
|
||||||
fi
|
fi
|
||||||
if [[ -n "$(git ls-files '*Dockerfile')" ]]; then
|
if [[ -n "$(git ls-files '*Dockerfile')" ]]; then
|
||||||
# SC2154 doesn't seem to work on dockerfile.
|
# SC2154 doesn't seem to work on dockerfile.
|
||||||
info "running \`shellcheck -e SC2148,SC2154,SC2250 \$(git ls-files '*Dockerfile')\`"
|
info "running \`shellcheck -e SC2148,SC2154,SC2250 \$(git ls-files '*Dockerfile')\`"
|
||||||
if ! shellcheck -e SC2148,SC2154,SC2250 $(git ls-files '*Dockerfile'); then
|
if ! shellcheck -e SC2148,SC2154,SC2250 $(git ls-files '*Dockerfile'); then
|
||||||
should_fail=1
|
should_fail=1
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# License check
|
# License check
|
||||||
# TODO: This check is still experimental and does not track all files that should be tracked.
|
# TODO: This check is still experimental and does not track all files that should be tracked.
|
||||||
if [[ -f tools/.tidy-check-license-headers ]]; then
|
if [[ -f tools/.tidy-check-license-headers ]]; then
|
||||||
info "checking license headers (experimental)"
|
info "checking license headers (experimental)"
|
||||||
failed_files=''
|
failed_files=''
|
||||||
for p in $(eval $(<tools/.tidy-check-license-headers)); do
|
for p in $(eval $(<tools/.tidy-check-license-headers)); do
|
||||||
case "$(basename "${p}")" in
|
case "$(basename "${p}")" in
|
||||||
*.stderr | *.expanded.rs) continue ;; # generated files
|
*.stderr | *.expanded.rs) continue ;; # generated files
|
||||||
*.sh | *.py | *.rb | *Dockerfile) prefix=("# ") ;;
|
*.sh | *.py | *.rb | *Dockerfile) prefix=("# ") ;;
|
||||||
*.rs | *.c | *.h | *.cpp | *.hpp | *.s | *.S | *.js) prefix=("// " "/* ") ;;
|
*.rs | *.c | *.h | *.cpp | *.hpp | *.s | *.S | *.js) prefix=("// " "/* ") ;;
|
||||||
*.ld | *.x) prefix=("/* ") ;;
|
*.ld | *.x) prefix=("/* ") ;;
|
||||||
# TODO: More file types?
|
# TODO: More file types?
|
||||||
*) continue ;;
|
*) continue ;;
|
||||||
esac
|
esac
|
||||||
# TODO: The exact line number is not actually important; it is important
|
# TODO: The exact line number is not actually important; it is important
|
||||||
# that it be part of the top-level comments of the file.
|
# that it be part of the top-level comments of the file.
|
||||||
line="1"
|
line="1"
|
||||||
if IFS= LC_ALL=C read -rn3 -d '' shebang <"${p}" && [[ "${shebang}" == '#!/' ]]; then
|
if IFS= LC_ALL=C read -rn3 -d '' shebang <"${p}" && [[ "${shebang}" == '#!/' ]]; then
|
||||||
line="2"
|
line="2"
|
||||||
elif [[ "${p}" == *"Dockerfile" ]] && IFS= LC_ALL=C read -rn9 -d '' syntax <"${p}" && [[ "${syntax}" == '# syntax=' ]]; then
|
elif [[ "${p}" == *"Dockerfile" ]] && IFS= LC_ALL=C read -rn9 -d '' syntax <"${p}" && [[ "${syntax}" == '# syntax=' ]]; then
|
||||||
line="2"
|
line="2"
|
||||||
fi
|
|
||||||
header_found=''
|
|
||||||
for pre in "${prefix[@]}"; do
|
|
||||||
# TODO: check that the license is valid as SPDX and is allowed in this project.
|
|
||||||
if [[ "$(grep -E -n "${pre}SPDX-License-Identifier: " "${p}")" == "${line}:${pre}SPDX-License-Identifier: "* ]]; then
|
|
||||||
header_found='1'
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ -z "${header_found}" ]]; then
|
|
||||||
failed_files+="${p}:${line}"$'\n'
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ -n "${failed_files}" ]]; then
|
|
||||||
error "license-check failed: please add SPDX-License-Identifier to the following files"
|
|
||||||
echo "======================================="
|
|
||||||
echo -n "${failed_files}"
|
|
||||||
echo "======================================="
|
|
||||||
fi
|
fi
|
||||||
|
header_found=''
|
||||||
|
for pre in "${prefix[@]}"; do
|
||||||
|
# TODO: check that the license is valid as SPDX and is allowed in this project.
|
||||||
|
if [[ "$(grep -E -n "${pre}SPDX-License-Identifier: " "${p}")" == "${line}:${pre}SPDX-License-Identifier: "* ]]; then
|
||||||
|
header_found='1'
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -z "${header_found}" ]]; then
|
||||||
|
failed_files+="${p}:${line}"$'\n'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -n "${failed_files}" ]]; then
|
||||||
|
error "license-check failed: please add SPDX-License-Identifier to the following files"
|
||||||
|
echo "======================================="
|
||||||
|
echo -n "${failed_files}"
|
||||||
|
echo "======================================="
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Spell check (if config exists)
|
# Spell check (if config exists)
|
||||||
if [[ -f .cspell.json ]]; then
|
if [[ -f .cspell.json ]]; then
|
||||||
info "spell checking"
|
info "spell checking"
|
||||||
project_dictionary=.github/.cspell/project-dictionary.txt
|
project_dictionary=.github/.cspell/project-dictionary.txt
|
||||||
if check_install npm jq python3; then
|
if check_install npm jq python3; then
|
||||||
has_rust=''
|
has_rust=''
|
||||||
if [[ -n "$(git ls-files '*Cargo.toml')" ]]; then
|
if [[ -n "$(git ls-files '*Cargo.toml')" ]]; then
|
||||||
venv_install_yq
|
venv_install_yq
|
||||||
has_rust='1'
|
has_rust='1'
|
||||||
dependencies=''
|
dependencies=''
|
||||||
for manifest_path in $(git ls-files '*Cargo.toml'); do
|
for manifest_path in $(git ls-files '*Cargo.toml'); do
|
||||||
if [[ "${manifest_path}" != "Cargo.toml" ]] && [[ "$(venv tomlq -c '.workspace' "${manifest_path}")" == "null" ]]; then
|
if [[ "${manifest_path}" != "Cargo.toml" ]] && [[ "$(venv tomlq -c '.workspace' "${manifest_path}")" == "null" ]]; then
|
||||||
continue
|
continue
|
||||||
fi
|
|
||||||
metadata=$(cargo metadata --format-version=1 --no-deps --manifest-path "${manifest_path}")
|
|
||||||
for id in $(jq <<<"${metadata}" '.workspace_members[]'); do
|
|
||||||
dependencies+="$(jq <<<"${metadata}" ".packages[] | select(.id == ${id})" | jq -r '.dependencies[].name')"$'\n'
|
|
||||||
done
|
|
||||||
done
|
|
||||||
# shellcheck disable=SC2001
|
|
||||||
dependencies=$(sed <<<"${dependencies}" 's/[0-9_-]/\n/g' | LC_ALL=C sort -f -u)
|
|
||||||
fi
|
fi
|
||||||
config_old=$(<.cspell.json)
|
metadata=$(cargo metadata --format-version=1 --no-deps --manifest-path "${manifest_path}")
|
||||||
config_new=$(grep <<<"${config_old}" -v '^ *//' | jq 'del(.dictionaries[] | select(index("organization-dictionary") | not))' | jq 'del(.dictionaryDefinitions[] | select(.name == "organization-dictionary" | not))')
|
for id in $(jq <<<"${metadata}" '.workspace_members[]'); do
|
||||||
trap -- 'echo "${config_old}" >.cspell.json; echo >&2 "$0: trapped SIGINT"; exit 1' SIGINT
|
dependencies+="$(jq <<<"${metadata}" ".packages[] | select(.id == ${id})" | jq -r '.dependencies[].name')"$'\n'
|
||||||
echo "${config_new}" >.cspell.json
|
done
|
||||||
if [[ -n "${has_rust}" ]]; then
|
done
|
||||||
dependencies_words=$(npx <<<"${dependencies}" -y cspell stdin --no-progress --no-summary --words-only --unique || true)
|
# shellcheck disable=SC2001
|
||||||
fi
|
dependencies=$(sed <<<"${dependencies}" 's/[0-9_-]/\n/g' | LC_ALL=C sort -f -u)
|
||||||
all_words=$(npx -y cspell --no-progress --no-summary --words-only --unique $(git ls-files | (grep -v "${project_dictionary//\./\\.}" || true)) || true)
|
fi
|
||||||
echo "${config_old}" >.cspell.json
|
config_old=$(<.cspell.json)
|
||||||
trap - SIGINT
|
config_new=$(grep <<<"${config_old}" -v '^ *//' | jq 'del(.dictionaries[] | select(index("organization-dictionary") | not))' | jq 'del(.dictionaryDefinitions[] | select(.name == "organization-dictionary" | not))')
|
||||||
cat >.github/.cspell/rust-dependencies.txt <<EOF
|
trap -- 'echo "${config_old}" >.cspell.json; echo >&2 "$0: trapped SIGINT"; exit 1' SIGINT
|
||||||
|
echo "${config_new}" >.cspell.json
|
||||||
|
if [[ -n "${has_rust}" ]]; then
|
||||||
|
dependencies_words=$(npx <<<"${dependencies}" -y cspell stdin --no-progress --no-summary --words-only --unique || true)
|
||||||
|
fi
|
||||||
|
all_words=$(npx -y cspell --no-progress --no-summary --words-only --unique $(git ls-files | (grep -v "${project_dictionary//\./\\.}" || true)) || true)
|
||||||
|
echo "${config_old}" >.cspell.json
|
||||||
|
trap - SIGINT
|
||||||
|
cat >.github/.cspell/rust-dependencies.txt <<EOF
|
||||||
// This file is @generated by $(basename "$0").
|
// This file is @generated by $(basename "$0").
|
||||||
// It is not intended for manual editing.
|
// It is not intended for manual editing.
|
||||||
EOF
|
EOF
|
||||||
if [[ -n "${dependencies_words:-}" ]]; then
|
if [[ -n "${dependencies_words:-}" ]]; then
|
||||||
echo $'\n'"${dependencies_words}" >>.github/.cspell/rust-dependencies.txt
|
echo $'\n'"${dependencies_words}" >>.github/.cspell/rust-dependencies.txt
|
||||||
fi
|
|
||||||
if [[ -z "${REMOVE_UNUSED_WORDS:-}" ]]; then
|
|
||||||
check_diff .github/.cspell/rust-dependencies.txt
|
|
||||||
fi
|
|
||||||
if ! grep -Fq '.github/.cspell/rust-dependencies.txt linguist-generated' .gitattributes; then
|
|
||||||
error "you may want to mark .github/.cspell/rust-dependencies.txt linguist-generated"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "running \`npx -y cspell --no-progress --no-summary \$(git ls-files)\`"
|
|
||||||
if ! npx -y cspell --no-progress --no-summary $(git ls-files); then
|
|
||||||
error "spellcheck failed: please fix uses of above words or add to ${project_dictionary} if correct"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure the project-specific dictionary does not contain duplicated words.
|
|
||||||
for dictionary in .github/.cspell/*.txt; do
|
|
||||||
if [[ "${dictionary}" == "${project_dictionary}" ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
dup=$(sed '/^$/d' "${project_dictionary}" "${dictionary}" | LC_ALL=C sort -f | uniq -d -i | (grep -v '//.*' || true))
|
|
||||||
if [[ -n "${dup}" ]]; then
|
|
||||||
error "duplicated words in dictionaries; please remove the following words from ${project_dictionary}"
|
|
||||||
echo "======================================="
|
|
||||||
echo "${dup}"
|
|
||||||
echo "======================================="
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Make sure the project-specific dictionary does not contain unused words.
|
|
||||||
if [[ -n "${REMOVE_UNUSED_WORDS:-}" ]]; then
|
|
||||||
grep_args=()
|
|
||||||
for word in $(grep -Ev '^//.*' "${project_dictionary}" || true); do
|
|
||||||
if ! grep -Eqi "^${word}$" <<<"${all_words}"; then
|
|
||||||
grep_args+=(-e "^${word}$")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ ${#grep_args[@]} -gt 0 ]]; then
|
|
||||||
info "removing unused words from ${project_dictionary}"
|
|
||||||
res=$(grep -Ev "${grep_args[@]}" "${project_dictionary}")
|
|
||||||
printf '%s\n' "${res}" >|"${project_dictionary}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
unused=''
|
|
||||||
for word in $(grep -Ev '^//.*' "${project_dictionary}" || true); do
|
|
||||||
if ! grep -Eqi "^${word}$" <<<"${all_words}"; then
|
|
||||||
unused+="${word}"$'\n'
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ -n "${unused}" ]]; then
|
|
||||||
error "unused words in dictionaries; please remove the following words from ${project_dictionary} or run ${0##*/} with REMOVE_UNUSED_WORDS=1"
|
|
||||||
printf '=======================================\n'
|
|
||||||
printf '%s' "${unused}"
|
|
||||||
printf '=======================================\n'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
if [[ -z "${REMOVE_UNUSED_WORDS:-}" ]]; then
|
||||||
|
check_diff .github/.cspell/rust-dependencies.txt
|
||||||
|
fi
|
||||||
|
if ! grep -Fq '.github/.cspell/rust-dependencies.txt linguist-generated' .gitattributes; then
|
||||||
|
error "you may want to mark .github/.cspell/rust-dependencies.txt linguist-generated"
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "running \`npx -y cspell --no-progress --no-summary \$(git ls-files)\`"
|
||||||
|
if ! npx -y cspell --no-progress --no-summary $(git ls-files); then
|
||||||
|
error "spellcheck failed: please fix uses of above words or add to ${project_dictionary} if correct"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure the project-specific dictionary does not contain duplicated words.
|
||||||
|
for dictionary in .github/.cspell/*.txt; do
|
||||||
|
if [[ "${dictionary}" == "${project_dictionary}" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
dup=$(sed '/^$/d' "${project_dictionary}" "${dictionary}" | LC_ALL=C sort -f | uniq -d -i | (grep -v '//.*' || true))
|
||||||
|
if [[ -n "${dup}" ]]; then
|
||||||
|
error "duplicated words in dictionaries; please remove the following words from ${project_dictionary}"
|
||||||
|
echo "======================================="
|
||||||
|
echo "${dup}"
|
||||||
|
echo "======================================="
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Make sure the project-specific dictionary does not contain unused words.
|
||||||
|
if [[ -n "${REMOVE_UNUSED_WORDS:-}" ]]; then
|
||||||
|
grep_args=()
|
||||||
|
for word in $(grep -Ev '^//.*' "${project_dictionary}" || true); do
|
||||||
|
if ! grep -Eqi "^${word}$" <<<"${all_words}"; then
|
||||||
|
grep_args+=(-e "^${word}$")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ ${#grep_args[@]} -gt 0 ]]; then
|
||||||
|
info "removing unused words from ${project_dictionary}"
|
||||||
|
res=$(grep -Ev "${grep_args[@]}" "${project_dictionary}")
|
||||||
|
printf '%s\n' "${res}" >|"${project_dictionary}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
unused=''
|
||||||
|
for word in $(grep -Ev '^//.*' "${project_dictionary}" || true); do
|
||||||
|
if ! grep -Eqi "^${word}$" <<<"${all_words}"; then
|
||||||
|
unused+="${word}"$'\n'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -n "${unused}" ]]; then
|
||||||
|
error "unused words in dictionaries; please remove the following words from ${project_dictionary} or run ${0##*/} with REMOVE_UNUSED_WORDS=1"
|
||||||
|
printf '=======================================\n'
|
||||||
|
printf '%s' "${unused}"
|
||||||
|
printf '=======================================\n'
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${should_fail:-}" ]]; then
|
if [[ -n "${should_fail:-}" ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user