diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..728893b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{sh,swift-format,yaml}] +indent_size = 2 diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml new file mode 100644 index 0000000..b5fdc31 --- /dev/null +++ b/.github/workflows/pull-request.yaml @@ -0,0 +1,14 @@ +name: Pull request + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + soundness: + name: Soundness + uses: ./.github/workflows/soundness.yaml + + unit_test: + name: Unit Test + uses: ./.github/workflows/unit-test.yaml diff --git a/.github/workflows/soundness.yaml b/.github/workflows/soundness.yaml new file mode 100644 index 0000000..3789c31 --- /dev/null +++ b/.github/workflows/soundness.yaml @@ -0,0 +1,42 @@ +name: Soundness +on: + workflow_call: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-soundness + cancel-in-progress: true +jobs: + unacceptable-language-check: + name: Unacceptable language check + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run unacceptable language check + run: ./scripts/check-unacceptable-language.sh + + license-header-check: + name: License headers check + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run license header check + run: ./scripts/check-license-headers.sh + + format-check: + name: Format check + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install Swift + uses: vapor/swiftly-action@v0.1 + with: + toolchain: latest + env: + SWIFTLY_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run format check + run: ./scripts/check-swift-format.sh diff --git a/.github/workflows/unit-test.yaml b/.github/workflows/unit-test.yaml new file mode 100644 index 0000000..1132960 --- /dev/null +++ b/.github/workflows/unit-test.yaml @@ -0,0 +1,30 @@ +name: Unit Test +on: + workflow_call: + push: + branches: [main] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-unit-test + cancel-in-progress: true +jobs: + unit-test: + name: Unit Test + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + toolchain: [latest] + steps: + - name: Install Swift + uses: vapor/swiftly-action@v0.1 + with: + toolchain: ${{ matrix.toolchain }} + env: + SWIFTLY_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Checkout + uses: actions/checkout@v4.2.2 + - name: Resolve Swift dependencies + run: swift package resolve + - name: Run Unit Tests + run: swift test --parallel --enable-code-coverage diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..619cef7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +.build/ +.swiftpm/ +Package.resolved +xcuserdata/ +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings +.vscode/ diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 0000000..adbc119 --- /dev/null +++ b/.licenseignore @@ -0,0 +1,9 @@ +.gitignore +.licenseignore +.unacceptablelanguageignore +.swift-format +.editorconfig +*.md +*.txt +*.yaml +Package.swift diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..7fa06fb --- /dev/null +++ b/.swift-format @@ -0,0 +1,62 @@ +{ + "version" : 1, + "indentation" : { + "spaces" : 4 + }, + "tabWidth" : 4, + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "spacesAroundRangeFormationOperators" : false, + "indentConditionalCompilationBlocks" : false, + "indentSwitchCaseLabels" : false, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : true, + "lineBreakBeforeEachGenericRequirement" : true, + "lineLength" : 120, + "maximumBlankLines" : 1, + "respectsExistingLineBreaks" : true, + "prioritizeKeepingFunctionOutputTogether" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : false, + "AmbiguousTrailingClosureOverload" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : true, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : false, + "UseLetInEveryBoundCaseVariable" : false, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : false, + "UseSynthesizedInitializer" : false, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + } +} diff --git a/.unacceptablelanguageignore b/.unacceptablelanguageignore new file mode 100644 index 0000000..f36b317 --- /dev/null +++ b/.unacceptablelanguageignore @@ -0,0 +1 @@ +scripts/check-unacceptable-language.sh diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..4cc38c2 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [swift-open-feature@slashmo.codes](mailto:swift-open-feature@slashmo.codes). +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 0000000..107c64a --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift OpenFeature open source project +// +// Copyright (c) 2024 the Swift OpenFeature project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + + The Swift OpenFeature Project + ============================= + +Please visit the Swift OpenFeature web site for more information: + + * https://github.com/swift-open-feature/swift-open-feature + +Copyright 2024 The Swift OpenFeature Project + +The Swift OpenFeature Project licenses this file to you under the Apache +License, version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at: + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations +under the License. + +Also, please refer to each LICENSE.txt file, which is located in +the 'license' directory of the distribution file, for the license terms of the +components that this product depends on. + +------------------------------------------------------------------------------- + +This product contains derivations of various scripts and templates from Swift. + + * LICENSE (Apache License 2.0): + * https://www.apache.org/licenses/LICENSE-2.0 + * HOMEPAGE: + * https://github.com/swiftlang/github-workflows + +--- diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..8e79305 --- /dev/null +++ b/Package.swift @@ -0,0 +1,33 @@ +// swift-tools-version:6.0 +import PackageDescription + +let package = Package( + name: "swift-flagd", + platforms: [ + .macOS(.v10_15), + .iOS(.v13), + .watchOS(.v6), + .tvOS(.v13), + ], + products: [ + .library(name: "Flagd", targets: ["Flagd"]) + ], + dependencies: [ + .package(url: "https://github.com/swift-open-feature/swift-open-feature.git", branch: "main") + ], + targets: [ + .target( + name: "Flagd", + dependencies: [ + .product(name: "OpenFeature", package: "swift-open-feature") + ] + ), + .testTarget( + name: "FlagdTests", + dependencies: [ + .target(name: "Flagd") + ] + ), + ], + swiftLanguageModes: [.v6] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..b270129 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Swift flagd + +[![Unit Test](https://github.com/swift-open-feature/swift-flagd/actions/workflows/unit-test.yaml/badge.svg)](https://github.com/swift-open-feature/swift-flagd/actions/workflows/unit-test.yaml) + +A cross-platform [flagd](https://flagd.dev) provider for Swift, +based on [Swift OpenFeature](https://github.com/swift-open-feature/swift-open-feature). diff --git a/Sources/Flagd/FlagdProvider.swift b/Sources/Flagd/FlagdProvider.swift new file mode 100644 index 0000000..16a6215 --- /dev/null +++ b/Sources/Flagd/FlagdProvider.swift @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift OpenFeature open source project +// +// Copyright (c) 2024 the Swift OpenFeature project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// diff --git a/Tests/FlagdTests/FlagdProviderTests.swift b/Tests/FlagdTests/FlagdProviderTests.swift new file mode 100644 index 0000000..16a6215 --- /dev/null +++ b/Tests/FlagdTests/FlagdProviderTests.swift @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift OpenFeature open source project +// +// Copyright (c) 2024 the Swift OpenFeature project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// diff --git a/scripts/check-license-headers.sh b/scripts/check-license-headers.sh new file mode 100755 index 0000000..a8091cd --- /dev/null +++ b/scripts/check-license-headers.sh @@ -0,0 +1,109 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift OpenFeature open source project +## +## Copyright (c) 2024 the Swift OpenFeature project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +expected_file_header_template="@@===----------------------------------------------------------------------===@@ +@@ +@@ This source file is part of the Swift OpenFeature open source project +@@ +@@ Copyright (c) YEARS the Swift OpenFeature project authors +@@ Licensed under Apache License v2.0 +@@ +@@ See LICENSE.txt for license information +@@ +@@ SPDX-License-Identifier: Apache-2.0 +@@ +@@===----------------------------------------------------------------------===@@" + +paths_with_missing_license=( ) + +if [[ -f .licenseignore ]]; then + static_exclude_list='":(exclude).licenseignore" ":(exclude).license_header_template" ' + dynamic_exclude_list=$(tr '\n' '\0' < .licenseignore | xargs -0 -I% printf '":(exclude)%" ') + exclude_list=$static_exclude_list$dynamic_exclude_list +else + exclude_list=":(exclude).license_header_template" +fi + +file_paths=$(echo "$exclude_list" | xargs git ls-files) + +while IFS= read -r file_path; do + file_basename=$(basename -- "${file_path}") + file_extension="${file_basename##*.}" + + # shellcheck disable=SC2001 # We prefer to use sed here instead of bash search/replace + case "${file_extension}" in + c) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + cmake) expected_file_header=$(sed -e 's|@@|##|g' <<<"${expected_file_header_template}") ;; + gradle) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + groovy) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + h) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + in) expected_file_header=$(sed -e 's|@@|##|g' <<<"${expected_file_header_template}") ;; + java) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + js) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + json) continue ;; # JSON doesn't support comments + jsx) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + kts) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + proto) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + ps1) 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}")) ;; + sh) expected_file_header=$(cat <(echo '#!/bin/bash') <(sed -e 's|@@|##|g' <<<"${expected_file_header_template}")) ;; + swift) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + swift-format) continue ;; # .swift-format is JSON and doesn't support comments + ts) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + tsx) expected_file_header=$(sed -e 's|@@|//|g' <<<"${expected_file_header_template}") ;; + *) + error "Unsupported file extension ${file_extension} for file (exclude or update this script): ${file_path}" + paths_with_missing_license+=("${file_path} ") + ;; + esac + expected_file_header_linecount=$(wc -l <<<"${expected_file_header}") + + 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/' \ + ) + + if ! diff -u \ + --label "Expected header" <(echo "${expected_file_header}") \ + --label "${file_path}" <(echo "${normalized_file_header}") + then + paths_with_missing_license+=("${file_path} ") + fi +done <<< "$file_paths" + +if [ "${#paths_with_missing_license[@]}" -gt 0 ]; then + fatal "❌ Found missing license header in files: ${paths_with_missing_license[*]}." +fi + +log "✅ Found no files with missing license header." diff --git a/scripts/check-swift-format.sh b/scripts/check-swift-format.sh new file mode 100755 index 0000000..45f2ddd --- /dev/null +++ b/scripts/check-swift-format.sh @@ -0,0 +1,58 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift OpenFeature open source project +## +## Copyright (c) 2024 the Swift OpenFeature project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + + +if [[ -f .swiftformatignore ]]; then + log "Found swiftformatignore file..." + + log "Running swift format format..." + tr '\n' '\0' < .swiftformatignore| xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files -z '*.swift' | xargs -0 swift format format --parallel --in-place + + log "Running swift format lint..." + + tr '\n' '\0' < .swiftformatignore | xargs -0 -I% printf '":(exclude)%" '| xargs git ls-files -z '*.swift' | xargs -0 swift format lint --strict --parallel +else + log "Running swift format format..." + git ls-files -z '*.swift' | xargs -0 swift format format --parallel --in-place + + log "Running swift format lint..." + + git ls-files -z '*.swift' | xargs -0 swift format lint --strict --parallel +fi + + + +log "Checking for modified files..." + +GIT_PAGER='' git diff --exit-code '*.swift' + +log "✅ Found no formatting issues." diff --git a/scripts/check-unacceptable-language.sh b/scripts/check-unacceptable-language.sh new file mode 100755 index 0000000..53d6b44 --- /dev/null +++ b/scripts/check-unacceptable-language.sh @@ -0,0 +1,51 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift OpenFeature open source project +## +## Copyright (c) 2024 the Swift OpenFeature project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +log() { printf -- "** %s\n" "$*" >&2; } +error() { printf -- "** ERROR: %s\n" "$*" >&2; } +fatal() { error "$@"; exit 1; } + +UNACCEPTABLE_WORD_LIST="blacklist whitelist slave master sane sanity insane insanity kill killed killing hang hung hanged hanging" + +unacceptable_language_lines= +if [[ -f .unacceptablelanguageignore ]]; then + log "Found for unacceptable 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// /|}" | grep -v "ignore-unacceptable-language") || true | /usr/bin/paste -s -d " " - +else + log "Checking for unacceptable language..." + unacceptable_language_lines=$(git grep -i -I -w -H -n --column -E "${UNACCEPTABLE_WORD_LIST// /|}" | grep -v "ignore-unacceptable-language") || true | /usr/bin/paste -s -d " " - +fi + +if [ -n "${unacceptable_language_lines}" ]; then + fatal " ❌ Found unacceptable language: +${unacceptable_language_lines} +" +fi + +log "✅ Found no unacceptable language."