diff --git a/.github/workflows/configs/.flake8 b/.github/workflows/configs/.flake8 new file mode 100644 index 0000000..c7b743c --- /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 new file mode 100644 index 0000000..52a1770 --- /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/create_automerge_pr.yml b/.github/workflows/create_automerge_pr.yml new file mode 100644 index 0000000..0c5a39c --- /dev/null +++ b/.github/workflows/create_automerge_pr.yml @@ -0,0 +1,104 @@ +name: Create automerge PR + +# Merges `head_branch` into `base_branch` and opens a PR to incorporate that merge commit into `base_branch`. +# +# The typical use case for this is in the first period after Swift has cut release branches. +# Some repositories want to include most changes from `main` also in the release branch. When this job is set up, it can automatically create PRs to merge `main` into the release branch. +# Maintainers of the package can then inspect the changes to ensure that they are not too risky for the release branch. +# We will also run the normal PR testing on these changes, ensuring that these modifications don't break the build. +# +# Example usage in a repository: +# +# ``` +# name: Create PR to merge main into release branch +# +# # In the first period after branching the release branch, we typically want to include all changes from `main` also in the release branch. This workflow automatically creates a PR every Monday to merge main into the release branch. +# # Later in the release cycle we should stop this practice to avoid landing risky changes by disabling this workflow. To do so, disable the workflow as described in https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow +# +# on: +# schedule: +# - cron: '0 9 * * MON' +# workflow_dispatch: +# +# jobs: +# create_merge_pr: +# name: Create PR to merge main into release branch +# uses: swiftlang/github-workflows/.github/workflows/create_automerge_pr.yml@main +# if: (github.event_name == 'schedule' && github.repository == 'swiftlang/swift-format') || (github.event_name != 'schedule') # Ensure that we don't run this on a schedule in a fork +# permissions: +# contents: write +# pull-requests: write +# with: +# base_branch: release/6.2 +# ``` +# +# PRs created by GitHub Actions don't kick off further actions (https://github.com/peter-evans/create-pull-request/blob/d57e551ebc1a16dee0b8c9ea6d24dba7627a6e35/docs/concepts-guidelines.md#triggering-further-workflow-runs). +# As a workaround, we mark automerge PRs that are created by GitHub actions as draft and trigger the GitHub actions by marking the PR as ready for review. `ready_for_review` must be added to the PR types for this purpose, eg. +# ``` +# on: +# pull_request: +# types: [..., ready_for_review] +# ``` +# Unfortunately this will also re-trigger testing evenon a normal user's PR (which may have already been tested), but skipping them causes the checks to reset so this is the best we can do for now. +on: + workflow_call: + inputs: + base_branch: + type: string + description: The branch into which head_branch should be merged + required: true + head_branch: + type: string + description: The branch that should be merged into base_branch + default: main + pr_message: + type: string + description: The message that should be included in the PR created by this job + default: This PR was automatically opened by a GitHub action. Review the changes included in this PR and determine if they should be included in the release branch. If yes, merge the PR. Otherwise revert changes that should not be included on this branch. + +jobs: + create_merge_pr: + name: Create PR to merge ${{ inputs.head_branch }} into ${{ inputs.base_branch }} branch + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Check if there are commits to merge + id: create_merge_commit + run: | + # Without this, we can't perform git operations in GitHub actions. + git config --global --add safe.directory "$(realpath .)" + git config --local user.name 'swift-ci' + git config --local user.email 'swift-ci@users.noreply.github.com' + + if [[ "$(git rev-list --left-only --count origin/${{ inputs.head_branch }}...origin/${{ inputs.base_branch }})" == 0 ]]; then + echo "Nothing to merge" + echo "has_commits_to_merge=false" >> "$GITHUB_OUTPUT" + exit + fi + + echo "has_commits_to_merge=true" >> "$GITHUB_OUTPUT" + - name: Push branch and create PR + id: push_branch + if: ${{ steps.create_merge_commit.outputs.has_commits_to_merge == 'true' }} + env: + GH_TOKEN: ${{ github.token }} + run: | + # Create a branch for the PR instead of opening a PR that merges head_branch directly so that we have a fixed + # target in the PR and don't modify the PR as new commits are put on the head branch. + PR_BRANCH="automerge/merge-main-$(date +%Y-%m-%d_%H-%M)" + git checkout ${{ inputs.head_branch }} + git checkout -b "$PR_BRANCH" + git push --set-upstream origin "$PR_BRANCH" + + gh pr create \ + --base "${{ inputs.base_branch }}" \ + --head "$PR_BRANCH" \ + --title 'Merge `${{ inputs.head_branch }}` into `${{ inputs.base_branch }}`' \ + --body '${{ inputs.pr_message }}' \ + --draft diff --git a/.github/workflows/performance_test.yml b/.github/workflows/performance_test.yml new file mode 100644 index 0000000..105e004 --- /dev/null +++ b/.github/workflows/performance_test.yml @@ -0,0 +1,92 @@ +name: Performance test + +on: + workflow_call: + inputs: + container: + type: string + description: "The container that the performance tests should run in" + default: "swift:latest" + package_path: + type: string + description: The directory in the repository that contains a package, which depends on ordo-one/package-benchmark and can run performance measurements. + default: Benchmarks + comment_header: + type: string + description: | + If the performance has changed, this text will be prepended to the comment that contains the performance measurements. + This can be either for performance improvements or regressions. + default: | + This PR has changed performance characteristics. Please review that the measurements reported below are expected. If these are improvements, thanks for improving the performance. + +jobs: + measure_performance: + name: Measure performance + runs-on: ubuntu-latest + container: + image: ${{ inputs.container }} + timeout-minutes: 60 + permissions: + pull-requests: write + steps: + - name: Install libjemalloc-dev + run: apt-get update && apt-get install -y libjemalloc-dev + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Mark the workspace as safe + # https://github.com/actions/checkout/issues/766 + run: git config --global --add safe.directory ${GITHUB_WORKSPACE} + - name: Measure PR performance + run: | + swift package --package-path ${{ inputs.package_path }} --allow-writing-to-directory ${{ inputs.package_path }}/.benchmarkBaselines/ benchmark baseline update "${{ github.head_ref }}" + - name: Measure base branch performance + run: | + git checkout ${{ github.base_ref }} + swift package --package-path ${{ inputs.package_path }} --allow-writing-to-directory ${{ inputs.package_path }}/.benchmarkBaselines/ benchmark baseline update "${{ github.base_ref }}" + - name: Compare performance measurements + id: compare_performance + run: | + if ! swift package --package-path ${{ inputs.package_path }} benchmark baseline check "${{ github.base_ref }}" "${{ github.head_ref }}" --format markdown > /tmp/comparison.md 2>/tmp/comparison-stderr.txt; then + echo "has_significant_changes=true" >> "$GITHUB_OUTPUT" + else + echo "has_significant_changes=false" >> "$GITHUB_OUTPUT" + fi + - name: Install gh + if: ${{ steps.compare_performance.outputs.has_significant_changes == 'true' }} + # Installation instructions from https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian-ubuntu-linux-raspberry-pi-os-apt + run: | + (type -p wget >/dev/null || (apt update && apt-get install wget -y)) + mkdir -p -m 755 /etc/apt/keyrings + out=$(mktemp) + wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg + cat $out | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null + chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null + apt update + apt install gh -y + - name: Post comment + if: ${{ steps.compare_performance.outputs.has_significant_changes == 'true' }} + env: + GH_TOKEN: ${{ github.token }} + run: | + if grep benchmarkThresholdRegression /tmp/comparison-stderr.txt > /dev/null; then + PERFORMANCE_CHANGE_MESSAGE="This PR has regressed performance characteristics. Please review whether the changes reported below are expected or if you can do something to improve them." + elif grep benchmarkThresholdImprovement /tmp/comparison-stderr.txt > /dev/null; then + PERFORMANCE_CHANGE_MESSAGE="This PR has improved performance characteristics. Thank you 🚀" + else + PERFORMANCE_CHANGE_MESSAGE="This PR has changed performance characteristics. Please review that the measurements reported below are expected or if you can do something to improve them." + fi + + cat > /tmp/performance_change_header.md <Performance report + + EOF + + echo "" > /tmp/performance_change_footer.md + + COMMENT="$(cat /tmp/performance_change_header.md /tmp/comparison.md /tmp/performance_change_footer.md)" + gh pr comment ${{ github.event.number }} --body "$COMMENT" diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..aea1491 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,86 @@ +name: Pull request + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + tests_with_docker_embedded_swift: + name: Test Embedded Swift SDKs + uses: ./.github/workflows/swift_package_test.yml + with: + # Wasm + enable_linux_checks: false + enable_macos_checks: false + enable_windows_checks: false + wasm_sdk_pre_build_command: | + mkdir MyPackage + cd MyPackage + swift package init --type library + enable_embedded_wasm_sdk_build: true + + tests_with_docker: + name: Test with Docker + uses: ./.github/workflows/swift_package_test.yml + with: + # Linux + linux_os_versions: '["jammy", "rhel-ubi9", "amazonlinux2"]' + linux_build_command: | + mkdir MyPackage + cd MyPackage + swift package init --type library + swift build + linux_static_sdk_pre_build_command: | + mkdir MyPackage + cd MyPackage + swift package init --type library + enable_linux_static_sdk_build: true + # Wasm + wasm_sdk_pre_build_command: | + mkdir MyPackage + cd MyPackage + swift package init --type library + enable_wasm_sdk_build: true + # Windows + windows_build_command: | + mkdir MyPackage + cd MyPackage + Invoke-Program swift package init --type library + Invoke-Program swift build + enable_windows_docker: true + + tests_without_docker: + name: Test without Docker + uses: ./.github/workflows/swift_package_test.yml + with: + # Skip Linux which doesn't currently support docker-less workflow + enable_linux_checks: false + # Windows + windows_build_command: | + mkdir MyPackage + cd MyPackage + Invoke-Program swift package init --type library + Invoke-Program swift build + enable_windows_docker: false + + tests_macos: + name: Test + uses: ./.github/workflows/swift_package_test.yml + with: + enable_linux_checks: false + enable_windows_checks: false + # macOS + enable_macos_checks: true + macos_build_command: | + mkdir MyPackage + cd MyPackage + xcrun swift package init --type library + xcrun swift build + + soundness: + name: Soundness + uses: ./.github/workflows/soundness.yml + with: + api_breakage_check_enabled: false + license_header_check_project_name: "Swift.org" + format_check_enabled: false diff --git a/.github/workflows/scripts/check-broken-symlinks.sh b/.github/workflows/scripts/check-broken-symlinks.sh index c9c0936..570cbdb 100755 --- a/.github/workflows/scripts/check-broken-symlinks.sh +++ b/.github/workflows/scripts/check-broken-symlinks.sh @@ -1,15 +1,15 @@ #!/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 -# -# ===----------------------------------------------------------------------===// +##===----------------------------------------------------------------------===## +## +## 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 diff --git a/.github/workflows/scripts/check-docs.sh b/.github/workflows/scripts/check-docs.sh index 368ad97..5c4fb02 100755 --- a/.github/workflows/scripts/check-docs.sh +++ b/.github/workflows/scripts/check-docs.sh @@ -1,15 +1,15 @@ #!/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 -# -# ===----------------------------------------------------------------------===// +##===----------------------------------------------------------------------===## +## +## 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 @@ -17,17 +17,43 @@ log() { printf -- "** %s\n" "$*" >&2; } error() { printf -- "** ERROR: %s\n" "$*" >&2; } fatal() { error "$@"; exit 1; } -log "Editing Package.swift..." -cat <> "Package.swift" +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 + fatal "yq could not be found. Please install yq to proceed." +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", "1.0.0"..<"1.4.0") + .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..." - swift package plugin generate-documentation --target "$target" --warnings-as-errors --analyze --level detailed + # 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 index 0768bee..845eb25 100755 --- a/.github/workflows/scripts/check-license-header.sh +++ b/.github/workflows/scripts/check-license-header.sh @@ -1,15 +1,15 @@ #!/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 -# -# ===----------------------------------------------------------------------===// +##===----------------------------------------------------------------------===## +## +## 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 @@ -17,9 +17,12 @@ log() { printf -- "** %s\n" "$*" >&2; } error() { printf -- "** ERROR: %s\n" "$*" >&2; } fatal() { error "$@"; exit 1; } -test -n "${PROJECT_NAME:-}" || fatal "PROJECT_NAME unset" - -expected_file_header_template="@@===----------------------------------------------------------------------===@@ +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 @@ @@ -32,35 +35,88 @@ expected_file_header_template="@@===-------------------------------------------- @@ SPDX-License-Identifier: Apache-2.0 @@ @@===----------------------------------------------------------------------===@@" +fi paths_with_missing_license=( ) -file_paths=$(tr '\n' '\0' < .licenseignore | xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files) +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 - swift) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; - h) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; - c) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; - sh) expected_file_header=$(cat <(echo '#!/bin/bash') <(sed -e 's|@@|##|g' <<<"${expected_file_header_template}")) ;; - kts) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; - java) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; - py) expected_file_header=$(cat <(echo '#!/usr/bin/env python3') <(sed -e 's|@@|##|g' <<<"${expected_file_header_template}")) ;; - rb) expected_file_header=$(cat <(echo '#!/usr/bin/env ruby') <(sed -e 's|@@|##|g' <<<"${expected_file_header_template}")) ;; - in) expected_file_header=$(sed -e 's|@@|##|g' <<<"${expected_file_header_template}") ;; - cmake) expected_file_header=$(sed -e 's|@@|##|g' <<<"${expected_file_header_template}") ;; - *) fatal "Unsupported file extension for file (exclude or update this script): ${file_path}" ;; + 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='//' ;; + 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='##' ;; + 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='//' ;; + 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_linecount=$(wc -l <<<"${expected_file_header}") + 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 's/20[12][0123456789]-20[12][0123456789]/YEARS/' -e 's/20[12][0123456789]/YEARS/' \ + | sed -E -e 's/20[12][0123456789] ?- ?20[12][0123456789]/YEARS/' -e 's/20[12][0123456789]/YEARS/' \ ) if ! diff -u \ diff --git a/.github/workflows/scripts/check-swift-format.sh b/.github/workflows/scripts/check-swift-format.sh index 7f48345..a3c3221 100755 --- a/.github/workflows/scripts/check-swift-format.sh +++ b/.github/workflows/scripts/check-swift-format.sh @@ -1,15 +1,15 @@ #!/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 -# -# ===----------------------------------------------------------------------===// +##===----------------------------------------------------------------------===## +## +## 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 diff --git a/.github/workflows/scripts/check-unacceptable-language.sh b/.github/workflows/scripts/check-unacceptable-language.sh index a26d985..2a69465 100755 --- a/.github/workflows/scripts/check-unacceptable-language.sh +++ b/.github/workflows/scripts/check-unacceptable-language.sh @@ -1,15 +1,15 @@ #!/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 -# -# ===----------------------------------------------------------------------===// +##===----------------------------------------------------------------------===## +## +## 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 @@ -19,12 +19,15 @@ fatal() { error "$@"; exit 1; } test -n "${UNACCEPTABLE_WORD_LIST:-}" || fatal "UNACCEPTABLE_WORD_LIST unset" -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 " " - +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: @@ -32,4 +35,5 @@ ${unacceptable_language_lines} " fi -log "✅ Found no unacceptable language." \ No newline at end of file + +log "✅ Found no unacceptable language." diff --git a/.github/workflows/scripts/install-and-build-with-sdk.sh b/.github/workflows/scripts/install-and-build-with-sdk.sh new file mode 100644 index 0000000..6111a63 --- /dev/null +++ b/.github/workflows/scripts/install-and-build-with-sdk.sh @@ -0,0 +1,585 @@ +#!/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; } + +# Parse command line options +INSTALL_STATIC_LINUX=false +INSTALL_WASM=false +BUILD_EMBEDDED_WASM=false +SWIFT_VERSION_INPUT="" +SWIFT_BUILD_FLAGS="" +SWIFT_BUILD_COMMAND="swift build" + +while [[ $# -gt 0 ]]; do + case $1 in + --static) + INSTALL_STATIC_LINUX=true + shift + ;; + --wasm) + INSTALL_WASM=true + shift + ;; + --embedded-wasm) + INSTALL_WASM=true + BUILD_EMBEDDED_WASM=true + shift + ;; + --flags=*) + SWIFT_BUILD_FLAGS="${1#*=}" + shift + ;; + --build-command=*) + SWIFT_BUILD_COMMAND="${1#*=}" + shift + ;; + -*) + fatal "Unknown option: $1" + ;; + *) + if [[ -z "$SWIFT_VERSION_INPUT" ]]; then + SWIFT_VERSION_INPUT="$1" + else + fatal "Multiple Swift versions specified: $SWIFT_VERSION_INPUT and $1" + fi + shift + ;; + esac +done + +# Validate arguments +if [[ -z "$SWIFT_VERSION_INPUT" ]]; then + fatal "Usage: $0 [--static] [--wasm] [--flags=\"\"] [--build-command=\"\"] " +fi + +if [[ "$INSTALL_STATIC_LINUX" == false && "$INSTALL_WASM" == false ]]; then + fatal "At least one of --static or --wasm must be specified" +fi + +log "Requested Swift version: $SWIFT_VERSION_INPUT" +log "Install Static Linux Swift SDK: $INSTALL_STATIC_LINUX" +log "Install Wasm Swift SDK: $INSTALL_WASM" +if [[ -n "$SWIFT_BUILD_FLAGS" ]]; then + log "Additional build flags: $SWIFT_BUILD_FLAGS" +fi + +# Detect package manager +if command -v apt >/dev/null 2>&1; then + INSTALL_PACKAGE_COMMAND="apt update -q && apt install -yq" +elif command -v dnf >/dev/null 2>&1; then + INSTALL_PACKAGE_COMMAND="dnf install -y" +elif command -v yum >/dev/null 2>&1; then + INSTALL_PACKAGE_COMMAND="yum install -y" +else + fatal "No supported package manager found" +fi + +install_package() { + eval "$INSTALL_PACKAGE_COMMAND $1" +} + +# Install dependencies +command -v curl >/dev/null || install_package curl +command -v jq >/dev/null || install_package jq + +SWIFT_API_INSTALL_ROOT="https://www.swift.org/api/v1/install" + +# Transforms a minor Swift release version into its latest patch version +# and gets the checksum for the patch version's Static Linux and/or Wasm Swift SDK. +# +# $1 (string): A minor Swift version, e.g. "6.1" +# Output: A string of the form "|| +find_latest_swift_version() { + local minor_version="$1" + + log "Finding latest patch version for Swift ${minor_version}" + log "Fetching releases from swift.org API..." + + local releases_json + releases_json=$(curl -fsSL "${SWIFT_API_INSTALL_ROOT}/releases.json") || fatal "Failed to fetch Swift releases" + + # Find all releases that start with the minor version (e.g, "6.1") + # Sort them and get the latest one + local latest_version + latest_version=$(echo "$releases_json" | jq -r --arg minor "$minor_version" ' + .[] + | select(.name | startswith($minor)) + | .name + ' | sort -V | tail -n1) + + if [[ -z "$latest_version" ]]; then + fatal "No Swift release found for version $minor_version" + fi + + log "Found latest patch version: $latest_version" + + local static_linux_sdk_checksum="" + if [[ "$INSTALL_STATIC_LINUX" == true ]]; then + static_linux_sdk_checksum=$(echo "$releases_json" | jq -r --arg version "$latest_version" ' + .[] + | select(.name == $version) + | .platforms[] + | select(.platform == "static-sdk") + | .checksum + ') + + if [[ -z "$static_linux_sdk_checksum" ]]; then + fatal "No Static Linux Swift SDK checksum found for Swift $latest_version" + fi + + log "Found Static Linux Swift SDK checksum: ${static_linux_sdk_checksum:0:12}..." + fi + + local wasm_sdk_checksum="" + if [[ "$INSTALL_WASM" == true ]]; then + wasm_sdk_checksum=$(echo "$releases_json" | jq -r --arg version "$latest_version" ' + .[] + | select(.name == $version) + | .platforms[] + | select(.platform == "wasm-sdk") + | .checksum + ') + + if [[ -z "$wasm_sdk_checksum" ]]; then + fatal "No Swift SDK for Wasm checksum found for Swift $latest_version" + fi + + log "Found Swift SDK for Wasm checksum: ${wasm_sdk_checksum:0:12}..." + fi + + echo "${latest_version}|${static_linux_sdk_checksum}|${wasm_sdk_checksum}" +} + +# Finds the latest Static Linux or Wasm Swift SDK development snapshot +# for the inputted Swift version and its checksum. +# +# $1 (string): Nightly Swift version, e.g. "6.2" or "main" +# $2 (string): "static" or "wasm" +# Output: A string of the form "|", +# e.g. "swift-6.2-DEVELOPMENT-SNAPSHOT-2025-07-29-a|" +find_latest_sdk_snapshot() { + local version="$1" + local sdk_name="$2" + + log "Finding latest ${sdk_name}-sdk for Swift nightly-${version}" + log "Fetching development snapshots from swift.org API..." + + local sdk_json + sdk_json=$(curl -fsSL "${SWIFT_API_INSTALL_ROOT}/dev/${version}/${sdk_name}-sdk.json") || fatal "Failed to fetch ${sdk_name}-sdk development snapshots" + + # Extract the snapshot tag from the "dir" field of the first (newest) element + local snapshot_tag + snapshot_tag=$(echo "$sdk_json" | jq -r '.[0].dir') + + if [[ -z "$snapshot_tag" || "$snapshot_tag" == "null" ]]; then + fatal "No ${version} snapshot tag found for ${sdk_name}-sdk" + fi + + log "Found latest ${version} ${sdk_name}-sdk snapshot: $snapshot_tag" + + # Extract the checksum + local checksum + checksum=$(echo "$sdk_json" | jq -r '.[0].checksum') + + if [[ -z "$checksum" || "$checksum" == "null" ]]; then + fatal "No checksum found for ${sdk_name}-sdk snapshot" + fi + + log "Found ${sdk_name}-sdk checksum: ${checksum:0:12}..." + + echo "${snapshot_tag}|${checksum}" +} + +SWIFT_VERSION_BRANCH="" +STATIC_LINUX_SDK_TAG="" +STATIC_LINUX_SDK_CHECKSUM="" +WASM_SDK_TAG="" +WASM_SDK_CHECKSUM="" + +# Parse Swift version input which may contain "nightly-" +if [[ "$SWIFT_VERSION_INPUT" == nightly-* ]]; then + version="${SWIFT_VERSION_INPUT#nightly-}" + if [[ "$version" == "main" ]]; then + SWIFT_VERSION_BRANCH="development" + else + SWIFT_VERSION_BRANCH="swift-${version}-branch" + fi + + if [[ "$INSTALL_STATIC_LINUX" == true ]]; then + static_linux_sdk_info=$(find_latest_sdk_snapshot "$version" "static") + + STATIC_LINUX_SDK_TAG=$(echo "$static_linux_sdk_info" | cut -d'|' -f1) + STATIC_LINUX_SDK_CHECKSUM=$(echo "$static_linux_sdk_info" | cut -d'|' -f2) + fi + + if [[ "$INSTALL_WASM" == true ]]; then + wasm_sdk_info=$(find_latest_sdk_snapshot "$version" "wasm") + + WASM_SDK_TAG=$(echo "$wasm_sdk_info" | cut -d'|' -f1) + WASM_SDK_CHECKSUM=$(echo "$wasm_sdk_info" | cut -d'|' -f2) + fi +else + latest_version_info=$(find_latest_swift_version "$SWIFT_VERSION_INPUT") + + latest_version=$(echo "$latest_version_info" | cut -d'|' -f1) + SWIFT_VERSION_BRANCH="swift-${latest_version}-release" + + STATIC_LINUX_SDK_TAG="swift-${latest_version}-RELEASE" + STATIC_LINUX_SDK_CHECKSUM=$(echo "$latest_version_info" | cut -d'|' -f2) + + WASM_SDK_TAG="swift-${latest_version}-RELEASE" + WASM_SDK_CHECKSUM=$(echo "$latest_version_info" | cut -d'|' -f3) +fi + +# Validate that required Swift SDK tags are set +if [[ "$INSTALL_STATIC_LINUX" == true && -z "$STATIC_LINUX_SDK_TAG" ]]; then + fatal "STATIC_LINUX_SDK_TAG is not set but Static Linux Swift SDK installation was requested" +fi + +if [[ "$INSTALL_WASM" == true && -z "$WASM_SDK_TAG" ]]; then + fatal "WASM_SDK_TAG is not set but Wasm Swift SDK installation was requested" +fi + +get_installed_swift_tag() { + if ! command -v swift >/dev/null 2>&1; then + log "Swift is not currently installed" + echo "none" + return 0 + fi + + # Check for /.swift_tag file + if [[ -f "/.swift_tag" ]]; then + local swift_tag + swift_tag=$(tr -d '\n' < /.swift_tag | tr -d ' ') + if [[ -n "$swift_tag" ]]; then + log "✅ Found Swift snapshot tag in /.swift_tag: $swift_tag" + echo "$swift_tag" + return 0 + fi + fi + + # Try to get release version from swift command if available + local swift_tag + swift_tag=$(swift --version 2>/dev/null | grep -o "(swift-.*-RELEASE)" | tr -d "()" | head -n1) + if [[ -n "$swift_tag" ]]; then + log "✅ Found Swift release tag via 'swift --version': $swift_tag" + echo "$swift_tag" + return 0 + fi + + log "Could not find tag of the installed Swift version" + echo "none" +} + +OS_NAME="" +OS_NAME_NO_DOT="" +OS_ARCH_SUFFIX="" + +# Detects OS from /etc/os-release and sets global variables +# +# OS_NAME: Lowercased OS name with the version dot included, e.g. ubuntu22.04 +# OS_NAME_NO_DOT: Version dot excluded, e.g. ubuntu2204 +# OS_ARCH_SUFFIX: "-aarch64" for aarch64 platforms, otherwise "" +initialize_os_info() { + if [[ -n "$OS_NAME" ]]; then + log "Already detected OS: $OS_NAME" + return 0 + fi + + if [[ ! -f /etc/os-release ]]; then + fatal "Cannot detect OS: /etc/os-release not found" + fi + + local os_id + os_id=$(grep '^ID=' /etc/os-release | cut -d'=' -f2 | tr -d '"' | tr '[:upper:]' '[:lower:]') + local version_id + version_id=$(grep '^VERSION_ID=' /etc/os-release | cut -d'=' -f2 | tr -d '"') + + if [[ -z "$os_id" || -z "$version_id" ]]; then + fatal "Could not parse OS information from /etc/os-release" + fi + + log "✅ Detected OS from /etc/os-release: ${os_id}${version_id}" + if [[ "$os_id" == "rhel" && "$version_id" == 9* ]]; then + OS_NAME="ubi9" + OS_NAME_NO_DOT="ubi9" + elif [[ "$os_id" == "amzn" && "$version_id" == "2" ]]; then + OS_NAME="amazonlinux2" + OS_NAME_NO_DOT="amazonlinux2" + else + # Ubuntu, Debian, Fedora + OS_NAME="${os_id}${version_id}" + OS_NAME_NO_DOT="${os_id}$(echo "$version_id" | tr -d '.')" + fi + log "Using OS name: $OS_NAME" + + local arch + arch=$(uname -m) + if [[ "$arch" == "aarch64" ]]; then + OS_ARCH_SUFFIX="-aarch64" + log "Detected aarch64 architecture, using suffix: $OS_ARCH_SUFFIX" + else + OS_ARCH_SUFFIX="" + log "Detected $arch architecture, using no suffix" + fi +} + +# Directory for extracted toolchains (if needed to match the SDKs) +TOOLCHAIN_DIR="${HOME}/.swift-toolchains" +SWIFT_DOWNLOAD_ROOT="https://download.swift.org" + +download_and_verify() { + local url="$1" + local sig_url="$2" + local output_file="$3" + local temp_sig="${output_file}.sig" + + log "Downloading ${url}" + curl -fsSL "$url" -o "$output_file" + + log "Downloading signature" + curl -fsSL "$sig_url" -o "$temp_sig" + + log "Setting up GPG for verification" + local gnupghome + gnupghome="$(mktemp -d)" + export GNUPGHOME="$gnupghome" + curl -fSsL https://swift.org/keys/all-keys.asc | zcat -f | gpg --import - >/dev/null 2>&1 + + log "Verifying signature" + if gpg --batch --verify "$temp_sig" "$output_file" >/dev/null 2>&1; then + log "✅ Signature verification successful" + else + fatal "Signature verification failed" + fi + + rm -rf "$GNUPGHOME" "$temp_sig" +} + +readonly EXIT_TOOLCHAIN_NOT_FOUND=44 + +# Downloads and extracts the Swift toolchain for the given snapshot tag +# +# $1 (string): A snapshot tag, e.g. "swift-6.2-DEVELOPMENT-SNAPSHOT-2025-07-29-a" +# Output: Path to the installed swift executable +download_and_extract_toolchain() { + local snapshot_tag="$1" + + log "Downloading Swift toolchain: $snapshot_tag" + + # "https://download.swift.org/swift-6.2-branch/ubuntu2204/swift-6.2-DEVELOPMENT-SNAPSHOT-2025-07-29-a" + local snapshot_root="${SWIFT_DOWNLOAD_ROOT}/${SWIFT_VERSION_BRANCH}/${OS_NAME_NO_DOT}${OS_ARCH_SUFFIX}/${snapshot_tag}" + + # "swift-6.2-DEVELOPMENT-SNAPSHOT-2025-07-29-a-ubuntu22.04.tar.gz" + # "swift-6.2-DEVELOPMENT-SNAPSHOT-2025-07-29-a-ubuntu22.04.tar.gz.sig" + local toolchain_filename="${snapshot_tag}-${OS_NAME}${OS_ARCH_SUFFIX}.tar.gz" + local toolchain_sig_filename="${toolchain_filename}.sig" + + local toolchain_url="${snapshot_root}/${toolchain_filename}" + local toolchain_sig_url="${snapshot_root}/${toolchain_sig_filename}" + + # Check if toolchain is available + local http_code + http_code=$(curl -sSL --head -w "%{http_code}" -o /dev/null "$toolchain_url") + if [[ "$http_code" == "404" ]]; then + log "Toolchain not found: ${toolchain_filename}" + log "Exiting workflow..." + # Don't fail the workflow if we can't find the right toolchain + exit $EXIT_TOOLCHAIN_NOT_FOUND + fi + + # Create toolchain directory + mkdir -p "$TOOLCHAIN_DIR" + local toolchain_path="${TOOLCHAIN_DIR}/${snapshot_tag}" + + # Check if toolchain already exists + if [[ -d "$toolchain_path" && -f "${toolchain_path}/usr/bin/swift" ]]; then + log "✅ Toolchain already exists at: $toolchain_path" + echo "$toolchain_path/usr/bin/swift" + return 0 + fi + + # Create temporary directory + local temp_dir + temp_dir=$(mktemp -d) + local toolchain_file="${temp_dir}/swift_toolchain.tar.gz" + + # Download and verify toolchain + download_and_verify "$toolchain_url" "$toolchain_sig_url" "$toolchain_file" + + log "Extracting toolchain to: $toolchain_path" + mkdir -p "$toolchain_path" + tar -xzf "$toolchain_file" --directory "$toolchain_path" --strip-components=1 + + # Clean up + rm -rf "$temp_dir" + + local swift_executable="${toolchain_path}/usr/bin/swift" + if [[ -f "$swift_executable" ]]; then + log "✅ Swift toolchain extracted successfully" + echo "$swift_executable" + else + fatal "Swift executable not found at expected path: $swift_executable" + fi +} + +INSTALLED_SWIFT_TAG=$(get_installed_swift_tag) +SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK="" +SWIFT_EXECUTABLE_FOR_WASM_SDK="" + +if [[ "$INSTALL_STATIC_LINUX" == true ]]; then + if [[ "$INSTALLED_SWIFT_TAG" == "$STATIC_LINUX_SDK_TAG" ]]; then + log "Current toolchain matches Static Linux Swift SDK snapshot: $STATIC_LINUX_SDK_TAG" + SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK="swift" + else + log "Installing Swift toolchain to match Static Linux Swift SDK snapshot: $STATIC_LINUX_SDK_TAG" + initialize_os_info + SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK=$(download_and_extract_toolchain "$STATIC_LINUX_SDK_TAG") + if [[ $? -eq $EXIT_TOOLCHAIN_NOT_FOUND ]]; then + # Don't fail the workflow if we can't find the right toolchain + exit 0 + fi + fi +fi + +if [[ "$INSTALL_WASM" == true ]]; then + if [[ "$INSTALLED_SWIFT_TAG" == "$WASM_SDK_TAG" ]]; then + log "Current toolchain matches Wasm Swift SDK snapshot: $WASM_SDK_TAG" + SWIFT_EXECUTABLE_FOR_WASM_SDK="swift" + else + log "Installing Swift toolchain to match Wasm Swift SDK snapshot: $WASM_SDK_TAG" + initialize_os_info + SWIFT_EXECUTABLE_FOR_WASM_SDK=$(download_and_extract_toolchain "$WASM_SDK_TAG") + if [[ $? -eq $EXIT_TOOLCHAIN_NOT_FOUND ]]; then + # Don't fail the workflow if we can't find the right toolchain + exit 0 + fi + fi +fi + +STATIC_LINUX_SDK_DOWNLOAD_ROOT="${SWIFT_DOWNLOAD_ROOT}/${SWIFT_VERSION_BRANCH}/static-sdk" +WASM_SDK_DOWNLOAD_ROOT="${SWIFT_DOWNLOAD_ROOT}/${SWIFT_VERSION_BRANCH}/wasm-sdk" + +install_static_linux_sdk() { + # Check if the Static Linux Swift SDK is already installed + if "$SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK" sdk list 2>/dev/null | grep -q "^${STATIC_LINUX_SDK_TAG}_static-linux-0.0.1"; then + log "✅ Static Linux Swift SDK ${STATIC_LINUX_SDK_TAG} is already installed, skipping installation" + return 0 + fi + + log "Installing Static Linux Swift SDK: $STATIC_LINUX_SDK_TAG" + + local static_linux_sdk_filename="${STATIC_LINUX_SDK_TAG}_static-linux-0.0.1.artifactbundle.tar.gz" + local sdk_url="${STATIC_LINUX_SDK_DOWNLOAD_ROOT}/${STATIC_LINUX_SDK_TAG}/${static_linux_sdk_filename}" + + log "Running: ${SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK} sdk install ${sdk_url} --checksum ${STATIC_LINUX_SDK_CHECKSUM}" + + if "$SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK" sdk install "$sdk_url" --checksum "$STATIC_LINUX_SDK_CHECKSUM"; then + log "✅ Static Linux Swift SDK installed successfully" + else + fatal "Failed to install Static Linux Swift SDK" + fi +} + +install_wasm_sdk() { + # Check if Swift SDK for Wasm is already installed + if "$SWIFT_EXECUTABLE_FOR_WASM_SDK" sdk list 2>/dev/null | grep -q "^${WASM_SDK_TAG}_wasm"; then + log "✅ Swift SDK for Wasm ${WASM_SDK_TAG} is already installed, skipping installation" + return 0 + fi + + log "Installing Swift SDK for Wasm: $WASM_SDK_TAG" + + local wasm_sdk_filename="${WASM_SDK_TAG}_wasm.artifactbundle.tar.gz" + local sdk_url="${WASM_SDK_DOWNLOAD_ROOT}/${WASM_SDK_TAG}/${wasm_sdk_filename}" + + log "Running: ${SWIFT_EXECUTABLE_FOR_WASM_SDK} sdk install ${sdk_url} --checksum ${WASM_SDK_CHECKSUM}" + + if "$SWIFT_EXECUTABLE_FOR_WASM_SDK" sdk install "$sdk_url" --checksum "$WASM_SDK_CHECKSUM"; then + log "✅ Swift SDK for Wasm installed successfully" + else + fatal "Failed to install Swift SDK for Wasm" + fi +} + +install_sdks() { + if [[ "$INSTALL_STATIC_LINUX" == true ]]; then + log "Starting install of Swift ${SWIFT_VERSION_INPUT} Static Linux Swift SDK" + install_static_linux_sdk + fi + + if [[ "$INSTALL_WASM" == true ]]; then + log "Starting install of Swift ${SWIFT_VERSION_INPUT} Wasm Swift SDK" + install_wasm_sdk + fi +} + +build() { + # Enable alias expansion to use a 'swift' alias for the executable path + shopt -s expand_aliases + + if [[ "$INSTALL_STATIC_LINUX" == true ]]; then + log "Running Swift build with Static Linux Swift SDK" + + local sdk_name="${STATIC_LINUX_SDK_TAG}_static-linux-0.0.1" + alias swift='$SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK' + local build_command="$SWIFT_BUILD_COMMAND --swift-sdk $sdk_name" + if [[ -n "$SWIFT_BUILD_FLAGS" ]]; then + build_command="$build_command $SWIFT_BUILD_FLAGS" + fi + + log "Running: $build_command" + + if eval "$build_command"; then + log "✅ Swift build with Static Linux Swift SDK completed successfully" + else + fatal "Swift build with Static Linux Swift SDK failed" + fi + fi + + if [[ "$INSTALL_WASM" == true ]]; then + log "Running Swift build with Swift SDK for Wasm" + + if [[ "$BUILD_EMBEDDED_WASM" == true ]]; then + local sdk_name="${WASM_SDK_TAG}_wasm-embedded" + else + local sdk_name="${WASM_SDK_TAG}_wasm" + fi + + alias swift='$SWIFT_EXECUTABLE_FOR_WASM_SDK' + local build_command="$SWIFT_BUILD_COMMAND --swift-sdk $sdk_name" + if [[ -n "$SWIFT_BUILD_FLAGS" ]]; then + build_command="$build_command $SWIFT_BUILD_FLAGS" + fi + + log "Running: $build_command" + + if eval "$build_command"; then + log "✅ Swift build with Swift SDK for Wasm completed successfully" + else + fatal "Swift build with Swift SDK for Wasm failed" + fi + fi +} + +main() { + install_sdks + build +} + +main "$@" diff --git a/.github/workflows/scripts/windows/install-vsb.ps1 b/.github/workflows/scripts/windows/install-vsb.ps1 new file mode 100644 index 0000000..931cbbb --- /dev/null +++ b/.github/workflows/scripts/windows/install-vsb.ps1 @@ -0,0 +1,43 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +$VSB='https://download.visualstudio.microsoft.com/download/pr/5536698c-711c-4834-876f-2817d31a2ef2/c792bdb0fd46155de19955269cac85d52c4c63c23db2cf43d96b9390146f9390/vs_BuildTools.exe' +$VSB_SHA256='C792BDB0FD46155DE19955269CAC85D52C4C63C23DB2CF43D96B9390146F9390' +Set-Variable ErrorActionPreference Stop +Set-Variable ProgressPreference SilentlyContinue +Write-Host -NoNewLine ('Downloading {0} ... ' -f ${VSB}) +Invoke-WebRequest -Uri $VSB -OutFile $env:TEMP\vs_buildtools.exe +Write-Host 'SUCCESS' +Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $VSB_SHA256) +$Hash = Get-FileHash $env:TEMP\vs_buildtools.exe -Algorithm sha256 +if ($Hash.Hash -eq $VSB_SHA256) { + Write-Host 'SUCCESS' +} else { + Write-Host ('FAILED ({0})' -f $Hash.Hash) + exit 1 +} +Write-Host -NoNewLine 'Installing Visual Studio Build Tools ... ' +$Process = + Start-Process $env:TEMP\vs_buildtools.exe -Wait -PassThru -NoNewWindow -ArgumentList @( + '--quiet', + '--wait', + '--norestart', + '--nocache', + '--add', 'Microsoft.VisualStudio.Component.Windows11SDK.22000', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' + ) +if ($Process.ExitCode -eq 0 -or $Process.ExitCode -eq 3010) { + Write-Host 'SUCCESS' +} else { + Write-Host ('FAILED ({0})' -f $Process.ExitCode) + exit 1 +} +Remove-Item -Force $env:TEMP\vs_buildtools.exe \ No newline at end of file diff --git a/.github/workflows/scripts/windows/swift/install-swift-5.10.ps1 b/.github/workflows/scripts/windows/swift/install-swift-5.10.ps1 new file mode 100644 index 0000000..7775354 --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift-5.10.ps1 @@ -0,0 +1,17 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +. $PSScriptRoot\install-swift.ps1 + +$SWIFT='https://download.swift.org/swift-5.10.1-release/windows10/swift-5.10.1-RELEASE/swift-5.10.1-RELEASE-windows10.exe' +$SWIFT_SHA256='3027762138ACFA1BBE3050FF6613BBE754332E84C9EFA5C23984646009297286' + +Install-Swift -Url $SWIFT -Sha256 $SWIFT_SHA256 diff --git a/.github/workflows/scripts/windows/swift/install-swift-5.9.ps1 b/.github/workflows/scripts/windows/swift/install-swift-5.9.ps1 new file mode 100644 index 0000000..2d6ae97 --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift-5.9.ps1 @@ -0,0 +1,17 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +. $PSScriptRoot\install-swift.ps1 + +$SWIFT='https://download.swift.org/swift-5.9.2-release/windows10/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-windows10.exe' +$SWIFT_SHA256='D78A717551C78E824C9B74B0CFB1AD86060FC286EA071FDDB26DF18F56DC7212' + +Install-Swift -Url $SWIFT -Sha256 $SWIFT_SHA256 \ No newline at end of file diff --git a/.github/workflows/scripts/windows/swift/install-swift-6.0.ps1 b/.github/workflows/scripts/windows/swift/install-swift-6.0.ps1 new file mode 100644 index 0000000..1a6a432 --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift-6.0.ps1 @@ -0,0 +1,17 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +. $PSScriptRoot\install-swift.ps1 + +$SWIFT='https://download.swift.org/swift-6.0.3-release/windows10/swift-6.0.3-RELEASE/swift-6.0.3-RELEASE-windows10.exe' +$SWIFT_SHA256='AB205D83A38047882DB80E6A88C7D33B651F3BAC96D4515D7CBA5335F37999D3' + +Install-Swift -Url $SWIFT -Sha256 $SWIFT_SHA256 \ No newline at end of file diff --git a/.github/workflows/scripts/windows/swift/install-swift-6.1.ps1 b/.github/workflows/scripts/windows/swift/install-swift-6.1.ps1 new file mode 100644 index 0000000..035d337 --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift-6.1.ps1 @@ -0,0 +1,17 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +. $PSScriptRoot\install-swift.ps1 + +$SWIFT='https://download.swift.org/swift-6.1.2-release/windows10/swift-6.1.2-RELEASE/swift-6.1.2-RELEASE-windows10.exe' +$SWIFT_SHA256='92a0323ed7dd333c3b05e6e0e428f3a91c77d159f6ccfc8626a996f2ace09a0b' + +Install-Swift -Url $SWIFT -Sha256 $SWIFT_SHA256 diff --git a/.github/workflows/scripts/windows/swift/install-swift-nightly-6.2.ps1 b/.github/workflows/scripts/windows/swift/install-swift-nightly-6.2.ps1 new file mode 100644 index 0000000..324bea0 --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift-nightly-6.2.ps1 @@ -0,0 +1,18 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +. $PSScriptRoot\install-swift.ps1 + +$SWIFT_RELEASE_METADATA='http://download.swift.org/swift-6.2-branch/windows10/latest-build.json' +$Release = curl.exe -sL ${SWIFT_RELEASE_METADATA} +$SWIFT_URL = "https://download.swift.org/swift-6.2-branch/windows10/$($($Release | ConvertFrom-JSON).dir)/$($($Release | ConvertFrom-JSON).download)" + +Install-Swift -Url $SWIFT_URL -Sha256 "" \ No newline at end of file diff --git a/.github/workflows/scripts/windows/swift/install-swift-nightly.ps1 b/.github/workflows/scripts/windows/swift/install-swift-nightly.ps1 new file mode 100644 index 0000000..9c0c154 --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift-nightly.ps1 @@ -0,0 +1,18 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +. $PSScriptRoot\install-swift.ps1 + +$SWIFT_RELEASE_METADATA='http://download.swift.org/development/windows10/latest-build.json' +$Release = curl.exe -sL ${SWIFT_RELEASE_METADATA} +$SWIFT_URL = "https://download.swift.org/development/windows10/$($($Release | ConvertFrom-JSON).dir)/$($($Release | ConvertFrom-JSON).download)" + +Install-Swift -Url $SWIFT_URL -Sha256 "" \ No newline at end of file diff --git a/.github/workflows/scripts/windows/swift/install-swift.ps1 b/.github/workflows/scripts/windows/swift/install-swift.ps1 new file mode 100644 index 0000000..811a53d --- /dev/null +++ b/.github/workflows/scripts/windows/swift/install-swift.ps1 @@ -0,0 +1,42 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## +function Install-Swift { + param ( + [string]$Url, + [string]$Sha256 + ) + Set-Variable ErrorActionPreference Stop + Set-Variable ProgressPreference SilentlyContinue + Write-Host -NoNewLine ('Downloading {0} ... ' -f $url) + Invoke-WebRequest -Uri $url -OutFile installer.exe + Write-Host 'SUCCESS' + Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $Sha256) + $Hash = Get-FileHash installer.exe -Algorithm sha256 + if ($Hash.Hash -eq $Sha256 -or $Sha256 -eq "") { + Write-Host 'SUCCESS' + } else { + Write-Host ('FAILED ({0})' -f $Hash.Hash) + exit 1 + } + Write-Host -NoNewLine 'Installing Swift ... ' + $Process = Start-Process installer.exe -Wait -PassThru -NoNewWindow -ArgumentList @( + '/quiet', + '/norestart' + ) + if ($Process.ExitCode -eq 0) { + Write-Host 'SUCCESS' + } else { + Write-Host ('FAILED ({0})' -f $Process.ExitCode) + exit 1 + } + Remove-Item -Force installer.exe +} \ No newline at end of file diff --git a/.github/workflows/soundness.yml b/.github/workflows/soundness.yml index f6bc36e..6c7d187 100644 --- a/.github/workflows/soundness.yml +++ b/.github/workflows/soundness.yml @@ -7,6 +7,14 @@ on: type: boolean description: "Boolean to enable the API breakage check job. Defaults to true." default: true + api_breakage_check_allowlist_path: + type: string + description: "Path to a file that will be passed as --breakage-allowlist-path to swift package diagnose-api-breaking-changes" + default: "" + api_breakage_check_baseline: + type: string + description: "The tag against which API breakages that should be used as the baseline for the API breakage check. By default the PR base is used." + default: "" api_breakage_check_container_image: type: string description: "Container image for the API breakage check job. Defaults to latest Swift Ubuntu image." @@ -19,6 +27,10 @@ on: type: string description: "Container image for the docs check job. Defaults to latest Swift Ubuntu image." default: "swift:6.0-noble" + docs_check_additional_arguments: + type: string + description: "Additional arguments that should be passed to docc" + default: "" unacceptable_language_check_enabled: type: boolean description: "Boolean to enable the acceptable language check job. Defaults to true." @@ -26,15 +38,15 @@ on: unacceptable_language_check_word_list: type: string description: "List of unacceptable words. Defaults to a sensible list of words." - default: "blacklist whitelist slave master sane sanity insane insanity kill killed killing hang hung hanged hanging" #ignore-unacceptable-language + default: "blacklist whitelist slave master sane sanity insane insanity kill killed killing hang hung hanged hanging" # ignore-unacceptable-language license_header_check_enabled: type: boolean description: "Boolean to enable the license header check job. Defaults to true." default: true license_header_check_project_name: type: string - description: "Name of the project called out in the license header." - required: true + description: "Name of the project called out in the license header. Required unless `license_header_check_enabled` is false or a `.license_header_template` file is present." + default: "" broken_symlink_check_enabled: type: boolean description: "Boolean to enable the broken symlink check job. Defaults to true." @@ -43,6 +55,10 @@ on: type: boolean description: "Boolean to enable the format check job. Defaults to true." default: true + format_check_container_image: + type: string + description: "Container image for the format check job. Defaults to latest Swift Ubuntu image." + default: "swift:6.0-noble" shell_check_enabled: type: boolean description: "Boolean to enable the shell check job. Defaults to true." @@ -51,12 +67,24 @@ on: type: string description: "Container image for the shell check job. Defaults to latest Swift Ubuntu image." default: "swift:6.0-noble" + yamllint_check_enabled: + type: boolean + description: "Boolean to enable the YAML lint check job. Defaults to true." + default: true + python_lint_check_enabled: + type: boolean + description: "Boolean to enable the Python lint check job. Defaults to true." + default: true + linux_pre_build_command: + type: string + description: "Linux command to execute before building the Swift package" + default: "" ## We are cancelling previously triggered workflow runs concurrency: group: ${{ github.workflow }}-${{ github.ref }}-soundness cancel-in-progress: true - + jobs: api-breakage-check: name: API breakage check @@ -66,17 +94,37 @@ jobs: image: ${{ inputs.api_breakage_check_container_image }} timeout-minutes: 20 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - persist-credentials: false - - name: Mark the workspace as safe - # https://github.com/actions/checkout/issues/766 - run: git config --global --add safe.directory ${GITHUB_WORKSPACE} - - name: Run API breakage check - run: | - git fetch ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} ${GITHUB_BASE_REF}:pull-base-ref - swift package diagnose-api-breaking-changes pull-base-ref + - name: Checkout repository + 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 + # private repos. + persist-credentials: true + submodules: true + fetch-tags: true + fetch-depth: 0 # Fetching tags requires fetch-depth: 0 (https://github.com/actions/checkout/issues/1471) + - name: Mark the workspace as safe + # https://github.com/actions/checkout/issues/766 + run: git config --global --add safe.directory ${GITHUB_WORKSPACE} + - name: Pre-build + if: ${{ inputs.linux_pre_build_command }} + run: ${{ inputs.linux_pre_build_command }} + - name: Run API breakage check + shell: bash + run: | + if [[ -z '${{ inputs.api_breakage_check_baseline }}' ]]; then + git fetch ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} ${GITHUB_BASE_REF}:pull-base-ref + BASELINE_REF='pull-base-ref' + else + BASELINE_REF='${{ inputs.api_breakage_check_baseline }}' + fi + echo "Using baseline: $BASELINE_REF" + if [[ -z '${{ inputs.api_breakage_check_allowlist_path }}' ]]; then + swift package diagnose-api-breaking-changes "$BASELINE_REF" + else + swift package diagnose-api-breaking-changes "$BASELINE_REF" --breakage-allowlist-path '${{ inputs.api_breakage_check_allowlist_path }}' + fi docs-check: name: Documentation check @@ -86,14 +134,20 @@ jobs: image: ${{ inputs.docs_check_container_image }} timeout-minutes: 20 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: + - name: Checkout repository + uses: actions/checkout@v4 + with: persist-credentials: false - - name: Run documentation check - run: | - apt-get -qq update && apt-get -qq -y install curl yq - curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-docs.sh | bash + submodules: true + - 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 }} + run: | + which curl yq || (apt -q update && apt -yq install curl yq) + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-docs.sh | bash unacceptable-language-check: name: Unacceptable language check @@ -101,14 +155,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 1 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: + - name: Checkout repository + uses: actions/checkout@v4 + with: persist-credentials: false - - name: Run unacceptable language check - env: - UNACCEPTABLE_WORD_LIST: ${{ inputs.unacceptable_language_check_word_list}} - run: curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-unacceptable-language.sh | bash + submodules: true + - name: Run unacceptable language check + env: + UNACCEPTABLE_WORD_LIST: ${{ inputs.unacceptable_language_check_word_list}} + run: curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-unacceptable-language.sh | bash license-header-check: name: License headers check @@ -116,14 +171,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 1 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: + - name: Checkout repository + uses: actions/checkout@v4 + with: persist-credentials: false - - name: Run license header check - env: - PROJECT_NAME: ${{ inputs.license_header_check_project_name }} - run: curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-license-header.sh | bash + submodules: true + - name: Run license header check + env: + PROJECT_NAME: ${{ inputs.license_header_check_project_name }} + run: curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-license-header.sh | bash broken-symlink-check: name: Broken symlinks check @@ -131,32 +187,34 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 1 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: + - name: Checkout repository + uses: actions/checkout@v4 + with: persist-credentials: false - - name: Run broken symlinks check - run: curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-broken-symlinks.sh | bash + submodules: true + - name: Run broken symlinks check + run: curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-broken-symlinks.sh | bash format-check: name: Format check if: ${{ inputs.format_check_enabled }} runs-on: ubuntu-latest container: - image: swiftlang/swift:nightly-6.0-jammy - timeout-minutes: 10 + image: ${{ inputs.format_check_container_image }} + timeout-minutes: 20 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: + - name: Checkout repository + uses: actions/checkout@v4 + with: persist-credentials: false - - 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 - run: | - apt-get -qq update && apt-get -qq -y install curl - curl -s https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-swift-format.sh | bash + submodules: true + - 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 + run: | + which curl || (apt -q update && apt -yq install curl) + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/check-swift-format.sh | bash shell-check: name: Shell check @@ -166,14 +224,57 @@ jobs: image: ${{ inputs.shell_check_container_image }} timeout-minutes: 5 steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: true + - name: Mark the workspace as safe + # https://github.com/actions/checkout/issues/766 + run: git config --global --add safe.directory ${GITHUB_WORKSPACE} + - name: Run shellcheck + run: | + which shellcheck || (apt -q update && apt -yq install shellcheck) + git ls-files -z '*.sh' | xargs -0 --no-run-if-empty shellcheck + + yaml-lint-check: + name: YAML lint check + if: ${{ inputs.yamllint_check_enabled }} + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: true + - name: Run yamllint + run: | + which yamllint || (apt -q update && apt install -yq yamllint) + cd ${GITHUB_WORKSPACE} + if [ ! -f ".yamllint.yml" ]; then + echo "Downloading default yamllint config file" + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/configs/yamllint.yml > .yamllint.yml + fi + yamllint --strict --config-file .yamllint.yml . + + python-lint-check: + name: Python lint check + if: ${{ inputs.python_lint_check_enabled }} + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: persist-credentials: false - - name: Mark the workspace as safe - # https://github.com/actions/checkout/issues/766 - run: git config --global --add safe.directory ${GITHUB_WORKSPACE} - - name: Run shellcheck - run: | - apt-get -qq update && apt-get -qq -y install shellcheck - git ls-files -z '*.sh' | xargs -0 shellcheck + submodules: true + - name: Run flake8 + run: | + pip3 install flake8 flake8-import-order + cd ${GITHUB_WORKSPACE} + if [ ! -f ".flake8" ]; then + echo "Downloading default flake8 config file" + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/configs/.flake8 > .flake8 + fi + flake8 diff --git a/.github/workflows/swift_package_test.yml b/.github/workflows/swift_package_test.yml index a305a13..aaf0669 100644 --- a/.github/workflows/swift_package_test.yml +++ b/.github/workflows/swift_package_test.yml @@ -1,16 +1,57 @@ -name: Swift Linux Matrix +name: Swift Matrix on: workflow_call: inputs: - exclude_swift_versions: + macos_xcode_versions: type: string - description: "Exclude Swift version list (JSON)" + description: "Xcode version list (JSON)" + default: "[\"16.2\", \"16.3\"]" + macos_exclude_xcode_versions: + type: string + description: "Exclude Xcode version list (JSON)" + default: "[{\"xcode_version\": \"\"}]" + macos_versions: + type: string + description: "macOS version list (JSON)" + default: "[\"sequoia\"]" + macos_archs: + type: string + description: "macOS arch list (JSON)" + default: "[\"ARM64\"]" + linux_swift_versions: + type: string + description: "Include Linux Swift version list (JSON)" + default: "[ \"5.9\", \"5.10\", \"6.0\", \"6.1\", \"nightly-main\", \"nightly-6.2\"]" + linux_exclude_swift_versions: + type: string + description: "Exclude Linux Swift version list (JSON)" default: "[{\"swift_version\": \"\"}]" - os_versions: + linux_os_versions: type: string - description: "OS version list (JSON)" + description: "Linux OS version list (JSON)" default: "[\"jammy\"]" + linux_static_sdk_versions: + type: string + description: "Static Linux Swift SDK version list (JSON)" + default: "[\"nightly-6.2\"]" + wasm_sdk_versions: + type: string + description: "Wasm Swift SDK version list (JSON)" + default: "[\"nightly-main\", \"nightly-6.2\"]" + wasm_exclude_swift_versions: + type: string + description: "Exclude Wasm Swift SDK version list (JSON)" + default: "[{\"swift_version\": \"\"}]" + windows_swift_versions: + type: string + description: "Include Windows Swift version list (JSON)" + # "5.10" is omitted for Windows because the container image is broken. + default: "[\"5.9\", \"6.0\", \"6.1\", \"nightly\", \"nightly-6.2\"]" + windows_exclude_swift_versions: + type: string + description: "Exclude Windows Swift version list (JSON)" + default: "[{\"swift_version\": \"\"}]" swift_flags: type: string description: "Swift flags for release version" @@ -19,44 +60,409 @@ on: type: string description: "Swift flags for nightly version" default: "" - pre_build_command: + linux_pre_build_command: + type: string + description: "Linux command to execute before building the Swift package" + default: "" + linux_static_sdk_pre_build_command: + type: string + description: "Linux command to execute before building the Swift package with the Static Linux Swift SDK" + default: "" + wasm_sdk_pre_build_command: type: string - description: "Command to execute before building the Swift package" + description: "Linux command to execute before building the Swift package with the Embedded Swift SDK for Wasm" default: "" - build_command: + macos_pre_build_command: type: string - description: "Build command default is swift test" + description: "macOS command to execute before building the Swift package" + default: "" + macos_build_command: + type: string + description: "macOS command to build and test the package" + default: "xcrun swift test" + linux_build_command: + type: string + description: "Linux command to build and test the package" default: "swift test" - env_vars: - description: "List of environment variables" + linux_static_sdk_build_command: + type: string + description: "Command to use when building the package with the Static Linux Swift SDK" + default: "swift build" + wasm_sdk_build_command: + type: string + description: "Command to use when building the package with the Swift SDK for Wasm" + default: "swift build" + windows_pre_build_command: + type: string + description: "Windows Command Prompt command to execute before building the Swift package" + default: "" + windows_build_command: + type: string + description: | + Windows Command Prompt command to build and test the package. + Note that Powershell does not automatically exit if a subcommand fails. The Invoke-Program utility is available to propagate non-zero exit codes. + It is strongly encouraged to run all command using `Invoke-Program` unless you want to continue on error eg. `Invoke-Program git apply patch.diff` instead of `git apply patch.diff`. + default: "Invoke-Program swift test" + macos_env_vars: + description: "Newline separated list of environment variables" + type: string + linux_env_vars: + description: "Newline separated list of environment variables" type: string + windows_env_vars: + description: "Newline separated list of environment variables" + type: string + enable_linux_checks: + type: boolean + description: "Boolean to enable linux testing. Defaults to true" + default: true + enable_linux_static_sdk_build: + type: boolean + description: "Boolean to enable building with the Static Linux Swift SDK. Defaults to false" + default: false + enable_wasm_sdk_build: + type: boolean + description: "Boolean to enable building with the Swift SDK for Wasm. Defaults to false" + default: false + enable_embedded_wasm_sdk_build: + type: boolean + description: "Boolean to enable building with the Embedded Swift SDK for Wasm. Defaults to false" + default: false + enable_macos_checks: + type: boolean + description: "Boolean to enable macOS testing. Defaults to false" + default: false + enable_windows_checks: + type: boolean + description: "Boolean to enable windows testing. Defaults to true" + default: true + enable_windows_docker: + type: boolean + description: "Boolean to enable running build in windows docker container. Defaults to true" + default: true + needs_token: + type: boolean + description: "Boolean to enable providing the GITHUB_TOKEN to downstream job." + default: false jobs: - build: + macos-build: + name: macOS (Xcode ${{ matrix.xcode_version }} - ${{ matrix.os_version }} - ${{ matrix.arch }}) + if: ${{ inputs.enable_macos_checks }} + runs-on: [self-hosted, macos, "${{ matrix.os_version }}", "${{ matrix.arch }}"] + strategy: + fail-fast: false + matrix: + xcode_version: ${{ fromJson(inputs.macos_xcode_versions) }} + os_version: ${{ fromJson(inputs.macos_versions) }} + arch: ${{ fromJson(inputs.macos_archs) }} + exclude: + - ${{ fromJson(inputs.macos_exclude_xcode_versions) }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Provide token + if: ${{ inputs.needs_token }} + run: | + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + - name: Set environment variables + if: ${{ inputs.macos_env_vars }} + run: | + for i in "${{ inputs.macos_env_vars }}" + do + printf "%s\n" $i >> $GITHUB_ENV + done + - name: Select Xcode + run: echo "DEVELOPER_DIR=/Applications/Xcode_${{ matrix.xcode_version }}.app" >> $GITHUB_ENV + - name: Swift version + run: xcrun swift --version + - name: Pre-build + run: ${{ inputs.macos_pre_build_command }} + - name: Build / Test + run: ${{ inputs.macos_build_command }} ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + timeout-minutes: 60 + + linux-build: name: Linux (${{ matrix.swift_version }} - ${{ matrix.os_version }}) + if: ${{ inputs.enable_linux_checks }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: - swift_version: ['5.8', '5.9', '5.10', '6.0', 'nightly-main', 'nightly-6.0'] - os_version: ${{ fromJson(inputs.os_versions) }} + swift_version: ${{ fromJson(inputs.linux_swift_versions) }} + os_version: ${{ fromJson(inputs.linux_os_versions) }} exclude: - - ${{ fromJson(inputs.exclude_swift_versions) }} + - ${{ fromJson(inputs.linux_exclude_swift_versions) }} container: image: ${{ (contains(matrix.swift_version, 'nightly') && 'swiftlang/swift') || 'swift' }}:${{ matrix.swift_version }}-${{ matrix.os_version }} steps: - - name: Swift version - run: swift --version - - name: Checkout repository - uses: actions/checkout@v4 - - name: Set environment variables - if: ${{ inputs.env_vars }} - run: | - for i in "${{ inputs.env_vars }}" - do - printf "%s\n" $i >> $GITHUB_ENV - done - - name: Pre-build - run: ${{ inputs.pre_build_command }} - - name: Build / Test - run: ${{ inputs.build_command }} ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + - name: Swift version + run: swift --version + - name: Checkout repository + uses: actions/checkout@v4 + if: ${{ matrix.os_version != 'amazonlinux2' }} + - name: Checkout repository + uses: actions/checkout@v1 + if: ${{ matrix.os_version == 'amazonlinux2' }} + - name: Provide token + if: ${{ inputs.needs_token }} + run: | + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + - name: Set environment variables + if: ${{ inputs.linux_env_vars }} + run: | + for i in "${{ inputs.linux_env_vars }}" + do + printf "%s\n" $i >> $GITHUB_ENV + done + - name: Pre-build + run: ${{ inputs.linux_pre_build_command }} + - name: Build / Test + run: ${{ inputs.linux_build_command }} ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + + linux-static-sdk-build: + name: Static Linux Swift SDK Build (${{ matrix.swift_version }} - ${{ matrix.os_version }}) + if: ${{ inputs.enable_linux_static_sdk_build }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + swift_version: ${{ fromJson(inputs.linux_static_sdk_versions) }} + os_version: ${{ fromJson(inputs.linux_os_versions) }} + container: + image: ${{ (contains(matrix.swift_version, 'nightly') && 'swiftlang/swift') || 'swift' }}:${{ matrix.swift_version }}-${{ matrix.os_version }} + steps: + - name: Swift version + run: swift --version + - name: Checkout repository + uses: actions/checkout@v4 + if: ${{ matrix.os_version != 'amazonlinux2' }} + - name: Checkout repository + uses: actions/checkout@v1 + if: ${{ matrix.os_version == 'amazonlinux2' }} + - name: Provide token + if: ${{ inputs.needs_token }} + run: | + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + - name: Set environment variables + if: ${{ inputs.linux_env_vars }} + run: | + for i in "${{ inputs.linux_env_vars }}" + do + printf "%s\n" $i >> $GITHUB_ENV + done + - name: Pre-build + run: ${{ inputs.linux_pre_build_command }} + - name: Install Static Linux Swift SDK and build + env: + BUILD_FLAGS: ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + run: | + ${{ inputs.linux_static_sdk_pre_build_command }} + if command -v apt-get >/dev/null 2>&1 ; then # bookworm, noble, jammy, focal + apt-get -q update && apt-get -yq install curl + elif command -v dnf >/dev/null 2>&1 ; then # rhel-ubi9 + dnf -y update + dnf -y install curl-minimal + elif command -v yum >/dev/null 2>&1 ; then # amazonlinux2 + yum -y update + yum -y install curl + else + echo "Unknown package manager (tried apt-get, dnf, yum)" >&2 + exit 1 + fi + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/install-and-build-with-sdk.sh | \ + bash -s -- --static --flags="$BUILD_FLAGS" --build-command="${{ inputs.linux_static_sdk_build_command }}" ${{ matrix.swift_version }} + + wasm-sdk-build: + name: Swift SDK for Wasm Build (${{ matrix.swift_version }} - ${{ matrix.os_version }}) + if: ${{ inputs.enable_wasm_sdk_build }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + swift_version: ${{ fromJson(inputs.wasm_sdk_versions) }} + os_version: ${{ fromJson(inputs.linux_os_versions) }} + exclude: + - ${{ fromJson(inputs.wasm_exclude_swift_versions) }} + container: + image: ${{ (contains(matrix.swift_version, 'nightly') && 'swiftlang/swift') || 'swift' }}:${{ matrix.swift_version }}-${{ matrix.os_version }} + steps: + - name: Swift version + run: swift --version + - name: Checkout repository + uses: actions/checkout@v4 + if: ${{ matrix.os_version != 'amazonlinux2' }} + - name: Checkout repository + uses: actions/checkout@v1 + if: ${{ matrix.os_version == 'amazonlinux2' }} + - name: Provide token + if: ${{ inputs.needs_token }} + run: | + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + - name: Set environment variables + if: ${{ inputs.linux_env_vars }} + run: | + for i in "${{ inputs.linux_env_vars }}" + do + printf "%s\n" $i >> $GITHUB_ENV + done + - name: Pre-build + run: ${{ inputs.linux_pre_build_command }} + - name: Install Swift SDK for Wasm and build + env: + BUILD_FLAGS: ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + run: | + ${{ inputs.wasm_sdk_pre_build_command }} + if command -v apt-get >/dev/null 2>&1 ; then # bookworm, noble, jammy, focal + apt-get -q update && apt-get -yq install curl + elif command -v dnf >/dev/null 2>&1 ; then # rhel-ubi9 + dnf -y update + dnf -y install curl-minimal + elif command -v yum >/dev/null 2>&1 ; then # amazonlinux2 + yum -y update + yum -y install curl + else + echo "Unknown package manager (tried apt-get, dnf, yum)" >&2 + exit 1 + fi + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/install-and-build-with-sdk.sh | \ + bash -s -- --wasm --flags="$BUILD_FLAGS" --build-command="${{ inputs.wasm_sdk_build_command }}" ${{ matrix.swift_version }} + + embedded-wasm-sdk-build: + name: Embedded Swift SDK for Wasm Build (${{ matrix.swift_version }} - ${{ matrix.os_version }}) + if: ${{ inputs.enable_embedded_wasm_sdk_build }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + swift_version: ${{ fromJson(inputs.wasm_sdk_versions) }} + os_version: ${{ fromJson(inputs.linux_os_versions) }} + exclude: + - ${{ fromJson(inputs.wasm_exclude_swift_versions) }} + container: + image: ${{ (contains(matrix.swift_version, 'nightly') && 'swiftlang/swift') || 'swift' }}:${{ matrix.swift_version }}-${{ matrix.os_version }} + steps: + - name: Swift version + run: swift --version + - name: Checkout repository + uses: actions/checkout@v4 + - name: Provide token + if: ${{ inputs.needs_token }} + run: | + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + - name: Set environment variables + if: ${{ inputs.linux_env_vars }} + run: | + for i in "${{ inputs.linux_env_vars }}" + do + printf "%s\n" $i >> $GITHUB_ENV + done + - name: Pre-build + run: ${{ inputs.linux_pre_build_command }} + - name: Install Swift SDK for Wasm and build + env: + BUILD_FLAGS: ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + run: | + ${{ inputs.wasm_sdk_pre_build_command }} + if command -v apt-get >/dev/null 2>&1 ; then # bookworm, noble, jammy, focal + apt-get -q update && apt-get -yq install curl + elif command -v dnf >/dev/null 2>&1 ; then # rhel-ubi9 + dnf -y update + dnf -y install curl-minimal + elif command -v yum >/dev/null 2>&1 ; then # amazonlinux2 + yum -y update + yum -y install curl + else + echo "Unknown package manager (tried apt-get, dnf, yum)" >&2 + exit 1 + fi + curl -s --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/install-and-build-with-sdk.sh | \ + bash -s -- --embedded-wasm --flags="$BUILD_FLAGS" ${{ matrix.swift_version }} + + windows-build: + name: Windows (${{ matrix.swift_version }} - windows-2022) + if: ${{ inputs.enable_windows_checks }} + runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + swift_version: ${{ fromJson(inputs.windows_swift_versions) }} + exclude: + - ${{ fromJson(inputs.windows_exclude_swift_versions) }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Provide token + if: ${{ inputs.needs_token }} + run: | + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + - name: Set environment variables + if: ${{ inputs.windows_env_vars }} + run: | + $lines = "${{ inputs.windows_env_vars }}" -split "`r`n" + foreach ($line in $lines) { + echo $line | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + } + - name: Pull Docker image + id: pull_docker_image + if: ${{ inputs.enable_windows_docker }} + run: | + if ("${{ matrix.swift_version }}".Contains("nightly")) { + $Image = "swiftlang/swift:${{ matrix.swift_version }}-windowsservercore-ltsc2022" + } else { + $Image = "swift:${{ matrix.swift_version }}-windowsservercore-ltsc2022" + } + docker pull $Image + echo "image=$Image" >> "$env:GITHUB_OUTPUT" + - name: Install Visual Studio Build Tools + if: ${{ !inputs.enable_windows_docker }} + run: | + Invoke-WebRequest -Uri https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/windows/install-vsb.ps1 -OutFile $env:TEMP\install-vsb.ps1 + . $env:TEMP\install-vsb.ps1 + del $env:TEMP\install-vsb.ps1 + - name: Install Swift + if: ${{ !inputs.enable_windows_docker }} + run: | + Invoke-WebRequest -Uri https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/windows/swift/install-swift.ps1 -OutFile $env:TEMP\install-swift.ps1 + Invoke-WebRequest -Uri https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/windows/swift/install-swift-${{ matrix.swift_version }}.ps1 -OutFile $env:TEMP\install-swift-${{ matrix.swift_version }}.ps1 + . $env:TEMP\install-swift-${{ matrix.swift_version }}.ps1 + del $env:TEMP\install-swift*.ps1 + - name: Create test script + run: | + mkdir $env:TEMP\test-script + echo @' + Set-PSDebug -Trace 1 + if ("${{ inputs.enable_windows_docker }}" -eq "true") { + $Source = "C:\source" + } else { + $Source = $env:GITHUB_WORKSPACE + } + + # Run the command following `Invoke-Program`. + # If that command returns a non-zero exit code, return the same exit code from this script. + function Invoke-Program($Executable) { + & $Executable @args + if ($LastExitCode -ne 0) { + exit $LastExitCode + } + } + Invoke-Program swift --version + Invoke-Program swift test --version + Invoke-Program cd $Source + ${{ inputs.windows_pre_build_command }} + ${{ inputs.windows_build_command }} ${{ (contains(matrix.swift_version, 'nightly') && inputs.swift_nightly_flags) || inputs.swift_flags }} + '@ >> $env:TEMP\test-script\run.ps1 + # Docker build + - name: Docker Build / Test + timeout-minutes: 60 + if: ${{ inputs.enable_windows_docker }} + run: | + docker run -v ${{ github.workspace }}:C:\source -v $env:TEMP\test-script:C:\test-script ${{ steps.pull_docker_image.outputs.image }} powershell.exe -NoLogo -File C:\test-script\run.ps1 + # Docker-less build + - name: Build / Test + timeout-minutes: 60 + if: ${{ !inputs.enable_windows_docker }} + run: | + Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 + RefreshEnv + powershell.exe -NoLogo -File $env:TEMP\test-script\run.ps1; exit $LastExitCode diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/.license_header_template b/.license_header_template new file mode 100644 index 0000000..309ac5a --- /dev/null +++ b/.license_header_template @@ -0,0 +1,11 @@ +@@===----------------------------------------------------------------------===@@ +@@ +@@ This source file is part of the Swift.org open source project +@@ +@@ Copyright (c) YEARS 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 +@@ +@@===----------------------------------------------------------------------===@@ diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 0000000..a37bae2 --- /dev/null +++ b/.licenseignore @@ -0,0 +1,5 @@ +.github/workflows/configs/.flake8 +**/*.yml +CODEOWNERS +LICENSE.txt +README.md diff --git a/CODEOWNERS b/CODEOWNERS index 4ffad00..a509381 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,4 +8,4 @@ # See https://swift.org/CONTRIBUTORS.txt for Swift project authors # -* @shahmishal +* @swiftlang/github-workflows-contributors diff --git a/README.md b/README.md index 2d04872..bb39448 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,48 @@ # GitHub Actions Workflows -This repository will contain reusable workflows to minimize redundant workflows across the organization. This effort will also facilitate the standardization of testing processes while empowering repository code owners to customize their testing plans as needed. The repository will contain workflows to support different types of repositories, such as Swift Package and Swift Compiler. +This repository will contain reusable workflows to minimize redundant workflows +across the organization. This effort will also facilitate the standardization of +testing processes while empowering repository code owners to customize their +testing plans as needed. The repository will contain workflows to support +different types of repositories, such as Swift Package and Swift Compiler. -For more details on reusable workflows, please refer to the [Reusing workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) section in the GitHub Docs. +For more details on reusable workflows, please refer to the [Reusing +workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) +section in the GitHub Docs. ## Reusable workflow for Swift package repositories -To enable pull request testing for all supported Swift versions (5.8, 5.9, 5.10, 6.0, and nightly) on Linux, add the following code example in `.github/workflows/pull_request.yml`: +There are different kinds of workflows that this repository offers: + +### Soundness + +The soundness workflows provides a multitude of checks to ensure a repository is +following the best practices. By default each check is enabled but can be +disabled by passing the appropriate workflow input. We recommend to adopt all +soundness checks and enforce them on each PR. + +A recommended workflow looks like this: + +```yaml +name: Pull request + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + license_header_check_project_name: "Swift.org" +``` + +### Testing + +To enable pull request testing for all supported Swift versions (5.9, 5.10, +6.0, 6.1, nightly, and nightly-6.1) on Linux and Windows, add the following code example in +`.github/workflows/pull_request.yml`: ```yaml name: pull_request @@ -21,16 +57,55 @@ jobs: uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main ``` -If your package only supports newer compiler versions, you can exclude older versions by using the `exclude_swift_versions` workflow input: +If your package only supports newer compiler versions, you can exclude older +versions by using the `*_exclude_swift_versions` workflow input: ```yaml -exclude_swift_versions: "[{\"swift_version\": \"5.8\"}]" +linux_exclude_swift_versions: "[{\"swift_version\": \"5.9\"}]" +windows_exclude_swift_versions: "[{\"swift_version\": \"5.9\"}]" ``` -Additionally, if your package requires additional installed packages, you can use the `pre_build_command`: +Additionally, if your package requires additional installed packages, you can +use the `pre_build_command`. For example, to install a package called +`example`: ```yaml -pre_build_command: "apt-get update -y -q && apt-get install -y -q example" +pre_build_command: "which example || (apt update -q && apt install -yq example" ``` -macOS and Windows platform support will be available soon. +macOS platform support will be available soon. + +## Running workflows locally + +You can run the Github Actions workflows locally using +[act](https://github.com/nektos/act). To run all the jobs that run on a pull +request, use the following command: + +```bash +% act pull_request +``` + +To run just a single job, use `workflow_call -j `, and specify the inputs +the job expects. For example, to run just shellcheck: + +```bash +% act workflow_call -j soundness --input shell_check_enabled=true +``` + +To bind-mount the working directory to the container, rather than a copy, use +`--bind`. For example, to run just the formatting, and have the results +reflected in your working directory: + +```bash +% act --bind workflow_call -j soundness --input format_check_enabled=true +``` + +If you'd like `act` to always run with certain flags, these can be be placed in +an `.actrc` file either in the current working directory or your home +directory, for example: + +```bash +--container-architecture=linux/amd64 +--remote-name upstream +--action-offline-mode +``` diff --git a/tests/test.ps1 b/tests/test.ps1 new file mode 100644 index 0000000..bea258d --- /dev/null +++ b/tests/test.ps1 @@ -0,0 +1,11 @@ +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 0000000..7c4470b --- /dev/null +++ b/tests/test.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===##