diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..bb3b3574 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,7 @@ +# Code owners file. +# This file controls who is tagged for review for any given pull request. +# +# For syntax help see: +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax + +* @google/a2a-eng diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000..9d0b58a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,33 @@ +name: ๐Ÿž Bug Report +description: File a bug report +title: "[Bug]: " +type: "Bug" +body: + - type: markdown + attributes: + value: | + Thanks for stopping by to let us know something could be better! + Private Feedback? Please use this [Google form](https://goo.gle/a2a-feedback) + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us what you expected to happen and how to reproduce the issue. + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/google/A2A?tab=coc-ov-file#readme) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000..c470a2de --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,41 @@ +name: ๐Ÿ’ก Feature Request +description: Suggest an idea for this repository +title: "[Feat]: " +type: "Feature" +body: + - type: markdown + attributes: + value: | + Thanks for stopping by to let us know something could be better! + Private Feedback? Please use this [Google form](https://goo.gle/a2a-feedback) + - type: textarea + id: problem + attributes: + label: Is your feature request related to a problem? Please describe. + description: A clear and concise description of what the problem is. + placeholder: Ex. I'm always frustrated when [...] + - type: textarea + id: describe + attributes: + label: Describe the solution you'd like + description: A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Describe alternatives you've considered + description: A clear and concise description of any alternative solutions or features you've considered. + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/google/a2a-python?tab=coc-ov-file#readme) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..24798217 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +# Description + +Thank you for opening a Pull Request! +Before submitting your PR, there are a few things you can do to make sure it goes smoothly: + +- [ ] Follow the [`CONTRIBUTING` Guide](https://github.com/google/a2a-python/blob/main/CONTRIBUTING.md). +- [ ] Make your Pull Request title in the specification. +- [ ] Ensure the tests and linter pass (Run `nox -s format` from the repository root to format) +- [ ] Appropriate docs were updated (if necessary) + +Fixes # ๐Ÿฆ• diff --git a/.github/actions/spelling/advice.md b/.github/actions/spelling/advice.md new file mode 100644 index 00000000..2c0631a0 --- /dev/null +++ b/.github/actions/spelling/advice.md @@ -0,0 +1,28 @@ + +
If the flagged items are :exploding_head: false positives + +If items relate to a ... + +- binary file (or some other file you wouldn't want to check at all). + + Please add a file path to the `excludes.txt` file matching the containing file. + + File paths are Perl 5 Regular Expressions - you can [test](https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files. + + `^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude `README.md` (on whichever branch you're using). + +- well-formed pattern. + + If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it, + try adding it to the `patterns.txt` file. + + Patterns are Perl 5 Regular Expressions - you can [test](https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines. + + Note that patterns can't match multiline strings. + +
+ + + +:steam_locomotive: If you're seeing this message and your PR is from a branch that doesn't have check-spelling, +please merge to your PR's base branch to get the version configured for your repository. diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt new file mode 100644 index 00000000..e69de29b diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt new file mode 100644 index 00000000..0d6f82d4 --- /dev/null +++ b/.github/actions/spelling/excludes.txt @@ -0,0 +1,87 @@ +# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes +(?:^|/)(?i)COPYRIGHT +(?:^|/)(?i)LICEN[CS]E +(?:^|/)(?i)CODE_OF_CONDUCT.md\E$ +(?:^|/)(?i).gitignore\E$ +(?:^|/)3rdparty/ +(?:^|/)go\.sum$ +(?:^|/)package(?:-lock|)\.json$ +(?:^|/)Pipfile$ +(?:^|/)pyproject.toml +(?:^|/)requirements(?:-dev|-doc|-test|)\.txt$ +(?:^|/)vendor/ +/CODEOWNERS$ +\.a$ +\.ai$ +\.all-contributorsrc$ +\.avi$ +\.bmp$ +\.bz2$ +\.cer$ +\.class$ +\.coveragerc$ +\.crl$ +\.crt$ +\.csr$ +\.dll$ +\.docx?$ +\.drawio$ +\.DS_Store$ +\.eot$ +\.eps$ +\.exe$ +\.gif$ +\.git-blame-ignore-revs$ +\.gitattributes$ +\.gitkeep$ +\.graffle$ +\.gz$ +\.icns$ +\.ico$ +\.jar$ +\.jks$ +\.jpe?g$ +\.key$ +\.lib$ +\.lock$ +\.map$ +\.min\.. +\.mo$ +\.mod$ +\.mp[34]$ +\.o$ +\.ocf$ +\.otf$ +\.p12$ +\.parquet$ +\.pdf$ +\.pem$ +\.pfx$ +\.png$ +\.psd$ +\.pyc$ +\.pylintrc$ +\.qm$ +\.s$ +\.sig$ +\.so$ +\.svgz?$ +\.sys$ +\.tar$ +\.tgz$ +\.tiff?$ +\.ttf$ +\.wav$ +\.webm$ +\.webp$ +\.woff2?$ +\.xcf$ +\.xlsx?$ +\.xpm$ +\.xz$ +\.zip$ +^\.github/actions/spelling/ +^\Q.github/workflows/spelling.yaml\E$ +^\Q.github/workflows/linter.yaml\E$ +\.gitignore\E$ +\.vscode/ diff --git a/.github/actions/spelling/line_forbidden.patterns b/.github/actions/spelling/line_forbidden.patterns new file mode 100644 index 00000000..f87ad0b7 --- /dev/null +++ b/.github/actions/spelling/line_forbidden.patterns @@ -0,0 +1,307 @@ +# Should be `HH:MM:SS` +\bHH:SS:MM\b + +# Should probably be `YYYYMMDD` +\b[Yy]{4}[Dd]{2}[Mm]{2}(?!.*[Yy]{4}[Dd]{2}[Mm]{2}).*$ + +# Should be `anymore` +\bany more[,.] + +# Should be `cannot` (or `can't`) +# See https://www.grammarly.com/blog/cannot-or-can-not/ +# > Don't use `can not` when you mean `cannot`. The only time you're likely to see `can not` written as separate words is when the word `can` happens to precede some other phrase that happens to start with `not`. +# > `Can't` is a contraction of `cannot`, and it's best suited for informal writing. +# > In formal writing and where contractions are frowned upon, use `cannot`. +# > It is possible to write `can not`, but you generally find it only as part of some other construction, such as `not only . . . but also.` +# - if you encounter such a case, add a pattern for that case to patterns.txt. +\b[Cc]an not\b + +# Should be `GitHub` +(? + Marking this issue as stale since it has been open for 14 days with no activity. + This issue will be closed if no further activity occurs. + close-issue-message: > + This issue was closed because it has been inactive for 27 days. + Please post a new issue if you need further assistance. Thanks! + days-before-pr-stale: 14 + days-before-pr-close: 13 + stale-pr-label: "status:stale" + stale-pr-message: > + Marking this pull request as stale since it has been open for 14 days with no activity. + This PR will be closed if no further activity occurs. + close-pr-message: > + This pull request was closed because it has been inactive for 27 days. + Please open a new pull request if you need further assistance. Thanks! + # Label that can be assigned to issues to exclude them from being marked as stale + exempt-issue-labels: "override-stale" + # Label that can be assigned to PRs to exclude them from being marked as stale + exempt-pr-labels: "override-stale" diff --git a/.ruff.toml b/.ruff.toml index b509651a..f4baf437 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -5,18 +5,6 @@ # This file follows the standards in Google Python Style Guide # https://google.github.io/styleguide/pyguide.html # -# The settings below are for the IDE configuration, and are optional. -#{ -# "editor.formatOnSave": true, -# "[python]": { -# "editor.defaultFormatter": "charliermarsh.ruff", -# "editor.formatOnSave": true, -# "editor.codeActionsOnSave": { -# "source.organizeImports": "true" -# }, -# }, -# "ruff.importStrategy": "fromEnvironment", -#} line-length = 80 # Google Style Guide ยง3.2: 80 columns indent-width = 4 # Google Style Guide ยง3.4: 4 spaces @@ -34,7 +22,7 @@ ignore = [ "ANN201", "ANN204", "D100", # Ignore Missing docstring in public module (often desired at top level __init__.py) - "D102", # Ignore return type annotiation in public method + "D102", # Ignore return type annotation in public method "D104", # Ignore Missing docstring in public package (often desired at top level __init__.py) "D107", # Ignore Missing docstring in __init__ (use class docstring) "TD002", # Ignore Missing author in TODOs (often not required) @@ -137,4 +125,4 @@ inline-quotes = "single" docstring-code-format = true docstring-code-line-length = "dynamic" # Or set to 80 quote-style = "single" -indent-style = "space" \ No newline at end of file +indent-style = "space" diff --git a/SECURITY.md b/SECURITY.md index 5d0d1a26..8b58ae9c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,4 +1,3 @@ - # Security Policy To report a security issue, please use [g.co/vulnz](https://g.co/vulnz). diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..4d8b3165 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,144 @@ +# pylint: skip-file +# type: ignore +# -*- coding: utf-8 -*- +# +# Copyright 2025 Google LLC +# +# 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 +# +# 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. + +import os +import pathlib +import subprocess + +import nox + + +DEFAULT_PYTHON_VERSION = '3.13' + +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +nox.options.sessions = [ + 'format', +] + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def format(session): + """Format Python code using autoflake, pyupgrade, and ruff.""" + # Sort Spelling Allowlist + spelling_allow_file = '.github/actions/spelling/allow.txt' + + with open(spelling_allow_file, encoding='utf-8') as file: + unique_words = sorted(set(file)) + + with open(spelling_allow_file, 'w', encoding='utf-8') as file: + file.writelines(unique_words) + + format_all = False + + if format_all: + lint_paths_py = ['.'] + else: + target_branch = 'origin/main' + + unstaged_files = subprocess.run( + [ + 'git', + 'diff', + '--name-only', + '--diff-filter=ACMRTUXB', + target_branch, + ], + stdout=subprocess.PIPE, + text=True, + check=False, + ).stdout.splitlines() + + staged_files = subprocess.run( + [ + 'git', + 'diff', + '--cached', + '--name-only', + '--diff-filter=ACMRTUXB', + target_branch, + ], + stdout=subprocess.PIPE, + text=True, + check=False, + ).stdout.splitlines() + + committed_files = subprocess.run( + [ + 'git', + 'diff', + 'HEAD', + target_branch, + '--name-only', + '--diff-filter=ACMRTUXB', + ], + stdout=subprocess.PIPE, + text=True, + check=False, + ).stdout.splitlines() + + changed_files = sorted( + { + file + for file in (unstaged_files + staged_files + committed_files) + if os.path.isfile(file) + } + ) + + lint_paths_py = [f for f in changed_files if f.endswith('.py')] + + if not lint_paths_py: + session.log('No changed Python files to lint.') + return + + session.install( + 'types-requests', + 'pyupgrade', + 'autoflake', + 'ruff', + ) + + if lint_paths_py: + if not format_all: + session.run( + 'pyupgrade', + '--exit-zero-even-if-changed', + '--py311-plus', + *lint_paths_py, + ) + session.run( + 'autoflake', + '-i', + '-r', + '--remove-all-unused-imports', + *lint_paths_py, + ) + session.run( + 'ruff', + 'check', + '--fix-only', + *lint_paths_py, + ) + session.run( + 'ruff', + 'format', + *lint_paths_py, + )