diff --git a/.github/workflows/ci-format.yml b/.github/workflows/ci-format.yml index bd3c2b8bd79..1f0683c978a 100644 --- a/.github/workflows/ci-format.yml +++ b/.github/workflows/ci-format.yml @@ -24,7 +24,7 @@ jobs: reviewer-stats path: ~/reviews - name: Copy stats - run: ./make_help_scripts/add_pr_stats + run: ./make_help_scripts/add_pr_stats.py - uses: pre-commit/action@v3.0.1 with: extra_args: --all-files --hook-stage manual diff --git a/.github/workflows/sphinx-check-page-multiversion.yml b/.github/workflows/sphinx-check-page-multiversion.yml new file mode 100644 index 00000000000..55619752d2c --- /dev/null +++ b/.github/workflows/sphinx-check-page-multiversion.yml @@ -0,0 +1,53 @@ +name: "Build Multiversion Page" +on: + workflow_dispatch: + inputs: + BASE_BRANCH: + description: 'Chose branch to run on' + required: true + default: 'master' + type: choice + options: + - humble + - iron + - master + pull_request: + branches: + - master + paths: + - 'make_help_scripts/**' + - 'conf.py' + +jobs: + build-multiversion: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: 'pip' + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade --requirement requirements.txt + shell: bash + - name: Install generate_parameter_library + run: | + cd + git clone https://github.com/PickNikRobotics/generate_parameter_library.git + cd generate_parameter_library/generate_parameter_library_py/ + python -m pip install . + shell: bash + - name: Install doxygen and graphviz + run: sudo apt-get install -y doxygen graphviz + - name: Build multiversion with API + env: + BASE_BRANCH: ${{ github.event.inputs.BASE_BRANCH }} + BASE_BRANCH_PR: ${{ github.event.pull_request.head.ref }} + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + make multiversion-with-api diff --git a/.gitignore b/.gitignore index c993f6a1fdb..b3d9ff6943a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,16 @@ # ignore pages build by sphinx _build/* +# ignore python cache +**/__pycache__/ + # ignore other docs that are included either by checkout or symlink doc/ros2_control doc/ros2_control_demos doc/ros2_controllers doc/gazebo_ros2_control doc/gz_ros2_control +doc/control_msgs/ +doc/control_toolbox/ +doc/kinematics_interface/ +doc/realtime_tools/ diff --git a/Makefile b/Makefile index de0ce3c74c2..2b01e42bcb4 100644 --- a/Makefile +++ b/Makefile @@ -30,80 +30,80 @@ html-with-api: Makefile @echo Step 1: Creating html files $(SPHINXBUILD) $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html @echo Step 2: Building API - ./make_help_scripts/create_api + ./make_help_scripts/create_api.py html-all-subrepos: Makefile @echo Single html file without API @echo Step 1: Cloning all subrepositories - ./make_help_scripts/add_sub_repos + ./make_help_scripts/add_sub_repos.py @echo Step 2: Building documentation $(SPHINXBUILD) $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html @echo Step 3: Deleting subrepositories in doc/ folder - ./make_help_scripts/delete_sub_repos + ./make_help_scripts/delete_sub_repos.py html-all-subrepos-with-errors: Makefile @echo Single html file without API @echo Step 1: Cloning all subrepositories - ./make_help_scripts/add_sub_repos + ./make_help_scripts/add_sub_repos.py @echo Step 2: Building documentation $(SPHINXBUILD) $(SPHINXOPTS) -W --keep-going $(SOURCEDIR) $(BUILDDIR)/html @echo Step 3: Deleting subrepositories in doc/ folder - ./make_help_scripts/delete_sub_repos + ./make_help_scripts/delete_sub_repos.py html-all-subrepos-with-api: Makefile @echo Single html file with API @echo Step 1: Cloning all subrepositories - ./make_help_scripts/add_sub_repos + ./make_help_scripts/add_sub_repos.py @echo Step 2: Building documentation $(SPHINXBUILD) $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html - @echo Step 3: Deleting subrepositories in doc/ folder - ./make_help_scripts/delete_sub_repos - @echo Step 4: Building API - ./make_help_scripts/create_api + @echo Step 3: Building API + ./make_help_scripts/create_api.py + @echo Step 4: Deleting subrepositories in doc/ folder + ./make_help_scripts/delete_sub_repos.py linkcheck-all-subrepos-with-api: Makefile @echo Single version html file with API and linkcheck @echo Step 1: Cloning all subrepositories - ./make_help_scripts/add_sub_repos + ./make_help_scripts/add_sub_repos.py @echo Step 2: Building API - ./make_help_scripts/create_api - @echo Step 3: Cloning all subrepositories again - ./make_help_scripts/add_sub_repos - @echo Step 4: Check links - ./make_help_scripts/check_links $(BUILDDIR) + ./make_help_scripts/create_api.py + @echo Step 3: Check links + ./make_help_scripts/check_links.py $(BUILDDIR)/html + @echo Step 4: Deleting subrepositories in doc/ folder + ./make_help_scripts/delete_sub_repos.py multiversion: Makefile @echo Building multi version documentation without API @echo Step 1: Creating temporary commits - ./make_help_scripts/add_tmp_commits + ./make_help_scripts/add_tmp_commits.py @echo Step 2: Build multi version documentation sphinx-multiversion $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html @echo Step 3: Deleting temporary commits - ./make_help_scripts/delete_tmp_commits + ./make_help_scripts/delete_tmp_commits.py @echo Step 4: Create correct index @echo "" > "$(BUILDDIR)"/html/index.html multiversion-with-errors: Makefile @echo Building multi version documentation without API @echo Step 1: Creating temporary commits - ./make_help_scripts/add_tmp_commits + ./make_help_scripts/add_tmp_commits.py @echo Step 2: Build multi version documentation sphinx-multiversion $(SPHINXOPTS) -W --keep-going $(SOURCEDIR) $(BUILDDIR)/html @echo Step 3: Deleting temporary commits - ./make_help_scripts/delete_tmp_commits + ./make_help_scripts/delete_tmp_commits.py @echo Step 4: Create correct index @echo "" > "$(BUILDDIR)"/html/index.html multiversion-with-api: Makefile @echo Building multi version documentation with API @echo Step 1: Creating temporary commits - ./make_help_scripts/add_tmp_commits + ./make_help_scripts/add_tmp_commits.py @echo Step 2: Build multi version documentation sphinx-multiversion $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html @echo Step 3: Deleting temporary commits - ./make_help_scripts/delete_tmp_commits + ./make_help_scripts/delete_tmp_commits.py @echo Step 4: Building multiverison API - ./make_help_scripts/create_api_multi_version + ./make_help_scripts/create_api_multi_version.py @echo Step 5: Create correct index @echo "" > "$(BUILDDIR)"/html/index.html diff --git a/conf.py b/conf.py index 9c70c65745a..7b615521f72 100644 --- a/conf.py +++ b/conf.py @@ -67,10 +67,14 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -# exclude index.rst files for metapackages for rosdoc2 +# exclude index.rst files from packages/metapackages for rosdoc2 exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**/CHANGELOG.rst", "**/README.rst", "doc/ros2_control/ros2_control/**.rst", + "doc/realtime_tools/doc/**.rst", + "doc/control_msgs/doc/**.rst", + "doc/control_toolbox/doc/**.rst", + "doc/kinematics_interface/**.rst", "doc/ros2_controllers/ros2_controllers/**.rst"] # The name of the Pygments (syntax highlighting) style to use. @@ -183,10 +187,18 @@ # Drop any source link suffix html_sourcelink_suffix = "" +# branch from which is started to checkout other branches +# TODO(anyone) use make_help_scripts/deploy_defines.py to set this variable +if os.environ.get('BASE_BRANCH_PR') is not None: + base_branch = os.environ.get('BASE_BRANCH_PR') +elif os.environ.get('BASE_BRANCH') is not None: + base_branch = os.environ.get('BASE_BRANCH') +else: + base_branch = "iron" # Add branches you want to whitelist here. -smv_branch_whitelist = r"^(foxy|galactic|humble|iron|master)$" -smv_released_pattern = r"^refs/(heads|remotes/[^/]+)/(foxy|galactic|humble|iron|rolling).*$" +smv_branch_whitelist = r"^(foxy|galactic|humble|"+ base_branch + r")$" +smv_released_pattern = r"^refs/(heads|remotes/[^/]+)/(foxy|galactic|humble|iron).*$" smv_remote_whitelist = r"^(origin)$" smv_latest_version = "iron" smv_eol_versions = ["foxy", "galactic"] @@ -312,7 +324,15 @@ def smv_rewrite_configs(app, config): # to rewrite the various configuration items with the current version. if app.config.smv_current_version != "": branch_distro = { - "master": "rolling", + base_branch: "rolling", + "iron": "iron", + "humble": "humble", + "foxy": "foxy", + "galactic": "galactic" + } + # this map is used to match branches of control.ros.org to REPOS_FILE_BRANCH macro + subrepo_branch = { + base_branch: "master", "iron": "iron", "humble": "humble", "foxy": "foxy", diff --git a/doc/api_list/api_list.rst b/doc/api_list/api_list.rst index 6ca1b934896..00eaac10e44 100644 --- a/doc/api_list/api_list.rst +++ b/doc/api_list/api_list.rst @@ -3,8 +3,12 @@ API Documentation ================= +ros2_control stack +############################# API documentation for the whole framework is parsed by doxygen and can be found `here <../api/index.html>`_. +Per-Package API Documentation +############################# In the following, you can find links to the per-package API documentation published on docs.ros.org. ros2_control diff --git a/doc/api_list/mainpage.md b/doc/api_list/mainpage.md index a914de89a10..7e8a4c4f1a0 100644 --- a/doc/api_list/mainpage.md +++ b/doc/api_list/mainpage.md @@ -2,7 +2,7 @@ This is the API documentation of the ros2_control framework including the follow * [ros2_control][ros2_control] - the main interfaces and components of the framework; * [ros2_controllers][ros2_controllers] - widely used controllers, such as forward command controller, joint trajectory controller, differential drive controller; -* [ros2_control_demos][ros2_control_demos] - examples implementations of common use-cases for a smooth start; +* [ros2_control_demos][ros2_control_demos] - example implementations of common use-cases for a smooth start; * [control_toolbox][control_toolbox] - some widely-used control theory implementations (e.g. PID) used by controllers; * [realtime_tools][realtime_tools] - general toolkit for realtime support, e.g., realtime buffers and publishers; * [control_msgs][control_msgs] - common messages. diff --git a/index.rst b/index.rst index 9fd5670a8cf..6774b7b48f9 100644 --- a/index.rst +++ b/index.rst @@ -35,13 +35,13 @@ The ros2_control framework consists of the following Github repositories: * `ros2_controllers`_ - widely used controllers, such as forward command controller, joint trajectory controller, differential drive controller; * `control_toolbox`_ - some widely-used control theory implementations (e.g. PID) used by controllers; * `realtime_tools`_ - general toolkit for realtime support, e.g., realtime buffers and publishers; -* `control_msgs`_ - common messages. -* `kinematics_interface`_ - for using C++ kinematics frameworks. +* `control_msgs`_ - common messages; +* `kinematics_interface`_ - for using C++ kinematics frameworks; Additionally, there are following (unreleased) packages are relevant for getting-started and project management: -* `ros2_control_demos`_ - examples implementations of common use-cases for a smooth start; +* `ros2_control_demos`_ - example implementations of common use-cases for a smooth start; * `roadmap`_ - planning and design docs for the project. Development Organisation and Communication diff --git a/make_help_scripts/add_pr_stats b/make_help_scripts/add_pr_stats deleted file mode 100755 index 4dbe1442763..00000000000 --- a/make_help_scripts/add_pr_stats +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -add_pr_stats_file diff --git a/make_help_scripts/add_pr_stats.py b/make_help_scripts/add_pr_stats.py new file mode 100755 index 00000000000..0ed5854966c --- /dev/null +++ b/make_help_scripts/add_pr_stats.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 deploy_defines import add_pr_stats_file + +add_pr_stats_file() diff --git a/make_help_scripts/add_sub_repos b/make_help_scripts/add_sub_repos deleted file mode 100755 index 643b5f0136c..00000000000 --- a/make_help_scripts/add_sub_repos +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -add_sub_repositories () { - # checkout a base for defined starting point - cd "$base_dir" || { echo "Could not checkout base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } - for repo_name in "${!subrepo_url[@]}"; do - if [ ! -d "doc/$repo_name" ]; then - echo "Create doc/$repo_name and checkout $base_branch branch" - git clone "${subrepo_url[$repo_name]}" -b "$base_branch" doc/"$repo_name" - else - echo "Update doc/$repo_name and checkout $base_branch branch" - cd doc/"$repo_name" - git fetch origin - git checkout "$base_branch" - git pull - cd "$base_dir" - fi - if [ ! -z ${subrepo_pr[$repo_name]} ]; then - echo "checkout PR: ${subrepo_pr[$repo_name]}" - cd doc/"$repo_name" - git fetch origin ${subrepo_pr[$repo_name]}:PR - git checkout PR - cd "$base_dir" - fi - done -} - -add_sub_repositories -add_pr_stats_file diff --git a/make_help_scripts/add_sub_repos.py b/make_help_scripts/add_sub_repos.py new file mode 100755 index 00000000000..c091ac739b6 --- /dev/null +++ b/make_help_scripts/add_sub_repos.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import subprocess +import deploy_defines + +def add_sub_repositories(base_branch): + # checkout a base for defined starting point + print(f"base_branch: {base_branch}") + print(f"base_version: {deploy_defines.branch_version[base_branch]}") + os.chdir(deploy_defines.base_dir) + for repo_name, repo_details in deploy_defines.repos.items(): + repo_path = os.path.join("doc", repo_name) + branch = repo_details["branch_version"][deploy_defines.branch_version[base_branch]] + if not os.path.isdir(repo_path): + print(f"Create {repo_path} and checkout {branch} branch") + subprocess.run(["git", "clone", "-b", branch, repo_details["url"], repo_path], check=True) + else: + print(f"Update {repo_path} and checkout {branch} branch") + os.chdir(repo_path) + subprocess.run(["git", "fetch", "origin"], check=True) + subprocess.run(["git", "checkout", branch], check=True) + subprocess.run(["git", "pull"], check=True) + os.chdir(deploy_defines.base_dir) + if repo_details["pr"]: + PR = repo_details["pr"] + print(f"checkout PR: {PR}") + os.chdir(repo_path) + subprocess.run(["git", "fetch", "origin", f"{PR}:PR"], check=True) + subprocess.run(["git", "checkout", "PR"], check=True) + os.chdir(deploy_defines.base_dir) + +if __name__ == "__main__": + add_sub_repositories(deploy_defines.base_branch) + deploy_defines.add_pr_stats_file() diff --git a/make_help_scripts/add_tmp_commits b/make_help_scripts/add_tmp_commits deleted file mode 100755 index d785f0c6c81..00000000000 --- a/make_help_scripts/add_tmp_commits +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -check_repositories () { - # checkout a base for defined starting point - cd "$base_dir" || { echo "Could not go to base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } - if [ -n "$(git status --porcelain)" ]; then - echo "control.ros.org repository has uncommitted changes, which will be deleted!"; exit 2; - fi - # check if subrepos do not exist and are no symlinks - for repo_name in "${!subrepo_url[@]}"; do - if [ -L doc/"$repo_name" ]; then - echo "$repo_name is a symlink, delete link or repository will be broken!"; exit 2; - fi - if [ -d doc/"$repo_name" ]; then - echo "$repo_name repository exists already, save your changes because it will be deleted!"; exit 2; - fi - done -} - -add_sub_repositories_and_commit () { - # checkout a base for defined starting point - cd "$base_dir" || { echo "Could not go to base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } - git checkout "$base_branch" || { echo "Exiting!"; exit "$ERRCODE"; } - - # for each branch from multi version, checkout branch, clone sub repositories with docs add as tmp commit and remove - for branch in "${!branch_version[@]}"; - do echo "Switch to branch: $branch. - With version:${branch_version[$branch]}"; - git checkout "$branch" - # change .gitignore, needed to include subrepositories. sed matches doc/ros2_control*, so all subrepositorie are excluded - sed -i "s/doc\/ros2_control/\#doc\/ros2_control/g" .gitignore - sed -i "s/doc\/gz_ros2_control/\#doc\/gz_ros2_control/g" .gitignore - sed -i "s/doc\/gazebo_ros2_control/\#doc\/gazebo_ros2_control/g" .gitignore - # clone all subrepositories and add as tmp commit to branch of multi version - echo "Clone repositories for $branch and checkout ${branch_version[$branch]}" - for repo_name in "${!subrepo_url[@]}"; - do echo "Create doc/$repo_name"; - git clone "${subrepo_url[$repo_name]}" -b "${branch_version[$branch]}" doc/"$repo_name" 1> /dev/null - cd doc/"$repo_name" || { echo "Could not clone $repo_name to doc/ directory. Exiting!"; exit "$ERRCODE"; } - # remove git repo so that doc files of subrepo can be added to tmp commit - rm -rf .git/ - cd ../../ - done - add_pr_stats_file - git add . - # we don't want to use-precommit to check if subrepos are correct - git commit -m "Add temporary changes for multi version" --no-verify 1> /dev/null - git checkout "$base_branch" - # remove left over folders if existing - for repo_name in "${!subrepo_url[@]}"; - do rm -rf doc/"$repo_name"; - done - done -} - -check_repositories -add_sub_repositories_and_commit diff --git a/make_help_scripts/add_tmp_commits.py b/make_help_scripts/add_tmp_commits.py new file mode 100755 index 00000000000..5bb758d3ac1 --- /dev/null +++ b/make_help_scripts/add_tmp_commits.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import subprocess +import sys +import shutil +import deploy_defines + +def check_repositories(): + os.chdir(deploy_defines.base_dir) + # Check for uncommitted changes in control.ros.org repository + if subprocess.run(["git", "status", "--porcelain"], capture_output=True, text=True).stdout.strip(): + print("control.ros.org repository has uncommitted changes, which will be deleted!") + subprocess.run(["git", "status", "--porcelain"]) + sys.exit(2) + # Check if subrepos exist or are symlinks + for repo_name in deploy_defines.repos.keys(): + repo_path = os.path.join("doc", repo_name) + if os.path.islink(repo_path): + print(f"{repo_name} is a symlink, delete link or repository will be broken!") + sys.exit(2) + if os.path.isdir(repo_path) and subprocess.run(["git", "-C", repo_path, "status", "--porcelain"], capture_output=True, text=True).stdout.strip(): + print(f"{repo_name} repository exists already, save your changes because it will be deleted!") + sys.exit(2) + +def add_sub_repositories_and_commit(): + os.chdir(deploy_defines.base_dir) + # Checkout the base branch + subprocess.run(["git", "checkout", deploy_defines.base_branch], check=True) + # For each branch from multi version, checkout branch, clone sub repositories with docs add as tmp commit and remove + for branch, version in deploy_defines.branch_version.items(): + print("----------------------------------------------------") + print(f"Switch to branch: {branch} with version: {version}") + subprocess.run(["git", "checkout", branch], check=True) + # Modify .gitignore to include subrepositories + subprocess.run(["sed", "-i", "s/doc\/ros2_control/\#doc\/ros2_control/g", ".gitignore"], check=True) + subprocess.run(["sed", "-i", "s/doc\/gz_ros2_control/\#doc\/gz_ros2_control/g", ".gitignore"], check=True) + subprocess.run(["sed", "-i", "s/doc\/gazebo_ros2_control/\#doc\/gazebo_ros2_control/g", ".gitignore"], check=True) + # Clone all subrepositories and add as tmp commit to branch of multi version + print(f"Clone repositories for {branch} and checkout branches for {version}") + for repo_name, repo_details in deploy_defines.repos.items(): + print(f"Create doc/{repo_name}") + # Remove leftover folders if existing + shutil.rmtree(f"doc/{repo_name}", ignore_errors=True) + branch = repo_details["branch_version"][version] + subprocess.run(["git", "clone", "-b", branch, repo_details["url"], f"doc/{repo_name}"], check=True, stdout=subprocess.DEVNULL) + os.chdir(f"doc/{repo_name}") + # Remove git repo so that doc files of subrepo can be added to tmp commit + shutil.rmtree(".git") + os.chdir("../../") + deploy_defines.add_pr_stats_file() + subprocess.run(["git", "add", "."], check=True) + # We don't want to use-precommit to check if subrepos are correct + subprocess.run(["git", "commit", "-m", "Add temporary changes for multi version", "--no-verify"], check=True, stdout=subprocess.DEVNULL) + subprocess.run(["git", "checkout", deploy_defines.base_branch], check=True) + print("---------- end add_sub_repositories_and_commit ----------------") + +if __name__ == "__main__": + check_repositories() + add_sub_repositories_and_commit() diff --git a/make_help_scripts/check_links b/make_help_scripts/check_links deleted file mode 100755 index f95cc40b958..00000000000 --- a/make_help_scripts/check_links +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# This script is used to check the links in the ROS documentation. -# due to a bug in the sphinx linkchecker, github anchors are false positives and -# have to be explicitly ignored -# https://github.com/sphinx-doc/sphinx/issues/9016 - -LOGFILE="linkcheck.log" -cleanup () { - rm "$LOGFILE" - rm -rf doc/api/ -} - -cp -r $1/html/doc/api/. doc/api/ -make linkcheck > "$LOGFILE" -if grep broken "$LOGFILE" | grep -v -E 'github.*Anchor'; then - num_broken=$(grep broken "$LOGFILE" | grep -v -E 'github.*Anchor' | wc -l) - echo "Broken links found: $num_broken" - cleanup - exit 1 -fi -cleanup -exit 0 diff --git a/make_help_scripts/check_links.py b/make_help_scripts/check_links.py new file mode 100755 index 00000000000..0182e19ba86 --- /dev/null +++ b/make_help_scripts/check_links.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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. + +# This script is used to check the links in the ROS documentation. +# due to a bug in the sphinx linkchecker, github anchors are false positives and +# have to be explicitly ignored +# https://github.com/sphinx-doc/sphinx/issues/9016 + +import os +import shutil +import subprocess +import sys + +LOGFILE = "linkcheck.log" + +def cleanup(): + os.remove(LOGFILE) + shutil.rmtree("doc/api/", ignore_errors=True) + +def main(): + if len(sys.argv) != 2: + print("Usage: python check_links.py ") + sys.exit(1) + + html_dir = sys.argv[1] + + # Copy API documentation to local directory + shutil.copytree(os.path.join(html_dir, "doc", "api"), "doc/api/", dirs_exist_ok=True) + + # Run linkcheck + with open(LOGFILE, "w") as logfile: + subprocess.run(["make", "linkcheck"], stdout=logfile, stderr=subprocess.PIPE) + + # Check for broken links + with open(LOGFILE, "r") as logfile: + broken_links = [line for line in logfile if "broken" in line and "github" not in line] + + if broken_links: + num_broken = len(broken_links) + print(f"Broken links found: {num_broken}") + for link in broken_links: + print(link) + cleanup() + sys.exit(1) + + cleanup() + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/make_help_scripts/create_api b/make_help_scripts/create_api deleted file mode 100755 index a67e3b924ba..00000000000 --- a/make_help_scripts/create_api +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -create_api () { - cd "$api_dir" || { echo "$api_dir does not exist. Exiting!"; exit "$ERRCODE"; } - git checkout "$api_branch"; - git pull - doxygen doc/Doxyfile - mkdir -p ../../"$build_dir"/html/doc/api/ - cp -r doc/_build/html/. ../../"$build_dir"/html/doc/api/ - rm -rf doc/_build -} - -cleanup() { - cd "$base_dir" || { echo "Changing back to base dir went wrong. You have to remove $api_dir yourself. Exiting!"; exit "$ERRCODE"; } - if [ -d "$api_dir" ]; - then - rm -rf "$api_dir" - else - echo "Could not delete $api_dir. Something went wrong. You have to cleanup yourself. Exiting!" - exit - fi -} - -cd "$base_dir" || { echo "Could not checkout base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } -if [ -d "$api_dir" ]; -then - create_api - cleanup -else - git clone https://github.com/ros-controls/"$api_repo" doc/"$api_repo" || { echo "Could not clone $api_repo. Exiting!"; exit "$ERRCODE"; } - create_api - cleanup -fi diff --git a/make_help_scripts/create_api.py b/make_help_scripts/create_api.py new file mode 100755 index 00000000000..46f92fe5a55 --- /dev/null +++ b/make_help_scripts/create_api.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import shutil +import deploy_defines + +def create_api(): + os.chdir(os.path.join(deploy_defines.base_dir, "doc")) + version = deploy_defines.branch_version[deploy_defines.base_branch] + os.system(f"( cat Doxyfile ; echo \"PROJECT_NAME = ros2_control - {version}\" ) | doxygen -") + os.makedirs(os.path.join(deploy_defines.base_dir, deploy_defines.build_dir, "html/doc/api/"), exist_ok=True) + shutil.copytree("tmp/html/", os.path.join(deploy_defines.base_dir, deploy_defines.build_dir, "html/doc/api/"), dirs_exist_ok=True) + shutil.rmtree("tmp") + +os.chdir(deploy_defines.base_dir) +create_api() diff --git a/make_help_scripts/create_api_multi_version b/make_help_scripts/create_api_multi_version deleted file mode 100755 index 0534fb246fd..00000000000 --- a/make_help_scripts/create_api_multi_version +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -create_apis () { - cd "$api_dir" || { echo "$api_dir does not exist. Exiting!"; exit "$ERRCODE"; } - for branch in "${!branch_version[@]}"; - do git checkout ${branch_version[$branch]}; - git pull - doxygen doc/Doxyfile - mkdir -p ../../"$build_dir"/html/"$branch"/doc/api/ - cp -r doc/_build/html/. ../../"$build_dir"/html/"$branch"/doc/api/ - rm -rf doc/_build - done -} - -cleanup() { - cd "$base_dir" || { echo "Changing back to basdir went wrong. You have to remove $api_dir yourself. Exiting!"; exit "$ERRCODE"; } - if [ -d "$api_dir" ]; - then - rm -rf "$api_dir" - else - echo "Could not delete $api_dir. Something went wrong. You have to cleanup yourself. Exiting!" - exit - fi -} - -cd "$base_dir" || { echo "Could not checkout base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } -if [ -d "$api_dir" ]; -then - create_apis - cleanup -else - git clone https://github.com/ros-controls/"$api_repo" doc/"$api_repo" || { echo "Could not clone $api_repo. Exiting!"; exit "$ERRCODE"; } - create_apis - cleanup -fi diff --git a/make_help_scripts/create_api_multi_version.py b/make_help_scripts/create_api_multi_version.py new file mode 100755 index 00000000000..335a31efcc1 --- /dev/null +++ b/make_help_scripts/create_api_multi_version.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import shutil +import subprocess +import deploy_defines +import add_sub_repos + +def create_apis(): + for branch, version in deploy_defines.branch_version.items(): + subprocess.run(["git", "checkout", branch], check=True) + add_sub_repos.add_sub_repositories(branch) + os.chdir("doc/") + os.system(f"( cat Doxyfile ; echo \"PROJECT_NAME = ros2_control - {version}\" ) | doxygen -") + api_output_dir = os.path.join(deploy_defines.base_dir, deploy_defines.build_dir, "html", branch, "doc", "api") + os.makedirs(api_output_dir, exist_ok=True) + shutil.copytree("tmp/html/", api_output_dir, dirs_exist_ok=True) + shutil.rmtree("tmp") + +if __name__ == "__main__": + os.chdir(deploy_defines.base_dir) + create_apis() diff --git a/make_help_scripts/create_pr_stats.py b/make_help_scripts/create_pr_stats.py index 71a061d6812..2e3df9f2697 100644 --- a/make_help_scripts/create_pr_stats.py +++ b/make_help_scripts/create_pr_stats.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 # Copyright (c) 2023 ros2_control maintainers # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/make_help_scripts/delete_sub_repos b/make_help_scripts/delete_sub_repos deleted file mode 100755 index e6516a7f31c..00000000000 --- a/make_help_scripts/delete_sub_repos +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -delete_sub_repositories () { - cd "$base_dir" || { echo "Could not checkout base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } - for repo_name in "${!subrepo_url[@]}"; - do rm -rf doc/"$repo_name"; - done -} - -delete_sub_repositories diff --git a/make_help_scripts/delete_sub_repos.py b/make_help_scripts/delete_sub_repos.py new file mode 100755 index 00000000000..7515464c3fe --- /dev/null +++ b/make_help_scripts/delete_sub_repos.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import subprocess +import deploy_defines + +def delete_sub_repositories(base_branch): + # checkout a base for defined starting point + os.chdir(deploy_defines.base_dir) + for repo_name in deploy_defines.repos.keys(): + repo_path = os.path.join("doc", repo_name) + if os.path.isdir(repo_path): + print(f"Delete {repo_path}") + subprocess.run(["rm", "-rf", repo_path], check=True) + +if __name__ == "__main__": + delete_sub_repositories(deploy_defines.base_branch) diff --git a/make_help_scripts/delete_tmp_commits b/make_help_scripts/delete_tmp_commits deleted file mode 100755 index b56007f3453..00000000000 --- a/make_help_scripts/delete_tmp_commits +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -# shellckeck source=deploy_defines -# source deploy_defines regardless of startingpoint -DIR="${BASH_SOURCE%/*}" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/deploy_defines" || { echo "Could not source deploy_defines script. This is needed for correct execution. Exiting!"; exit; } - -# checkout a base -cd "$base_dir" || { echo "Could not checkout base dir of control.ros.org. Exiting!"; exit "$ERRCODE"; } -git checkout "$base_branch" || { echo "Exiting!"; exit $ERRCODE; } - -# delete temporary created commits -for branch in "${!branch_version[@]}"; - do echo "Revert to last changes before temporary multiversion commit on: $branch."; - git checkout "$branch" - git reset --hard HEAD~1 - git checkout "$base_branch" -done diff --git a/make_help_scripts/delete_tmp_commits.py b/make_help_scripts/delete_tmp_commits.py new file mode 100755 index 00000000000..c01b6215e9c --- /dev/null +++ b/make_help_scripts/delete_tmp_commits.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import subprocess +import deploy_defines + +def revert_temporary_commits(): + os.chdir(deploy_defines.base_dir) + subprocess.run(["git", "checkout", deploy_defines.base_branch], check=True) + + for branch, _ in deploy_defines.branch_version.items(): + print(f"Revert to last changes before temporary multiversion commit on: {branch}.") + subprocess.run(["git", "checkout", branch], check=True) + subprocess.run(["git", "reset", "--hard", "HEAD~1"], check=True) + subprocess.run(["git", "checkout", deploy_defines.base_branch], check=True) + +if __name__ == "__main__": + revert_temporary_commits() diff --git a/make_help_scripts/deploy_defines b/make_help_scripts/deploy_defines deleted file mode 100755 index 01d4db1c8a5..00000000000 --- a/make_help_scripts/deploy_defines +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash - -# This file includes all the definitions used in the other scripts -api_repo="ros2_control" -api_dir="doc/$api_repo" -script_base_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -# should by control.ros.org folder -base_dir="$(dirname "$script_base_dir")" -# branch from which is started to checkout other branches -base_branch="iron" -build_dir="_build" - -# pr stats -pr_stats_files=("reviewers_maintainers_stats_recent.html" - "reviewers_stats_recent.html" - "reviewers_maintainers_stats.html" - "reviewers_stats.html" - "contributors_maintainers_stats_recent.html" - "contributors_stats_recent.html" - "contributors_maintainers_stats.html" - "contributors_stats.html") -pr_stats_cache_folder="reviews" -pr_stats_target_folder="./doc/acknowledgements" - -add_pr_stats_file () { - for pr_stats_filename in "${pr_stats_files[@]}"; do - ORIGFILE="$HOME/$pr_stats_cache_folder/$pr_stats_filename" - # echo $ORIGFILE - if test -f "$ORIGFILE"; then - echo "Copy PR stats file '${pr_stats_filename}' to '${pr_stats_target_folder}'" - cp ${ORIGFILE} ${pr_stats_target_folder} - else - echo "Create empty PR stats file '${pr_stats_filename}' in '${pr_stats_target_folder}'" - echo "No pr statistics available yet." > ${pr_stats_target_folder}/${pr_stats_filename} - fi - done -} - -# definition single html -# the branch from which the api is checked out and built -api_branch="iron" - -# definitions for multiversion -# branches on which the temporary commits are created and which branch should be checked out in the subrepositories -# ["branch checked out for mutliversion"]="branch checked out for all subrepos" -declare -A branch_version=( ["foxy"]="foxy" ["galactic"]="galactic" ["humble"]="humble" ["iron"]="iron") - - -# the subrepos which are cloned into the branches and, optionally, their corresponding PR for checkout -declare -A subrepo_url=( ["ros2_control"]="https://github.com/ros-controls/ros2_control" ["ros2_controllers"]="https://github.com/ros-controls/ros2_controllers" ["ros2_control_demos"]="https://github.com/ros-controls/ros2_control_demos" ["gazebo_ros2_control"]="https://github.com/ros-controls/gazebo_ros2_control" ["gz_ros2_control"]="https://github.com/ros-controls/gz_ros2_control") -declare -A subrepo_pr=( ["ros2_control"]=$ROS2_CONTROL_PR ["ros2_controllers"]=$ROS2_CONTROLLERS_PR ["ros2_control_demos"]=$ROS2_CONTROL_DEMOS_PR ["gazebo_ros2_control"]=$GAZEBO_ROS2_CONTROL_PR ["gz_ros2_control"]=$GZ_ROS2_CONTROL_PR) diff --git a/make_help_scripts/deploy_defines.py b/make_help_scripts/deploy_defines.py new file mode 100644 index 00000000000..b68b0aee53e --- /dev/null +++ b/make_help_scripts/deploy_defines.py @@ -0,0 +1,176 @@ +# Copyright (c) 2023 ros2_control maintainers +# +# 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 os +import shutil + +# This file includes all the definitions used in the other scripts +script_base_dir = os.path.dirname(os.path.abspath(__file__)) +# should be control.ros.org folder +base_dir = os.path.dirname(script_base_dir) +# branch from which is started to checkout other branches +if os.environ.get('BASE_BRANCH_PR') is not None: + base_branch = os.environ.get('BASE_BRANCH_PR') +elif os.environ.get('BASE_BRANCH') is not None: + base_branch = os.environ.get('BASE_BRANCH') +else: + base_branch = "iron" +print(f"Using base_branch: {base_branch}") + +build_dir = "_build" + +# pr stats +pr_stats_files = [ + "reviewers_maintainers_stats_recent.html", + "reviewers_stats_recent.html", + "reviewers_maintainers_stats.html", + "reviewers_stats.html", + "contributors_maintainers_stats_recent.html", + "contributors_stats_recent.html", + "contributors_maintainers_stats.html", + "contributors_stats.html" +] +pr_stats_cache_folder = "reviews" +pr_stats_target_folder = "./doc/acknowledgements" + +def add_pr_stats_file(): + for pr_stats_filename in pr_stats_files: + orig_file = os.path.join(os.environ['HOME'], pr_stats_cache_folder, pr_stats_filename) + if os.path.isfile(orig_file): + print(f"Copy PR stats file '{pr_stats_filename}' to '{pr_stats_target_folder}'") + shutil.copy(orig_file, pr_stats_target_folder) + else: + print(f"Create empty PR stats file '{pr_stats_filename}' in '{pr_stats_target_folder}'") + with open(os.path.join(pr_stats_target_folder, pr_stats_filename), 'w') as f: + f.write("No pr statistics available yet.") + +# definition single html +# the branch from which the api is checked out and built +api_branch = "master" + +# definitions for multiversion +# branches on which the temporary commits are created +# {"branch checked out for multiversion": "branch checked out for all subrepos with maps below"} +branch_version = { + "foxy": "foxy", + "galactic": "galactic", + "humble": "humble", + base_branch: "iron", + "master": "rolling" # master is rolling, PRs are tested on rolling +} + +# the subrepos which are cloned into the branches and, optionally, their corresponding PR for checkout +# and a dict, which branch should be checked out in the subrepositories + +repos = { + "ros2_control": { + "url": "https://github.com/ros-controls/ros2_control", + "branch_version": { + "foxy": "foxy", + "galactic": "galactic", + "humble": "humble", + "iron": "iron", + "rolling": "master" # master is rolling + }, + "pr": os.environ.get('ROS2_CONTROL_PR') + }, + "ros2_controllers": { + "url": "https://github.com/ros-controls/ros2_controllers", + "branch_version": { + "foxy": "foxy", + "galactic": "galactic", + "humble": "humble", + "iron": "iron", + "rolling": "master" # master is rolling + }, + "pr": os.environ.get('ROS2_CONTROLLERS_PR') + }, + "ros2_control_demos": { + "url": "https://github.com/ros-controls/ros2_control_demos", + "branch_version": { + "foxy": "foxy", + "galactic": "galactic", + "humble": "humble", + "iron": "iron", + "rolling": "master" # master is rolling + }, + "pr": os.environ.get('ROS2_CONTROL_DEMOS_PR') + }, + "gazebo_ros2_control": { + "url": "https://github.com/ros-controls/gazebo_ros2_control", + "branch_version": { + "foxy": "foxy", + "galactic": "galactic", + "humble": "humble", + "iron": "iron", + "rolling": "master" # master is rolling + }, + "pr": os.environ.get('GAZEBO_ROS2_CONTROL_PR') + }, + "gz_ros2_control": { + "url": "https://github.com/ros-controls/gz_ros2_control", + "branch_version": { + "foxy": "foxy", + "galactic": "galactic", + "humble": "humble", + "iron": "iron", + "rolling": "master" # master is rolling + }, + "pr": os.environ.get('GZ_ROS2_CONTROL_PR') + }, + "control_toolbox": { + "url": "https://github.com/ros-controls/control_toolbox", + "branch_version": { + "foxy": "foxy", + "galactic": "ros2-master", + "humble": "ros2-master", + "iron": "ros2-master", + "rolling": "ros2-master" # master is rolling + }, + "pr": None + }, + "control_msgs": { + "url": "https://github.com/ros-controls/control_msgs", + "branch_version": { + "foxy": "foxy-devel", + "galactic": "galactic-devel", + "humble": "humble", + "iron": "master", + "rolling": "master" # master is rolling + }, + "pr": None + }, + "realtime_tools": { + "url": "https://github.com/ros-controls/realtime_tools", + "branch_version": { + "foxy": "foxy-devel", + "galactic": "master", + "humble": "master", + "iron": "master", + "rolling": "master" # master is rolling + }, + "pr": None + }, + "kinematics_interface": { + "url": "https://github.com/ros-controls/kinematics_interface", + "branch_version": { + "foxy": "humble", + "galactic": "humble", + "humble": "humble", + "iron": "master", + "rolling": "master" # master is rolling + }, + "pr": None + } +}