diff --git a/.github/actions/broken-symlinks-check/action.yml b/.github/actions/broken-symlinks-check/action.yml deleted file mode 100644 index 988226b1..00000000 --- a/.github/actions/broken-symlinks-check/action.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: broken-symlink-check -description: Check for broken symbolic links -runs: - using: composite - steps: - - name: Run broken symlink check - shell: bash - run: $GITHUB_ACTION_PATH/check-broken-symlinks.sh diff --git a/.github/actions/broken-symlinks-check/check-broken-symlinks.sh b/.github/actions/broken-symlinks-check/check-broken-symlinks.sh deleted file mode 100755 index 570cbdb7..00000000 --- a/.github/actions/broken-symlinks-check/check-broken-symlinks.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift.org open source project -## -## Copyright (c) 2024 Apple Inc. and the Swift project authors -## Licensed under Apache License v2.0 with Runtime Library Exception -## -## See https://swift.org/LICENSE.txt for license information -## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -## -##===----------------------------------------------------------------------===## - -set -euo pipefail - -log() { printf -- "** %s\n" "$*" >&2; } -error() { printf -- "** ERROR: %s\n" "$*" >&2; } -fatal() { error "$@"; exit 1; } - -log "Checking for broken symlinks..." -num_broken_symlinks=0 -while read -r -d '' file; do - if ! test -e "./${file}"; then - error "Broken symlink: ${file}" - ((num_broken_symlinks++)) - fi -done < <(git ls-files -z) - -if [ "${num_broken_symlinks}" -gt 0 ]; then - fatal "❌ Found ${num_broken_symlinks} symlinks." -fi - -log "✅ Found 0 symlinks." diff --git a/.github/actions/check-unacceptable-language/action.yml b/.github/actions/check-unacceptable-language/action.yml deleted file mode 100644 index dbefa77d..00000000 --- a/.github/actions/check-unacceptable-language/action.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: check-unacceptable-language -description: Check Language Format -runs: - using: composite - steps: - - name: Run unacceptable language check - shell: bash - run: $GITHUB_ACTION_PATH/check-unacceptable-language.sh diff --git a/.github/actions/check-unacceptable-language/check-unacceptable-language.sh b/.github/actions/check-unacceptable-language/check-unacceptable-language.sh deleted file mode 100755 index 2a694650..00000000 --- a/.github/actions/check-unacceptable-language/check-unacceptable-language.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift.org open source project -## -## Copyright (c) 2024 Apple Inc. and the Swift project authors -## Licensed under Apache License v2.0 with Runtime Library Exception -## -## See https://swift.org/LICENSE.txt for license information -## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -## -##===----------------------------------------------------------------------===## - -set -euo pipefail - -log() { printf -- "** %s\n" "$*" >&2; } -error() { printf -- "** ERROR: %s\n" "$*" >&2; } -fatal() { error "$@"; exit 1; } - -test -n "${UNACCEPTABLE_WORD_LIST:-}" || fatal "UNACCEPTABLE_WORD_LIST unset" - -unacceptable_language_lines= -if [[ -f .unacceptablelanguageignore ]]; then - log "Found unacceptable language ignore file..." - log "Checking for unacceptable language..." - unacceptable_language_lines=$(tr '\n' '\0' < .unacceptablelanguageignore | xargs -0 -I% printf '":(exclude)%" '| xargs git grep -i -I -w -H -n --column -E "${UNACCEPTABLE_WORD_LIST// /|}" -- ':!*.unacceptablelanguageignore' | grep -v "ignore-unacceptable-language") || true | /usr/bin/paste -s -d " " - -else - log "Checking for unacceptable language..." - unacceptable_language_lines=$(git grep -i -I -w -H -n --column -E "${UNACCEPTABLE_WORD_LIST// /|}" | grep -v "ignore-unacceptable-language") || true | /usr/bin/paste -s -d " " - -fi - -if [ -n "${unacceptable_language_lines}" ]; then - fatal " ❌ Found unacceptable language: -${unacceptable_language_lines} -" -fi - - -log "✅ Found no unacceptable language." diff --git a/.github/actions/docs-check/action.yml b/.github/actions/docs-check/action.yml deleted file mode 100644 index 118e1f93..00000000 --- a/.github/actions/docs-check/action.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: docs-check -description: Check Docs -runs: - using: composite - steps: - - name: Run docs check - shell: bash - run: $GITHUB_ACTION_PATH/check-docs.sh diff --git a/.github/actions/docs-check/check-docs.sh b/.github/actions/docs-check/check-docs.sh deleted file mode 100755 index d0becf00..00000000 --- a/.github/actions/docs-check/check-docs.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift.org open source project -## -## Copyright (c) 2025 Apple Inc. and the Swift project authors -## Licensed under Apache License v2.0 with Runtime Library Exception -## -## See https://swift.org/LICENSE.txt for license information -## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -## -##===----------------------------------------------------------------------===## - -set -euo pipefail - -log() { printf -- "** %s\n" "$*" >&2; } -error() { printf -- "** ERROR: %s\n" "$*" >&2; } -fatal() { error "$@"; exit 1; } - -if [ ! -f .spi.yml ]; then - log "No '.spi.yml' found, no documentation targets to check." - exit 0 -fi - -if ! command -v yq &> /dev/null; then - case "$(uname -s)" in - Darwin*) brew install yq;; - Linux*) apt -q update && apt -yq install yq;; - esac -fi - -package_files=$(find . -maxdepth 1 -name 'Package*.swift') -if [ -z "$package_files" ]; then - fatal "Package.swift not found. Please ensure you are running this script from the root of a Swift package." -fi - -# yq 3.1.0-3 doesn't have filter, otherwise we could replace the grep call with "filter(.identity == "swift-docc-plugin") | keys | .[]" -hasDoccPlugin=$(swift package dump-package | yq -r '.dependencies[].sourceControl' | grep -e "\"identity\": \"swift-docc-plugin\"" || true) -if [[ -n $hasDoccPlugin ]] -then - log "swift-docc-plugin already exists" -else - log "Appending swift-docc-plugin" - for package_file in $package_files; do - log "Editing $package_file..." - cat <> "$package_file" - -package.dependencies.append( - .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.0.0") -) -EOF - done -fi - -log "Checking documentation targets..." -for target in $(yq -r '.builder.configs[].documentation_targets[]' .spi.yml); do - log "Checking target $target..." - # shellcheck disable=SC2086 # We explicitly want to explode "$ADDITIONAL_DOCC_ARGUMENTS" into multiple arguments. - swift package plugin generate-documentation --target "$target" --warnings-as-errors --analyze $ADDITIONAL_DOCC_ARGUMENTS -done - -log "✅ Found no documentation issues." diff --git a/.github/actions/format-check/action.yml b/.github/actions/format-check/action.yml deleted file mode 100644 index 0d7fc86f..00000000 --- a/.github/actions/format-check/action.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: format-check -description: Check Swift Format -runs: - using: composite - steps: - - name: Run format check - shell: bash - run: $GITHUB_ACTION_PATH/check-swift-format.sh diff --git a/.github/actions/format-check/check-swift-format.sh b/.github/actions/format-check/check-swift-format.sh deleted file mode 100755 index fb6d351b..00000000 --- a/.github/actions/format-check/check-swift-format.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift.org open source project -## -## Copyright (c) 2024 Apple Inc. and the Swift project authors -## Licensed under Apache License v2.0 with Runtime Library Exception -## -## See https://swift.org/LICENSE.txt for license information -## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -## -##===----------------------------------------------------------------------===## - -set -euo pipefail - -log() { printf -- "** %s\n" "$*" >&2; } -error() { printf -- "** ERROR: %s\n" "$*" >&2; } -fatal() { error "$@"; exit 1; } - - -if [[ -f .swiftformatignore ]]; then - log "Found swiftformatignore file..." - - log "Running swift-format format..." - tr '\n' '\0' < .swiftformatignore| xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files -z '*.swift' | xargs -0 swift-format format --parallel --in-place - - log "Running swift-format lint..." - - tr '\n' '\0' < .swiftformatignore | xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files -z '*.swift' | xargs -0 swift-format lint --strict --parallel -else - log "Running swift-format format..." - git ls-files -z '*.swift' | xargs -0 swift-format format --parallel --in-place - - log "Running swift-format lint..." - - git ls-files -z '*.swift' | xargs -0 swift-format lint --strict --parallel -fi - - - -log "Checking for modified files..." - -GIT_PAGER='' git diff --exit-code '*.swift' - -log "✅ Found no formatting issues." diff --git a/.github/actions/license-header-check/action.yml b/.github/actions/license-header-check/action.yml deleted file mode 100644 index c78892b3..00000000 --- a/.github/actions/license-header-check/action.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: license-header-check -description: Check License Headers -runs: - using: composite - steps: - - name: Run license header check - shell: bash - run: $GITHUB_ACTION_PATH/check-license-header.sh diff --git a/.github/actions/license-header-check/check-license-header.sh b/.github/actions/license-header-check/check-license-header.sh deleted file mode 100755 index 2677b084..00000000 --- a/.github/actions/license-header-check/check-license-header.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift.org open source project -## -## Copyright (c) 2024 Apple Inc. and the Swift project authors -## Licensed under Apache License v2.0 with Runtime Library Exception -## -## See https://swift.org/LICENSE.txt for license information -## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -## -##===----------------------------------------------------------------------===## - -set -euo pipefail - -log() { printf -- "** %s\n" "$*" >&2; } -error() { printf -- "** ERROR: %s\n" "$*" >&2; } -fatal() { error "$@"; exit 1; } - -if [ -f .license_header_template ]; then - # allow projects to override the license header template - expected_file_header_template=$(cat .license_header_template) -else - test -n "${PROJECT_NAME:-}" || fatal "PROJECT_NAME unset" - expected_file_header_template="@@===----------------------------------------------------------------------===@@ -@@ -@@ This source file is part of the ${PROJECT_NAME} open source project -@@ -@@ Copyright (c) YEARS Apple Inc. and the ${PROJECT_NAME} project authors -@@ Licensed under Apache License v2.0 -@@ -@@ See LICENSE.txt for license information -@@ See CONTRIBUTORS.txt for the list of ${PROJECT_NAME} project authors -@@ -@@ SPDX-License-Identifier: Apache-2.0 -@@ -@@===----------------------------------------------------------------------===@@" -fi - -paths_with_missing_license=( ) - -if [[ -f .licenseignore ]]; then - static_exclude_list='":(exclude).licenseignore" ":(exclude).license_header_template" ' - dynamic_exclude_list=$(tr '\n' '\0' < .licenseignore | xargs -0 -I% printf '":(exclude)%" ') - exclude_list=$static_exclude_list$dynamic_exclude_list -else - exclude_list=":(exclude).license_header_template" -fi - -file_paths=$(echo "$exclude_list" | xargs git ls-files) - -while IFS= read -r file_path; do - file_basename=$(basename -- "${file_path}") - file_extension="${file_basename##*.}" - if [[ -L "${file_path}" ]]; then - continue # Ignore symbolic links - fi - - # The characters that are used to start a line comment and that replace '@@' in the license header template - comment_marker='' - # A line that we expect before the license header. This should end with a newline if it is not empty - header_prefix='' - # shellcheck disable=SC2001 # We prefer to use sed here instead of bash search/replace - case "${file_extension}" in - bazel) comment_marker='##' ;; - bazelrc) comment_marker='##' ;; - bzl) comment_marker='##' ;; - c) comment_marker='//' ;; - cpp) comment_marker='//' ;; - cmake) comment_marker='##' ;; - code-workspace) continue ;; # VS Code workspaces are JSON and shouldn't contain comments - CODEOWNERS) continue ;; # Doesn't need a license header - Dockerfile) comment_marker='##' ;; - editorconfig) comment_marker='##' ;; - flake8) continue ;; # Configuration file doesn't need a license header - gitattributes) continue ;; # Configuration files don't need license headers - gitignore) continue ;; # Configuration files don't need license headers - gradle) comment_marker='//' ;; - groovy) comment_marker='//' ;; - gyb) comment_marker='//' ;; - h) comment_marker='//' ;; - in) comment_marker='##' ;; - java) comment_marker='//' ;; - js) comment_marker='//' ;; - json) continue ;; # JSON doesn't support line comments - jsx) comment_marker='//' ;; - kts) comment_marker='//' ;; - kt) comment_marker='//' ;; - md) continue ;; # Text files don't need license headers - mobileconfig) continue ;; # Doesn't support comments - modulemap) continue ;; # Configuration file doesn't need a license header - plist) continue ;; # Plists don't support line comments - proto) comment_marker='//' ;; - ps1) comment_marker='##' ;; - psm1) comment_marker='##' ;; - py) comment_marker='##'; header_prefix=$'#!/usr/bin/env python3\n' ;; - rb) comment_marker='##'; header_prefix=$'#!/usr/bin/env ruby\n' ;; - sh) comment_marker='##'; header_prefix=$'#!/bin/bash\n' ;; - strings) comment_marker='//' ;; - swift-format) continue ;; # .swift-format is JSON and doesn't support comments - swift) comment_marker='//' ;; - toml) comment_marker='##' ;; - ts) comment_marker='//' ;; - tsx) comment_marker='//' ;; - txt) continue ;; # Text files don't need license headers - yml) continue ;; # YAML Configuration files don't need license headers - yaml) continue ;; # YAML Configuration files don't need license headers - xcbuildrules) comment_marker='//' ;; - xcspec) comment_marker='//' ;; - *) - error "Unsupported file extension ${file_extension} for file (exclude or update this script): ${file_path}" - paths_with_missing_license+=("${file_path} ") - continue - ;; - esac - expected_file_header=$(echo "${header_prefix}${expected_file_header_template}" | sed -e "s|@@|$comment_marker|g") - expected_file_header_linecount=$(echo "${expected_file_header}" | wc -l) - - file_header=$(head -n "${expected_file_header_linecount}" "${file_path}") - normalized_file_header=$( - echo "${file_header}" \ - | sed -E -e 's/20[12][0123456789] ?[-–] ?20[12][0123456789]/YEARS/' -e 's/20[12][0123456789]/YEARS/' \ - ) - - if ! diff -u \ - --label "Expected header" <(echo "${expected_file_header}") \ - --label "${file_path}" <(echo "${normalized_file_header}") - then - paths_with_missing_license+=("${file_path} ") - fi -done <<< "$file_paths" - -if [ "${#paths_with_missing_license[@]}" -gt 0 ]; then - fatal "❌ Found missing license header in files: ${paths_with_missing_license[*]}." -fi - -log "✅ Found no files with missing license header." diff --git a/.github/actions/python-lint-check/.flake8 b/.github/actions/python-lint-check/.flake8 deleted file mode 100644 index c7b743c5..00000000 --- a/.github/actions/python-lint-check/.flake8 +++ /dev/null @@ -1,10 +0,0 @@ -[flake8] - -ignore = - # These are needed to make our license headers pass the linting - E265, - E266, - -# 10% larger than the standard 80 character limit. Conforms to the black -# standard and Bugbear's B950. -max-line-length = 88 diff --git a/.github/actions/python-lint-check/action.yml b/.github/actions/python-lint-check/action.yml deleted file mode 100644 index ac010f43..00000000 --- a/.github/actions/python-lint-check/action.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: python-lint-check -description: Check python files -runs: - using: composite - steps: - - name: Install flake - shell: bash - run: pip3 install flake8 flake8-import-order - - name: Copy flake8 config - shell: bash - run: cp $GITHUB_ACTION_PATH/.flake8 .flake8 - - name: Run flake8 - shell: bash - run: flake8 diff --git a/.github/actions/yamllint-check/action.yml b/.github/actions/yamllint-check/action.yml deleted file mode 100644 index 6a956d45..00000000 --- a/.github/actions/yamllint-check/action.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: yamllint-check -description: Check yaml files -runs: - using: composite - steps: - - name: Install yamllint - shell: bash - run: which yamllint || (apt -q update && apt install -yq yamllint) - - name: Run yaml lint - shell: bash - run: yamllint --strict --config-file $GITHUB_ACTION_PATH/yamllint.yml . diff --git a/.github/actions/yamllint-check/yamllint.yml b/.github/actions/yamllint-check/yamllint.yml deleted file mode 100644 index 52a1770f..00000000 --- a/.github/actions/yamllint-check/yamllint.yml +++ /dev/null @@ -1,7 +0,0 @@ -extends: default - -rules: - line-length: false - document-start: false - truthy: - check-keys: false # Otherwise we get a false positive on GitHub action's `on` key diff --git a/.github/workflows/configs/.flake8 b/.github/workflows/configs/.flake8 deleted file mode 120000 index 1fa4dde4..00000000 --- a/.github/workflows/configs/.flake8 +++ /dev/null @@ -1 +0,0 @@ -../../actions/python-lint-check/.flake8 \ No newline at end of file diff --git a/.github/workflows/configs/.flake8 b/.github/workflows/configs/.flake8 new file mode 100644 index 00000000..c7b743c5 --- /dev/null +++ b/.github/workflows/configs/.flake8 @@ -0,0 +1,10 @@ +[flake8] + +ignore = + # These are needed to make our license headers pass the linting + E265, + E266, + +# 10% larger than the standard 80 character limit. Conforms to the black +# standard and Bugbear's B950. +max-line-length = 88 diff --git a/.github/workflows/configs/yamllint.yml b/.github/workflows/configs/yamllint.yml deleted file mode 120000 index f193167d..00000000 --- a/.github/workflows/configs/yamllint.yml +++ /dev/null @@ -1 +0,0 @@ -../../actions/yamllint-check/yamllint.yml \ No newline at end of file diff --git a/.github/workflows/configs/yamllint.yml b/.github/workflows/configs/yamllint.yml new file mode 100644 index 00000000..52a1770f --- /dev/null +++ b/.github/workflows/configs/yamllint.yml @@ -0,0 +1,7 @@ +extends: default + +rules: + line-length: false + document-start: false + truthy: + check-keys: false # Otherwise we get a false positive on GitHub action's `on` key diff --git a/.github/workflows/scripts/check-broken-symlinks.sh b/.github/workflows/scripts/check-broken-symlinks.sh deleted file mode 120000 index 2f30ee85..00000000 --- a/.github/workflows/scripts/check-broken-symlinks.sh +++ /dev/null @@ -1 +0,0 @@ -../../actions/broken-symlinks-check/check-broken-symlinks.sh \ No newline at end of file diff --git a/.github/workflows/scripts/check-broken-symlinks.sh b/.github/workflows/scripts/check-broken-symlinks.sh new file mode 100755 index 00000000..570cbdb7 --- /dev/null +++ b/.github/workflows/scripts/check-broken-symlinks.sh @@ -0,0 +1,33 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +log "Checking for broken symlinks..." +num_broken_symlinks=0 +while read -r -d '' file; do + if ! test -e "./${file}"; then + error "Broken symlink: ${file}" + ((num_broken_symlinks++)) + fi +done < <(git ls-files -z) + +if [ "${num_broken_symlinks}" -gt 0 ]; then + fatal "❌ Found ${num_broken_symlinks} symlinks." +fi + +log "✅ Found 0 symlinks." diff --git a/.github/workflows/scripts/check-docs.sh b/.github/workflows/scripts/check-docs.sh deleted file mode 120000 index 57f98b5a..00000000 --- a/.github/workflows/scripts/check-docs.sh +++ /dev/null @@ -1 +0,0 @@ -../../actions/docs-check/check-docs.sh \ No newline at end of file diff --git a/.github/workflows/scripts/check-docs.sh b/.github/workflows/scripts/check-docs.sh new file mode 100755 index 00000000..d0becf00 --- /dev/null +++ b/.github/workflows/scripts/check-docs.sh @@ -0,0 +1,62 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2025 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +if [ ! -f .spi.yml ]; then + log "No '.spi.yml' found, no documentation targets to check." + exit 0 +fi + +if ! command -v yq &> /dev/null; then + case "$(uname -s)" in + Darwin*) brew install yq;; + Linux*) apt -q update && apt -yq install yq;; + esac +fi + +package_files=$(find . -maxdepth 1 -name 'Package*.swift') +if [ -z "$package_files" ]; then + fatal "Package.swift not found. Please ensure you are running this script from the root of a Swift package." +fi + +# yq 3.1.0-3 doesn't have filter, otherwise we could replace the grep call with "filter(.identity == "swift-docc-plugin") | keys | .[]" +hasDoccPlugin=$(swift package dump-package | yq -r '.dependencies[].sourceControl' | grep -e "\"identity\": \"swift-docc-plugin\"" || true) +if [[ -n $hasDoccPlugin ]] +then + log "swift-docc-plugin already exists" +else + log "Appending swift-docc-plugin" + for package_file in $package_files; do + log "Editing $package_file..." + cat <> "$package_file" + +package.dependencies.append( + .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.0.0") +) +EOF + done +fi + +log "Checking documentation targets..." +for target in $(yq -r '.builder.configs[].documentation_targets[]' .spi.yml); do + log "Checking target $target..." + # shellcheck disable=SC2086 # We explicitly want to explode "$ADDITIONAL_DOCC_ARGUMENTS" into multiple arguments. + swift package plugin generate-documentation --target "$target" --warnings-as-errors --analyze $ADDITIONAL_DOCC_ARGUMENTS +done + +log "✅ Found no documentation issues." diff --git a/.github/workflows/scripts/check-license-header.sh b/.github/workflows/scripts/check-license-header.sh deleted file mode 120000 index f23cfb07..00000000 --- a/.github/workflows/scripts/check-license-header.sh +++ /dev/null @@ -1 +0,0 @@ -../../actions/license-header-check/check-license-header.sh \ No newline at end of file diff --git a/.github/workflows/scripts/check-license-header.sh b/.github/workflows/scripts/check-license-header.sh new file mode 100755 index 00000000..2677b084 --- /dev/null +++ b/.github/workflows/scripts/check-license-header.sh @@ -0,0 +1,137 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +if [ -f .license_header_template ]; then + # allow projects to override the license header template + expected_file_header_template=$(cat .license_header_template) +else + test -n "${PROJECT_NAME:-}" || fatal "PROJECT_NAME unset" + expected_file_header_template="@@===----------------------------------------------------------------------===@@ +@@ +@@ This source file is part of the ${PROJECT_NAME} open source project +@@ +@@ Copyright (c) YEARS Apple Inc. and the ${PROJECT_NAME} project authors +@@ Licensed under Apache License v2.0 +@@ +@@ See LICENSE.txt for license information +@@ See CONTRIBUTORS.txt for the list of ${PROJECT_NAME} project authors +@@ +@@ SPDX-License-Identifier: Apache-2.0 +@@ +@@===----------------------------------------------------------------------===@@" +fi + +paths_with_missing_license=( ) + +if [[ -f .licenseignore ]]; then + static_exclude_list='":(exclude).licenseignore" ":(exclude).license_header_template" ' + dynamic_exclude_list=$(tr '\n' '\0' < .licenseignore | xargs -0 -I% printf '":(exclude)%" ') + exclude_list=$static_exclude_list$dynamic_exclude_list +else + exclude_list=":(exclude).license_header_template" +fi + +file_paths=$(echo "$exclude_list" | xargs git ls-files) + +while IFS= read -r file_path; do + file_basename=$(basename -- "${file_path}") + file_extension="${file_basename##*.}" + if [[ -L "${file_path}" ]]; then + continue # Ignore symbolic links + fi + + # The characters that are used to start a line comment and that replace '@@' in the license header template + comment_marker='' + # A line that we expect before the license header. This should end with a newline if it is not empty + header_prefix='' + # shellcheck disable=SC2001 # We prefer to use sed here instead of bash search/replace + case "${file_extension}" in + bazel) comment_marker='##' ;; + bazelrc) comment_marker='##' ;; + bzl) comment_marker='##' ;; + c) comment_marker='//' ;; + cpp) comment_marker='//' ;; + cmake) comment_marker='##' ;; + code-workspace) continue ;; # VS Code workspaces are JSON and shouldn't contain comments + CODEOWNERS) continue ;; # Doesn't need a license header + Dockerfile) comment_marker='##' ;; + editorconfig) comment_marker='##' ;; + flake8) continue ;; # Configuration file doesn't need a license header + gitattributes) continue ;; # Configuration files don't need license headers + gitignore) continue ;; # Configuration files don't need license headers + gradle) comment_marker='//' ;; + groovy) comment_marker='//' ;; + gyb) comment_marker='//' ;; + h) comment_marker='//' ;; + in) comment_marker='##' ;; + java) comment_marker='//' ;; + js) comment_marker='//' ;; + json) continue ;; # JSON doesn't support line comments + jsx) comment_marker='//' ;; + kts) comment_marker='//' ;; + kt) comment_marker='//' ;; + md) continue ;; # Text files don't need license headers + mobileconfig) continue ;; # Doesn't support comments + modulemap) continue ;; # Configuration file doesn't need a license header + plist) continue ;; # Plists don't support line comments + proto) comment_marker='//' ;; + ps1) comment_marker='##' ;; + psm1) comment_marker='##' ;; + py) comment_marker='##'; header_prefix=$'#!/usr/bin/env python3\n' ;; + rb) comment_marker='##'; header_prefix=$'#!/usr/bin/env ruby\n' ;; + sh) comment_marker='##'; header_prefix=$'#!/bin/bash\n' ;; + strings) comment_marker='//' ;; + swift-format) continue ;; # .swift-format is JSON and doesn't support comments + swift) comment_marker='//' ;; + toml) comment_marker='##' ;; + ts) comment_marker='//' ;; + tsx) comment_marker='//' ;; + txt) continue ;; # Text files don't need license headers + yml) continue ;; # YAML Configuration files don't need license headers + yaml) continue ;; # YAML Configuration files don't need license headers + xcbuildrules) comment_marker='//' ;; + xcspec) comment_marker='//' ;; + *) + error "Unsupported file extension ${file_extension} for file (exclude or update this script): ${file_path}" + paths_with_missing_license+=("${file_path} ") + continue + ;; + esac + expected_file_header=$(echo "${header_prefix}${expected_file_header_template}" | sed -e "s|@@|$comment_marker|g") + expected_file_header_linecount=$(echo "${expected_file_header}" | wc -l) + + file_header=$(head -n "${expected_file_header_linecount}" "${file_path}") + normalized_file_header=$( + echo "${file_header}" \ + | sed -E -e 's/20[12][0123456789] ?[-–] ?20[12][0123456789]/YEARS/' -e 's/20[12][0123456789]/YEARS/' \ + ) + + if ! diff -u \ + --label "Expected header" <(echo "${expected_file_header}") \ + --label "${file_path}" <(echo "${normalized_file_header}") + then + paths_with_missing_license+=("${file_path} ") + fi +done <<< "$file_paths" + +if [ "${#paths_with_missing_license[@]}" -gt 0 ]; then + fatal "❌ Found missing license header in files: ${paths_with_missing_license[*]}." +fi + +log "✅ Found no files with missing license header." diff --git a/.github/workflows/scripts/check-swift-format.sh b/.github/workflows/scripts/check-swift-format.sh deleted file mode 120000 index d801f2a2..00000000 --- a/.github/workflows/scripts/check-swift-format.sh +++ /dev/null @@ -1 +0,0 @@ -../../actions/format-check/check-swift-format.sh \ No newline at end of file diff --git a/.github/workflows/scripts/check-swift-format.sh b/.github/workflows/scripts/check-swift-format.sh new file mode 100755 index 00000000..fb6d351b --- /dev/null +++ b/.github/workflows/scripts/check-swift-format.sh @@ -0,0 +1,45 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + + +if [[ -f .swiftformatignore ]]; then + log "Found swiftformatignore file..." + + log "Running swift-format format..." + tr '\n' '\0' < .swiftformatignore| xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files -z '*.swift' | xargs -0 swift-format format --parallel --in-place + + log "Running swift-format lint..." + + tr '\n' '\0' < .swiftformatignore | xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files -z '*.swift' | xargs -0 swift-format lint --strict --parallel +else + log "Running swift-format format..." + git ls-files -z '*.swift' | xargs -0 swift-format format --parallel --in-place + + log "Running swift-format lint..." + + git ls-files -z '*.swift' | xargs -0 swift-format lint --strict --parallel +fi + + + +log "Checking for modified files..." + +GIT_PAGER='' git diff --exit-code '*.swift' + +log "✅ Found no formatting issues." diff --git a/.github/workflows/scripts/check-unacceptable-language.sh b/.github/workflows/scripts/check-unacceptable-language.sh deleted file mode 120000 index 76efc5cf..00000000 --- a/.github/workflows/scripts/check-unacceptable-language.sh +++ /dev/null @@ -1 +0,0 @@ -../../actions/check-unacceptable-language/check-unacceptable-language.sh \ No newline at end of file diff --git a/.github/workflows/scripts/check-unacceptable-language.sh b/.github/workflows/scripts/check-unacceptable-language.sh new file mode 100755 index 00000000..2a694650 --- /dev/null +++ b/.github/workflows/scripts/check-unacceptable-language.sh @@ -0,0 +1,39 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +test -n "${UNACCEPTABLE_WORD_LIST:-}" || fatal "UNACCEPTABLE_WORD_LIST unset" + +unacceptable_language_lines= +if [[ -f .unacceptablelanguageignore ]]; then + log "Found unacceptable language ignore file..." + log "Checking for unacceptable language..." + unacceptable_language_lines=$(tr '\n' '\0' < .unacceptablelanguageignore | xargs -0 -I% printf '":(exclude)%" '| xargs git grep -i -I -w -H -n --column -E "${UNACCEPTABLE_WORD_LIST// /|}" -- ':!*.unacceptablelanguageignore' | grep -v "ignore-unacceptable-language") || true | /usr/bin/paste -s -d " " - +else + log "Checking for unacceptable language..." + unacceptable_language_lines=$(git grep -i -I -w -H -n --column -E "${UNACCEPTABLE_WORD_LIST// /|}" | grep -v "ignore-unacceptable-language") || true | /usr/bin/paste -s -d " " - +fi + +if [ -n "${unacceptable_language_lines}" ]; then + fatal " ❌ Found unacceptable language: +${unacceptable_language_lines} +" +fi + + +log "✅ Found no unacceptable language." diff --git a/.github/workflows/soundness.yml b/.github/workflows/soundness.yml index 4c543663..c1b7b59a 100644 --- a/.github/workflows/soundness.yml +++ b/.github/workflows/soundness.yml @@ -118,7 +118,7 @@ jobs: timeout-minutes: 40 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: # This is set to true since swift package diagnose-api-breaking-changes is # cloning the repo again and without it being set to true this job won't work for @@ -158,17 +158,31 @@ jobs: timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Pre-build if: ${{ inputs.linux_pre_build_command }} run: ${{ inputs.linux_pre_build_command }} - name: Run documentation check env: ADDITIONAL_DOCC_ARGUMENTS: ${{ inputs.docs_check_additional_arguments }} - uses: ./.github/actions/docs-check + run: ${{ steps.script_path.outputs.root }}/.github/workflows/scripts/check-docs.sh docs-check-macos: name: Documentation check (macOS) @@ -177,10 +191,24 @@ jobs: timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Select Xcode run: echo "DEVELOPER_DIR=/Applications/Xcode_${{ inputs.docs_check_macos_xcode_version }}.app" >> $GITHUB_ENV - name: Swift version @@ -190,7 +218,7 @@ jobs: - name: Run documentation check env: ADDITIONAL_DOCC_ARGUMENTS: ${{ inputs.docs_check_macos_additional_arguments }} - uses: ./.github/actions/docs-check + run: ${{ steps.script_path.outputs.root }}/.github/workflows/scripts/check-docs.sh unacceptable-language-check: name: Unacceptable language check @@ -199,14 +227,28 @@ jobs: timeout-minutes: 1 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Run unacceptable language check env: UNACCEPTABLE_WORD_LIST: ${{ inputs.unacceptable_language_check_word_list}} - uses: ./.github/actions/check-unacceptable-language + run: ${{ steps.script_path.outputs.root }}/.github/workflows/scripts/check-unacceptable-language.sh license-header-check: name: License headers check @@ -215,14 +257,28 @@ jobs: timeout-minutes: 1 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Run license header check env: PROJECT_NAME: ${{ inputs.license_header_check_project_name }} - uses: ./.github/actions/license-header-check + run: ${{ steps.script_path.outputs.root }}/.github/workflows/scripts/check-license-header.sh broken-symlink-check: name: Broken symlinks check @@ -231,12 +287,26 @@ jobs: timeout-minutes: 1 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Run broken symlinks check - uses: ./.github/actions/broken-symlinks-check + run: ${{ steps.script_path.outputs.root }}/.github/workflows/scripts/check-broken-symlinks.sh format-check: name: Format check @@ -247,15 +317,29 @@ jobs: timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Mark the workspace as safe # https://github.com/actions/checkout/issues/766 run: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: Run format check - uses: ./.github/actions/format-check + run: ${{ steps.script_path.outputs.root }}/.github/workflows/scripts/check-swift-format.sh shell-check: name: Shell check @@ -268,7 +352,7 @@ jobs: - name: Install git run: which git || (apt -q update && apt -yq install git) - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true @@ -287,12 +371,33 @@ jobs: timeout-minutes: 5 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Run yamllint - uses: ./.github/actions/yamllint-check + run: | + which yamllint || (apt -q update && apt install -yq yamllint) + cd ${GITHUB_WORKSPACE} + if [ ! -f ".yamllint.yml" ]; then + echo "Downloading default yamllint config file" + cat ${{ steps.script_path.outputs.root }}/.github/workflows/configs/yamllint.yml > .yamllint.yml + fi + yamllint --strict --config-file .yamllint.yml . python-lint-check: name: Python lint check @@ -301,9 +406,30 @@ jobs: timeout-minutes: 5 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: persist-credentials: false submodules: true + - name: Checkout swiftlang/github-workflows repository + if: ${{ github.repository != 'swiftlang/github-workflows' }} + uses: actions/checkout@v4 + with: + repository: swiftlang/github-workflows + path: github-workflows + - name: Determine script-root path + id: script_path + run: | + if [ "${{ github.repository }}" = "swiftlang/github-workflows" ]; then + echo "root=$GITHUB_WORKSPACE" >> $GITHUB_OUTPUT + else + echo "root=$GITHUB_WORKSPACE/github-workflows" >> $GITHUB_OUTPUT + fi - name: Run flake8 - uses: ./.github/actions/python-lint-check + run: | + pip3 install flake8 flake8-import-order + cd ${GITHUB_WORKSPACE} + if [ ! -f ".flake8" ]; then + echo "Downloading default flake8 config file" + cat ${{ steps.script_path.outputs.root }}/.github/workflows/configs/.flake8 > .flake8 + fi + flake8 diff --git a/.licenseignore b/.licenseignore index 5e84d245..ee4247a1 100644 --- a/.licenseignore +++ b/.licenseignore @@ -1,5 +1,4 @@ -.github/actions/python-lint-check/.flake8 -.github/workflows/configs/.flake +.github/workflows/configs/.flake8 **/*.yml CODEOWNERS LICENSE.txt