diff --git a/packages/help/.repo-metadata.json b/packages/help/.repo-metadata.json new file mode 100644 index 000000000000..fabe0b8f18df --- /dev/null +++ b/packages/help/.repo-metadata.json @@ -0,0 +1,10 @@ +{ + "name": "help", + "name_pretty": "Client libraries help", + "client_documentation": "https://cloud.google.com/python/docs/reference/help/latest", + "language": "python", + "library_type": "OTHER", + "repo": "googleapis/google-cloud-python", + "distribution_name": "help", + "codeowner_team": "@googleapis/cloud-sdk-python-team" +} diff --git a/packages/help/README.md b/packages/help/README.md new file mode 100644 index 000000000000..a877b991e63d --- /dev/null +++ b/packages/help/README.md @@ -0,0 +1,3 @@ +# Google Cloud Python Help + +Client libraries help documentation for common support issues and general information. diff --git a/packages/help/docfx_helper.py b/packages/help/docfx_helper.py new file mode 100644 index 000000000000..87d4c521b792 --- /dev/null +++ b/packages/help/docfx_helper.py @@ -0,0 +1,101 @@ +# Copyright 2026 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 argparse +import pathlib +import shutil +from typing import Dict, Union +import yaml +import pypandoc + +def build_docfx( + current_dir: Union[str, pathlib.Path], + docs_map: Dict[str, str], +) -> None: + current_dir = pathlib.Path(current_dir) + output_dir = current_dir / "docs" / "_build" + + if output_dir.exists(): + shutil.rmtree(output_dir) + output_dir.mkdir(parents=True) + + # Ensure pandoc is available (pypandoc will download it if not found in PATH) + try: + pypandoc.get_pandoc_version() + except OSError: + print("Pandoc not found. Downloading...") + pypandoc.download_pandoc() + + doc_items = [] + + for title, source in docs_map.items(): + source_path = pathlib.Path(source) + if not source_path.is_absolute(): + source_path = current_dir / source_path + + filename = source_path.name + + if filename.endswith(".rst"): + target_filename = filename.replace(".rst", ".md") + print(f"Converting {filename} -> {target_filename} using pandoc") + if source_path.exists(): + # Use pandoc to convert RST to GFM (GitHub Flavored Markdown) + output = pypandoc.convert_file( + str(source_path), + 'gfm', + format='rst' + ) + (output_dir / target_filename).write_text(output, encoding="utf-8") + else: + print(f"Warning: Source {source_path} not found.") + (output_dir / target_filename).write_text(f"# {title}\n\nContent missing.") + href = target_filename + else: + print(f"Copying {filename}") + if source_path.exists(): + shutil.copy(source_path, output_dir / filename) + else: + print(f"Warning: Source {source_path} not found.") + (output_dir / filename).write_text(f"# {title}\n\nContent missing.") + href = filename + + doc_items.append({"name": title, "href": href}) + + # Create the structured TOC + toc = [ + { + "uid": "product-neutral-guides", + "name": "Client library help", + "items": doc_items + } + ] + + # Write toc.yaml + toc_path = output_dir / "toc.yaml" + with open(toc_path, "w", encoding="utf-8") as f: + # Using block style for YAML as requested + yaml.dump(toc, f, default_flow_style=False) + + print(f"DocFX build complete in {output_dir}") + print(f"Generated TOC: {toc}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Build DocFX documentation.") + parser.add_argument("--current-dir", required=True, help="Current package directory") + parser.add_argument("--doc", action="append", nargs=2, metavar=("TITLE", "PATH"), help="Add a document title and its source path") + + args = parser.parse_args() + + docs_map = {title: path for title, path in args.doc} if args.doc else {} + build_docfx(args.current_dir, docs_map) diff --git a/packages/help/help/__init__.py b/packages/help/help/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/help/help/version.py b/packages/help/help/version.py new file mode 100644 index 000000000000..3c71cd41a387 --- /dev/null +++ b/packages/help/help/version.py @@ -0,0 +1,19 @@ +# Copyright 2026 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 +# +# 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. + +__version__ = "1.0.0" + +# {x-release-please-start-date} +__release_date__ = "2026-04-07" +# {x-release-please-end} diff --git a/packages/help/mypy.ini b/packages/help/mypy.ini new file mode 100644 index 000000000000..49860029cf36 --- /dev/null +++ b/packages/help/mypy.ini @@ -0,0 +1,8 @@ +[mypy] +python_version = 3.9 +ignore_missing_imports = True +strict = True +disallow_untyped_decorators = False +show_error_codes = True +explicit_package_bases = True +namespace_packages = True diff --git a/packages/help/noxfile.py b/packages/help/noxfile.py new file mode 100644 index 000000000000..2a0c5a97f383 --- /dev/null +++ b/packages/help/noxfile.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2026 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 pathlib +import nox + +DEFAULT_PYTHON_VERSION = "3.14" +ALL_PYTHON = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() +REPO_ROOT = CURRENT_DIRECTORY.parent.parent + +# Hardcoded dictionary of documentation files. +# Format: {"Display Title": "filename.md" or absolute path} +DOCS_MAP = { + "Getting started": str(REPO_ROOT / "README.rst"), +} + +nox.options.sessions = [ + "lint", + "lint_setup_py", + "unit", + "mypy", + "prerelease_deps", + "core_deps_from_source", + "docfx", + "docs", +] + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def lint_setup_py(session: nox.Session) -> None: + """Verify that setup.py is valid.""" + session.install("setuptools") + session.run("python", "setup.py", "check", "--strict") + +@nox.session(python=ALL_PYTHON) +def unit(session: nox.Session) -> None: + """Run unit tests.""" + session.install("pytest", "pytest-cov") + session.install("-e", ".") + session.run("pytest", "tests") + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def mypy(session: nox.Session) -> None: + """Run mypy.""" + session.install("mypy", "types-PyYAML") + session.install("-e", ".") + session.run("mypy", "help", "tests", "noxfile.py", "docfx_helper.py") + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def prerelease_deps(session: nox.Session) -> None: + """Run unit tests with prerelease dependencies.""" + # Since we have no dependencies, this is just a normal unit test run + # but with --pre enabled for any test tools. + session.install("pytest", "pytest-cov") + session.install("-e", ".") + session.run("pytest", "tests") + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def core_deps_from_source(session: nox.Session) -> None: + """Run unit tests with core dependencies installed from source.""" + # We don't depend on core, so we just run unit tests. + session.install("pytest", "pytest-cov") + session.install("-e", ".") + session.run("pytest", "tests") + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def lint(session: nox.Session) -> None: + """Run linters.""" + session.install("ruff") + session.run("ruff", "check", ".") + +@nox.session(python="3.10") +def docfx(session: nox.Session) -> None: + """Build the docfx yaml files for this library.""" + session.install("PyYAML", "pypandoc") + + # Construct arguments for the helper script + args = [ + "--current-dir", str(CURRENT_DIRECTORY), + ] + for title, source in DOCS_MAP.items(): + args.extend(["--doc", title, str(source)]) + + session.run("python", "docfx_helper.py", *args) + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def docs(session: nox.Session) -> None: + """No-op session for docs.""" + session.log("This package does not have Sphinx documentation.") diff --git a/packages/help/setup.py b/packages/help/setup.py new file mode 100644 index 000000000000..135317b8e883 --- /dev/null +++ b/packages/help/setup.py @@ -0,0 +1,74 @@ +# Copyright 2026 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 +# +# 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. + + +import io +import os + +import setuptools + +# Package metadata. + +name = "help" +description = "Client libraries help documentation" +release_status = "Development Status :: 5 - Production/Stable" +dependencies = [] + +# Setup boilerplate below this line. + +package_root = os.path.abspath(os.path.dirname(__file__)) + +readme_filename = os.path.join(package_root, "README.md") +with io.open(readme_filename, encoding="utf-8") as readme_file: + readme = readme_file.read() + +version = {} +with open(os.path.join(package_root, "help/version.py")) as fp: + exec(fp.read(), version) +version_id = version["__version__"] + +setuptools.setup( + name=name, + version=version_id, + description=description, + long_description=readme, + long_description_content_type="text/markdown", + author="Google LLC", + author_email="cloud-sdk@google.com", + license="Apache 2.0", + url="https://github.com/googleapis/google-cloud-python/tree/main/packages/help", + project_urls={ + "Source": "https://github.com/googleapis/google-cloud-python/tree/main/packages/help", + "Changelog": "https://github.com/googleapis/google-cloud-python/tree/main/packages/help/CHANGELOG.md", + "Issues": "https://github.com/googleapis/google-cloud-python/issues", + }, + classifiers=[ + release_status, + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Operating System :: OS Independent", + "Topic :: Internet", + ], + install_requires=dependencies, + python_requires=">=3.9", + include_package_data=True, + zip_safe=False, + packages=["help"], +) diff --git a/packages/help/tests/test_package.py b/packages/help/tests/test_package.py new file mode 100644 index 000000000000..ae8c102db35b --- /dev/null +++ b/packages/help/tests/test_package.py @@ -0,0 +1,18 @@ +# Copyright 2026 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 +# +# 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. + +from help import version + +def test_version() -> None: + assert version.__version__ is not None