Guide du développeur ROS 2

Cette page définit les pratiques et politiques que nous employons lors du développement de ROS 2.

Principes généraux

Certains principes sont communs à tous les développements ROS 2 :

  • Propriété partagée : toute personne travaillant sur ROS 2 doit se sentir propriétaire de toutes les parties du système. L’auteur original d’un morceau de code n’a aucune permission ou obligation spéciale de contrôler ou de maintenir ce morceau de code. Chacun est libre de proposer des modifications n’importe où, de gérer n’importe quel type de ticket et d’examiner n’importe quelle pull request.

  • Être prêt à travailler sur n’importe quoi : en corollaire de la propriété partagée, tout le monde doit être prêt à assumer n’importe quelle tâche disponible et à contribuer à n’importe quel aspect du système.

  • Demandez de l’aide : si vous rencontrez des problèmes avec quelque chose, demandez de l’aide à vos collègues développeurs, via des tickets, des commentaires ou des e-mails, selon le cas.

Pratiques de qualité

Les packages peuvent être attribués à différents niveaux de qualité en fonction des pratiques de développement auxquelles ils adhèrent, conformément aux directives de REP 2004 : Package Quality Categories . Les catégories se différencient par leurs politiques en matière de gestion des versions, de test, de documentation, etc.

Les sections suivantes sont les règles de développement spécifiques que nous suivons pour garantir que les packages de base sont de la plus haute qualité (« Niveau 1 »). Nous recommandons à tous les développeurs ROS de s’efforcer de respecter les politiques suivantes pour garantir la qualité dans l’ensemble de l’écosystème ROS.

Gestion des versions

Nous utiliserons les Semantic Versioning guidelines (semver) pour la gestion des versions.

Nous respecterons également certaines règles spécifiques à ROS construites au-dessus de la signification complète de semver :

  • Les incréments de version majeurs (c’est-à-dire les changements de rupture) ne doivent pas être effectués dans une distribution ROS publiée.

    • Les correctifs (préservant l’interface) et les incréments de version mineurs (sans rupture) ne rompent pas la compatibilité, donc ces types de modifications sont autorisées dans une version.

    • Les versions majeures de ROS sont le meilleur moment pour publier des changements de rupture. Si un package de base nécessite plusieurs changements avec rupture, ils doivent être fusionnés dans leur branche d’intégration (par exemple, roulement) pour permettre de détecter rapidement les problèmes dans CI, mais publiés ensemble pour réduire le nombre de versions majeures pour les utilisateurs de ROS.

    • Bien que les incréments majeurs nécessitent une nouvelle distribution, une nouvelle distribution ne nécessite pas nécessairement une bosse majeure (si le développement et la publication peuvent se produire sans casser l’API).

  • Pour le code compilé, l’ABI est considérée comme faisant partie de l’interface publique. Toute modification nécessitant la recompilation du code dépendant est considérée comme majeure (rupture).

    • Les changements de rupture d’ABI * peuvent * être apportés dans une version mineure * avant * une version de distribution (ajoutée à la version continue).

  • Nous appliquons la stabilité de l’API pour les packages de base dans Dashing et Eloquent même si leurs principaux composants de version sont 0, malgré la spécification de SemVer concernant le développement initial.

    • Par la suite, les paquets doivent s’efforcer d’atteindre un état mature et passer à la version 1.0.0 afin de correspondre aux spécifications de semver.

Mises en garde

Ces règles sont * au mieux *. Dans des cas extrêmes peu probables, il peut être nécessaire de casser l’API dans une version/distribution majeure. Le fait qu’une pause imprévue incrémente la version majeure ou mineure sera évalué au cas par cas.

Par exemple, considérons une situation impliquant une tortue X publiée, correspondant à la version majeure 1.0.0, et une tortue Y publiée, correspondant à la version majeure 2.0.0.

Si un correctif de rupture d’API est identifié comme étant absolument nécessaire dans X-turtle, le passage à 2.0.0 n’est évidemment pas une option car 2.0.0 existe déjà.

Les solutions pour gérer la version de X-turtle dans un tel cas, toutes deux non idéales, sont :

  1. Version mineure de Bumping X-turtle : non idéale car elle viole le principe de SemVer selon lequel les changements de rupture doivent remplacer la version majeure.

  2. Faire passer la version majeure de X-turtle au-delà de Y-turtle (à `` 3.0.0``): non idéal car la version de l’ancienne distribution deviendrait supérieure à la version déjà disponible d’une distribution plus récente, ce qui invaliderait / casserait la version- code conditionnel spécifique.

Le développeur devra décider quelle solution utiliser ou, plus important encore, quel principe il est prêt à enfreindre. Nous ne pouvons pas suggérer l’un ou l’autre, mais dans les deux cas, nous exigeons que des mesures explicites soient prises pour communiquer manuellement la perturbation et son explication aux utilisateurs (au-delà de l’incrément de version).

S’il n’y avait pas de Y-turtle, même si le correctif ne serait techniquement qu’un patch, X-turtle devrait passer à 2.0.0. Ce cas adhère à SemVer, mais enfreint notre propre règle selon laquelle les incréments majeurs ne doivent pas être introduits dans une distribution publiée.

C’est pourquoi nous considérons les règles de versioning best-effort. Aussi improbables que soient les exemples ci-dessus, il est important de définir avec précision notre système de gestion des versions.

Déclaration d’API publique

Selon semver, chaque paquet doit clairement déclarer une API publique. Nous utiliserons la section « Public API Declaration » de la déclaration de qualité d’un package pour déclarer quels symboles font partie de l’API publique.

Pour la plupart des packages C et C++, la déclaration est n’importe quel en-tête qu’il installe. Cependant, il est acceptable de définir un ensemble de symboles considérés comme privés. Éviter les symboles privés dans les en-têtes peut aider à la stabilité de l’ABI, mais n’est pas obligatoire.

Pour d’autres langages comme Python, une API publique doit être explicitement définie, de sorte qu’il soit clair sur quels symboles on peut s’appuyer en ce qui concerne les directives de version. L’API publique peut également être étendue pour créer des artefacts tels que des variables de configuration, des fichiers de configuration CMake, etc., ainsi que des exécutables, des options et des sorties de ligne de commande. Tous les éléments de l’API publique doivent être clairement indiqués dans la documentation du package. Si quelque chose que vous utilisez n’est pas explicitement répertorié dans le cadre de l’API publique dans la documentation du package, vous ne pouvez pas vous attendre à ce qu’il ne change pas entre les versions mineures ou correctives.

Stratégie d’abandon

Dans la mesure du possible, nous utiliserons également la stratégie de dépréciation et de migration tic-tac pour les incréments de version majeurs. De nouvelles dépréciations viendront dans une nouvelle version de distribution, accompagnées d’avertissements du compilateur indiquant que la fonctionnalité est obsolète. Dans la prochaine version, la fonctionnalité sera complètement supprimée (pas d’avertissement).

Exemple de fonction foo obsolète et remplacée par la fonction bar :

Version

API

X-tortue

void foo();

Y-tortue

[[deprecated(« use bar() »)]] void foo(); <br> void bar();

Z-tortue

barre vide();

Nous ne devons pas ajouter de dépréciations après la sortie d’une distribution. Cependant, les dépréciations ne nécessitent pas nécessairement un changement de version majeur. Une dépréciation peut être introduite dans un bump de version mineure si le bump se produit avant la sortie de la distribution (similaire aux changements de rupture d’ABI).

Par exemple, si X-turtle commence son développement en tant que 2.0.0, une dépréciation peut être ajoutée dans 2.1.0 avant la sortie de X-turtle.

Nous essaierons de maintenir autant que possible la compatibilité entre les distributions. Cependant, comme les mises en garde associées à SemVer, le tic-tac ou même la dépréciation en général peuvent être impossibles à respecter complètement dans certains cas.

Changer le processus de contrôle

  • Toutes les modifications doivent passer par une pull request.

  • Nous appliquerons le Certificat d’origine du développeur (DCO) sur les demandes d’extraction dans les référentiels ROSSore.

    • Il exige que tous les messages de commit contiennent la ligne Signed-off-by avec une adresse e-mail qui correspond à l’auteur du commit.

    • Vous pouvez passer -s / --signoff à l’invocation git commit ou écrire le message attendu manuellement (par exemple Signed-off-by: Your Name Developer <your.name@ exemple.com>).

    • DCO n’est pas requis pour les demandes d’extraction qui traitent uniquement de la suppression des espaces blancs, de la correction des fautes de frappe et d’autres modifications triviales.

  • Exécutez toujours les travaux CI pour toutes les plates-formes de niveau 1 pour chaque demande d’extraction et incluez des liens vers les travaux dans la demande d’extraction. (Si vous n’avez pas accès aux travaux Jenkins, quelqu’un les déclenchera pour vous.)

  • Un minimum d’une approbation d’un autre développeur qui n’est pas l’auteur de la demande d’extraction est nécessaire pour la considérer comme approuvée. L’approbation est requise avant la fusion.

    • Les forfaits peuvent choisir d’augmenter ce nombre.

  • Toute modification requise de la documentation (documentation de l’API, documentation des fonctionnalités, notes de version, etc.) doit être proposée avant de fusionner les modifications associées.

Lignes directrices pour le rétroportage des PR

Lors de la modification d’une ancienne version de ROS :

  • Assurez-vous que les fonctionnalités ou les correctifs sont acceptés et fusionnés dans la branche roulante avant d’ouvrir un PR pour rétroporter les modifications vers les anciennes versions.

  • Lors de la rétroportation vers des versions plus anciennes, envisagez également de rétroporter vers toute autre versions encore prises en charge, même les versions non-LTS.

  • Si vous rétroportez un seul PR dans son intégralité, intitulez le PR rétroporté « [Distro] <nom du PR d’origine> ». Si vous rétroportez un sous-ensemble de modifications d’un ou de plusieurs PR, le titre doit être « [Distro] <description des modifications> ».

  • Lien vers tous les PR dont vous rétroportez les modifications à partir de la description de votre PR de rétroportage. Dans un rétroportage Dashing d’un changement Foxy, vous n’avez pas besoin de créer un lien vers le rétroportage Eloquent du même changement.

Documentation

Tous les packages doivent avoir ces éléments de documentation présents dans leur README ou liés à partir de leur README :

  • Description et objectif

  • Définition et description de l’API publique

  • Exemples

  • Comment créer et installer (doit faire référence à des outils/flux de travail externes)

  • Comment créer et exécuter des tests

  • Comment construire une documentation

  • Comment développer (utile pour décrire des choses comme python setup.py develop)

  • Déclarations de licence et de copyright

Chaque fichier source doit avoir une licence et une déclaration de copyright, vérifiée avec un linter automatisé.

Chaque paquet doit avoir un fichier LICENSE, généralement la licence Apache 2.0, à moins que le paquet n’ait une licence permissive existante (par exemple, rviz utilise un BSD à trois clauses).

Chaque package doit se décrire lui-même et son objectif en supposant, autant que possible, que le lecteur est tombé dessus sans connaissance préalable de ROS ou d’autres projets connexes.

Chaque package doit définir et décrire son API publique afin que les utilisateurs s’attendent raisonnablement à ce qui est couvert par la politique de version sémantique. Même en C et C++, où l’API publique peut être appliquée par la vérification de l’API et de l’ABI, c’est une bonne occasion de décrire la disposition du code et la fonction de chaque partie du code.

Il devrait être facile de prendre n’importe quel package et à partir de la documentation de ce package, comprendre comment construire, exécuter, construire et exécuter des tests, et construire la documentation. Évidemment, nous devons éviter de nous répéter pour les flux de travail courants, comme la création d’un package dans un espace de travail, mais les flux de travail de base doivent être décrits ou référencés.

Enfin, il devrait inclure toute documentation destinée aux développeurs. Cela peut inclure des flux de travail pour tester le code en utilisant quelque chose comme python setup.py develop, ou cela peut signifier décrire comment utiliser les points d’extension fournis par votre package.

Exemples:

(Les documents API ne sont pas encore générés automatiquement)

Essai

Tous les packages doivent avoir un certain niveau de tests système, d’intégration et/ou unitaires.

Les tests unitaires doivent toujours se trouver dans le package en cours de test et doivent utiliser des outils tels que Mock pour essayer de tester des parties étroites de la base de code dans des scénarios construits. Les tests unitaires ne doivent pas introduire de dépendances de test qui ne sont pas des outils de test, par ex. gtest, nosetest, pytest, mock, etc…

Les tests d’intégration peuvent tester les interactions entre des parties du code ou entre des parties du code et le système. Ils testent souvent les interfaces logicielles de manière à ce que nous attendions de l’utilisateur qu’il les utilise. Comme les tests unitaires, les tests d’intégration doivent être dans le package qui est testé et ne doivent pas introduire de dépendances de test non liées à l’outil, sauf en cas d’absolue nécessité, c’est-à-dire que toutes les dépendances non liées à l’outil ne doivent être autorisées que sous un examen minutieux, elles doivent donc être évitées si possible.

Les tests système sont conçus pour tester des situations de bout en bout entre les packages et doivent être dans leurs propres packages pour éviter les packages gonflés ou couplés et pour éviter les dépendances circulaires.

En général, il convient d’éviter de minimiser les dépendances de test externes ou entre packages pour éviter les dépendances circulaires et les packages de test étroitement couplés.

Tous les packages doivent avoir des tests unitaires et éventuellement des tests d’intégration, mais le degré auquel ils doivent les avoir est basé sur la catégorie de qualité du package. Les sous-sections suivantes s’appliquent aux forfaits de « niveau 1 » :

Couverture de code

Nous fournirons une couverture de ligne et atteindrons une couverture de ligne supérieure à 95 %. Si un objectif de pourcentage inférieur est justifiable, il doit être clairement documenté. Nous pouvons fournir une couverture de branche ou exclure du code de la couverture (code de test, code de débogage, etc.). Nous exigeons que la couverture augmente ou reste la même avant de fusionner une modification, mais il peut être acceptable d’apporter une modification qui diminue la couverture du code avec une justification appropriée (par exemple, la suppression du code qui était précédemment couvert peut entraîner une baisse du pourcentage).

Performance

Nous recommandons fortement les tests de performances, mais reconnaissons qu’ils n’ont pas de sens pour certains packages. S’il y a des tests de performance, nous choisirons de vérifier chaque changement ou avant chaque version ou les deux. Nous aurons également besoin d’une justification pour fusionner un changement ou faire une version qui réduit les performances.

Linters et analyse statique

Nous allons utiliser style de code ROS et l’appliquer avec les linters de ament_lint_common. Tous les linters/analyses statiques qui font partie de ament_lint_common doivent être utilisés.

La documentation ament_lint_auto fournit des informations sur l’exécution de ament_lint_common.

Pratiques générales

Certaines pratiques sont communes à tous les développements ROS 2.

Ces pratiques n’affectent pas le niveau de qualité du package tel que décrit dans REP 2004, mais sont toujours fortement recommandées pour le processus de développement.

Questions

Lorsque vous signalez un problème, assurez-vous de :

  • Incluez suffisamment d’informations pour qu’une autre personne comprenne le problème. Dans ROS 2, les points suivants sont nécessaires pour déterminer la cause d’un problème. Tester avec autant d’alternatives dans chaque catégorie que possible sera particulièrement utile.

    • Le système d’exploitation et la version. Raisonnement : ROS 2 prend en charge plusieurs plates-formes, et certains bogues sont spécifiques à des versions particulières de systèmes d’exploitation/compilateurs.

    • La méthode d’installation. Raisonnement : Certains problèmes ne se manifestent que si ROS 2 a été installé à partir de « fat archives » ou de Debians. Cela peut nous aider à déterminer si le problème vient du processus d’emballage.

    • La version spécifique de ROS 2. Raisonnement : Certains bogues peuvent être présents dans une version particulière de ROS 2 et corrigés ultérieurement. Il est important de savoir si votre installation inclut ces correctifs.

    • L’implémentation DDS/RMW utilisée (voir cette page pour savoir comment déterminer lequel). Raisonnement : les problèmes de communication peuvent être spécifiques au middleware ROS sous-jacent utilisé.

    • La bibliothèque cliente ROS 2 utilisée. Raisonnement : Cela nous aide à réduire la couche de la pile à laquelle le problème pourrait survenir.

  • Incluez une liste d’étapes pour reproduire le problème.

  • En cas de bogue, envisagez de fournir un exemple court, autonome et correct (compilable) <http://sscce.org/>`__. Les problèmes sont beaucoup plus susceptibles d’être résolus si d’autres peuvent les reproduire facilement.

  • Mentionnez les étapes de dépannage qui ont déjà été essayées, notamment :

    • Mise à niveau vers la dernière version du code, qui peut inclure des correctifs de bogues qui n’ont pas encore été publiés. Voir cette section et suivez les instructions pour obtenir les branches « rolling ».

    • Essayer avec une autre implémentation RMW. Voir cette page pour savoir comment procéder.

Branches

Note

Ce ne sont que des lignes directrices. Il appartient au responsable du paquet de choisir des noms de branche qui correspondent à son propre flux de travail.

Il est recommandé d’avoir des branches séparées dans le référentiel source d’un package pour chaque distribution ROS qu’il cible. Ces branches portent généralement le nom de la distribution qu’elles ciblent. Par exemple, une branche humble pour le développement ciblant spécifiquement la distribution Humble.

Des sorties sont également faites à partir de ces branches, en ciblant la distribution appropriée. Le développement ciblé sur une distribution ROS spécifique peut se produire sur la branche appropriée. Par exemple : les commits de développement ciblant foxy sont créés dans la branche foxy, et les versions de package pour foxy sont créées à partir de cette même branche.

Note

Cela nécessite que les responsables du paquet effectuent des backports ou des forwardports selon les besoins pour maintenir toutes les branches à jour avec les fonctionnalités. Les mainteneurs doivent également effectuer une maintenance générale (corrections de bogues, etc.) sur toutes les branches à partir desquelles des versions de paquets sont encore créées.

Par exemple, si une fonctionnalité est fusionnée dans la branche spécifique à Rolling (par exemple, rolling ou main), et que cette fonctionnalité est également appropriée à la distribution Humble (ne casse pas l’API, etc.), alors il est recommandé de rétroporter la fonctionnalité sur la branche spécifique à Humble.

Les responsables peuvent créer des versions pour ces distributions plus anciennes si de nouvelles fonctionnalités ou des corrections de bogues sont disponibles.

Qu’en est-il de main et rolling ** ?**

main cible généralement Rolling (et donc, la prochaine distribution ROS inédite), bien que les mainteneurs puissent décider de développer et de publier à partir d’un branche rolling à la place.

Demandes d’extraction

  • Une demande d’extraction ne doit se concentrer que sur un seul changement. Les modifications distinctes doivent être placées dans des demandes d’extraction distinctes. Voir GitHub’s guide to writing the perfect pull request.

  • Un patch doit être de taille minimale et éviter tout type de modifications inutiles.

  • Une demande d’extraction doit contenir un nombre minimum de commits significatifs.

    • Vous pouvez créer de nouveaux commits pendant que la demande d’extraction est en cours d’examen.

  • Avant de fusionner une demande d’extraction, toutes les modifications doivent être écrasées dans un petit nombre de commits sémantiques pour garder l’historique clair.

    • Mais évitez d’écraser les commits pendant qu’une pull request est en cours d’examen. Vos examinateurs pourraient ne pas remarquer que vous avez apporté la modification, introduisant ainsi un risque de confusion. De plus, vous allez écraser avant de fusionner de toute façon ; il n’y a aucun avantage à le faire tôt.

  • Tout développeur est invité à examiner et à approuver une demande d’extraction (voir Principes généraux).

  • Lorsque vous commencez à examiner une demande d’extraction, commentez la demande d’extraction afin que les autres développeurs sachent que vous l’examinez.

  • La révision de la demande d’extraction n’est pas en lecture seule, le réviseur faisant des commentaires et attendant ensuite que l’auteur y réponde. En tant que réviseur, n’hésitez pas à apporter des améliorations mineures (fautes de frappe, problèmes de style, etc.) sur place. En tant qu’ouvreur d’une pull-request, si vous travaillez dans un fork, cochez la case pour autoriser les modifications des contributeurs en amont aidera avec ce qui précède. En tant que réviseur, n’hésitez pas non plus à apporter des améliorations plus substantielles, mais envisagez de les mettre dans une branche distincte (soit mentionner la nouvelle branche dans un commentaire, soit ouvrir une autre pull request de la nouvelle branche vers la branche d’origine).

  • N’importe quel développeur (l’auteur, le réviseur ou quelqu’un d’autre) peut fusionner n’importe quelle demande d’extraction approuvée.

Gestion des versions de la bibliothèque

Nous versionnerons toutes les bibliothèques d’un package ensemble. Cela signifie que les bibliothèques héritent de leur version du package. Cela empêche les versions de bibliothèque et de package de diverger et partage le raisonnement avec la politique de publication de packages qui partagent un référentiel ensemble. Si vous avez besoin de bibliothèques pour différentes versions, envisagez de les diviser en différents packages.

Processus de développement

  • La branche par défaut (dans la plupart des cas la branche roulante) doit toujours se construire, réussir tous les tests et compiler sans avertissement. Si à tout moment il y a une régression, la priorité absolue est de restaurer au moins l’état précédent.

  • Compilez toujours avec les tests activés.

  • Exécutez toujours les tests localement après les modifications et avant de les proposer dans une demande d’extraction. En plus d’utiliser des tests automatisés, exécutez également le chemin de code modifié manuellement pour vous assurer que le correctif fonctionne comme prévu.

  • Exécutez toujours les travaux CI pour toutes les plates-formes pour chaque demande d’extraction et incluez des liens vers les travaux dans la demande d’extraction.

Pour plus de détails sur le workflow de développement logiciel recommandé, consultez la section Cycle de vie du développement logiciel.

Modifications de l’API RMW

Lors de la mise à jour de RMW API, il est nécessaire que les implémentations RMW pour les bibliothèques middleware de niveau 1 soient également mises à jour. Par exemple, une nouvelle fonction rmw_foo() introduite dans l’API RMW doit être implémentée dans les packages suivants (à partir de ROS Galactic) :

Les mises à jour pour les bibliothèques middleware non de niveau 1 doivent également être envisagées si possible (par exemple, en fonction de la taille du changement). Voir REP-2000 pour la liste des bibliothèques middleware et leurs niveaux.

Suivi des tâches

Pour aider à organiser le travail sur ROS 2, l’équipe de développement principale de ROS 2 utilise des tableaux de projet GitHub de style kanban <https://github.com/orgs/ros2/projects>`_.

Cependant, tous les problèmes et demandes d’extraction ne sont pas suivis sur les tableaux de projet. Un tableau représente généralement une version à venir ou un projet spécifique. Les tickets peuvent être consultés sur une base par dépôt en parcourant les référentiels ROS 2” pages de problèmes individuels.

Les noms et les objectifs des colonnes dans un tableau de projet ROS 2 donné varient, mais suivent généralement la même structure générale :

  • À faire : problèmes pertinents pour le projet, prêts à être attribués

  • En cours : demandes d’extraction actives sur lesquelles des travaux sont actuellement en cours

  • En cours d’examen : demandes d’extraction pour lesquelles le travail est terminé et prêt à être examiné, et pour celles qui sont actuellement en cours d’examen

  • Terminé : les demandes d’extraction et les problèmes associés sont fusionnés/fermés (à titre informatif)

Pour demander l’autorisation d’apporter des modifications, il vous suffit de commenter les tickets qui vous intéressent. En fonction de la complexité, il peut être utile de décrire comment vous envisagez de le résoudre. Nous mettrons à jour le statut (si vous n’en avez pas l’autorisation) et vous pourrez commencer à travailler sur une pull request. Si vous contribuez régulièrement, nous vous accorderons probablement simplement la permission de gérer vous-même les étiquettes, etc.

Conventions de programmation

  • Programmation défensive : assurez-vous que les hypothèses sont maintenues le plus tôt possible. Par exemple. vérifiez chaque code de retour et assurez-vous de lever au moins une exception jusqu’à ce que le cas soit traité avec plus de grâce.

  • Tous les messages d’erreur doivent être dirigés vers stderr.

  • Déclarez les variables dans la portée la plus étroite possible.

  • Gardez le groupe d’éléments (dépendances, importations, inclusions, etc.) classés par ordre alphabétique.

Spécifique C++

  • Évitez d’utiliser le streaming direct (<<) vers stdout / stderr pour empêcher l’entrelacement entre plusieurs threads.

  • Évitez d’utiliser des références pour std::shared_ptr car cela perturbe le comptage des références. Si l’instance d’origine sort de la portée et que la référence est utilisée, elle accède à la mémoire libérée.

Disposition du système de fichiers

La disposition du système de fichiers des packages et des référentiels doit suivre les mêmes conventions afin de fournir une expérience cohérente aux utilisateurs parcourant notre code source.

Disposition de l’emballage

  • src : contient tout le code C et C++

    • Contient également des en-têtes C/C++ qui ne sont pas installés

  • include : contient tous les en-têtes C et C++ qui sont installés

    • <nom du package> : pour tous les en-têtes installés en C et C++, ils doivent être placés dans un espace de nom de dossier par le nom du package

  • <package_name> : contient tout le code Python

  • test : contient tous les tests automatisés et les données de test

  • config : contient les fichiers de configuration, par ex. Fichiers de paramètres YAML et fichiers de configuration RViz

  • doc : contient toute la documentation

  • launch : contient tous les fichiers de lancement

  • package.xml : tel que défini par REP-0140 (peut être mis à jour pour le prototypage)

  • CMakeLists.txt : seuls les packages ROS qui utilisent CMake

  • setup.py : uniquement les packages ROS qui utilisent uniquement du code Python

  • README : peut être rendu sur GitHub en tant que page de destination pour le projet

    • Cela peut être aussi court ou détaillé que possible, mais il doit au moins être lié à la documentation du projet

    • Envisagez de mettre un CI ou une balise de couverture de code dans ce README

    • Il peut également s’agir de .rst ou de tout autre élément pris en charge par GitHub

  • CONTRIBUTING : décrit les directives de contribution

    • Cela peut inclure l’implication de la licence, par ex. lors de l’utilisation de la licence Apache 2.

  • LICENSE : une copie de la licence ou des licences pour ce package

  • CHANGELOG.rst : REP-0132 journal des modifications conforme

Disposition du référentiel

Chaque package doit se trouver dans un sous-dossier portant le même nom que le package. Si un référentiel ne contient qu’un seul package, il peut éventuellement se trouver à la racine du référentiel.

Flux de travail du développeur

Nous suivons les tickets ouverts et les relations publiques actives liées aux versions à venir et aux projets plus importants à l’aide de tableaux de projets GitHub.

Le flux de travail habituel est :

  • Discutez de la conception (ticket GitHub sur le référentiel approprié et un PR de conception à https://github.com/ros2/design si nécessaire)

  • Écrire l’implémentation sur une branche de fonctionnalité sur un fork

  • Rédiger des tests

  • Activer et exécuter les linters

  • Exécutez les tests localement en utilisant colcon test (voir le colcon tutorial)

  • Une fois que tout se construit localement sans avertissement et que tous les tests réussissent, exécutez CI sur votre branche de fonctionnalité :

    • Allez sur ci.ros2.org

    • Connectez-vous (coin supérieur droit)

    • Cliquez sur la tâche ci_launcher

    • Cliquez sur « Construire avec des paramètres » (colonne de gauche)

    • Dans la première case « CI_BRANCH_TO_TEST » entrez le nom de votre branche de fonctionnalité

    • Appuyez sur le bouton construire

    (si vous n’êtes pas un committer ROS 2, vous n’avez pas accès à la ferme CI. Dans ce cas, envoyez un ping au réviseur de votre PR pour qu’il exécute CI pour vous)

  • Si votre cas d’utilisation nécessite une couverture de code en cours d’exécution :

    • Allez sur ci.ros2.org

    • Connectez-vous (coin supérieur droit)

    • Cliquez sur le travail ci_linux_coverage

    • Cliquez sur « Construire avec des paramètres » (colonne de gauche)

    • Assurez-vous de laisser « CI_BUILD_ARGS » et « CI_TEST_ARGS » avec les valeurs par défaut

    • Appuyez sur le bouton construire

    • À la fin du document, il y a des instructions sur la façon de interpréter le résultat du rapport et calculer le taux de couverture

  • Si le travail CI construit sans avertissements, erreurs et échecs de test, postez les liens de vos travaux sur votre PR ou ticket de haut niveau regroupant tous vos PRs (voir exemple ici)

    • Notez que la démarque de ces badges se trouve dans la sortie console du travail ci_launcher

  • Lorsque le PR a été approuvé :

    • la personne qui a soumis le PR le fusionne en utilisant l’option « Squash and Merge » afin que nous gardions un historique propre

      • Si les commits méritent d’être séparés : écrasez tous les nitpick/linters/typo ensemble et fusionnez l’ensemble restant

        • Remarque : chaque PR doit cibler une fonctionnalité spécifique afin que Squash et Merge aient du sens 99 % du temps

  • Supprimer la branche une fois fusionnée

Pratiques de développement architectural

Cette section décrit le cycle de vie idéal qui doit être utilisé lors de modifications architecturales importantes de ROS 2.

Cycle de vie du développement logiciel

Cette section décrit étape par étape comment planifier, concevoir et implémenter une nouvelle fonctionnalité :

  1. Création de tâche

  2. Création du document de conception

  3. Examen de la conception

  4. Mise en œuvre

  5. Révision des codes

Création de tâche

Les tâches nécessitant des modifications des parties critiques de ROS 2 doivent faire l’objet de revues de conception au cours des premières étapes du cycle de publication. Si une révision de la conception a lieu dans les étapes ultérieures, les modifications feront partie d’une future version.

  • Un problème doit être créé dans le dépôt ros2 approprié, décrivant clairement la tâche en cours.

    • Il doit avoir des critères de réussite clairs et mettre en évidence les améliorations concrètes attendues de celui-ci.

    • Si la fonctionnalité cible une version ROS, assurez-vous que cela est suivi dans le ticket de version ROS (exemple).

Rédaction du document de conception

Les documents de conception ne doivent jamais inclure d’informations confidentielles. La nécessité ou non d’un document de conception pour votre modification dépend de l’ampleur de la tâche.

  1. Vous apportez une petite modification ou corrigez un bogue :

  • Un document de conception n’est pas requis, mais un problème doit être ouvert dans le référentiel approprié pour suivre le travail et éviter la duplication des efforts.

  1. Vous implémentez une nouvelle fonctionnalité ou souhaitez contribuer à l’infrastructure appartenant à OSRF (comme Jenkins CI):

  • La documentation de conception est requise et doit être ajoutée à ros2/design pour être rendue accessible sur https://design.ros2.org/.

  • Vous devez bifurquer le référentiel et soumettre une demande d’extraction détaillant la conception.

Mentionnez le problème ros2 associé (par exemple, Design doc for task ros2/ros2#<issue id>) dans la demande d’extraction ou le message de validation. Des instructions détaillées se trouvent sur la page ROS 2 Contribute. Les commentaires de conception seront faits directement sur la demande d’extraction.

S’il est prévu que la tâche soit publiée avec une version spécifique de ROS, ces informations doivent être incluses dans la demande d’extraction.

Examen des documents de conception

Une fois que la conception est prête à être examinée, une demande d’extraction doit être ouverte et des examinateurs appropriés doivent être affectés. Il est recommandé d’inclure le(s) propriétaire(s) du projet - responsables de tous les packages impactés (tel que défini par le champ responsable package.xml, voir REP-140) - en tant que réviseurs.

  • Si le document de conception est complexe ou si les réviseurs ont des horaires contradictoires, une réunion facultative de révision de la conception peut être organisée. Dans ce cas,

    Avant la réunion

    • Envoyer une invitation à une réunion au moins une semaine à l’avance

    • Une durée de réunion d’une heure est recommandée

    • L’invitation à la réunion doit répertorier toutes les décisions à prendre lors de l’examen (décisions nécessitant l’approbation du responsable du paquet)

    • Réunion des participants requis : réviseurs de demandes d’extraction de conception

      Réunion des participants facultatifs : tous les ingénieurs OSRF, le cas échéant

    Pendant la réunion

    • Le propriétaire de la tâche dirige la réunion, présente ses idées et gère les discussions pour s’assurer qu’un accord est atteint à temps

    Après la réunion

    • Le propriétaire de la tâche doit renvoyer les notes de réunion à tous les participants

    • Si des problèmes mineurs ont été soulevés concernant la conception :

      • Le propriétaire de la tâche doit mettre à jour la demande d’extraction de document de conception en fonction des commentaires

      • Un examen supplémentaire n’est pas nécessaire

    • Si des problèmes majeurs ont été soulevés concernant la conception :

      • Il est acceptable de supprimer les sections pour lesquelles il n’y a pas d’accord clair

      • Les parties discutables de la conception peuvent être soumises à nouveau en tant que tâche distincte à l’avenir

      • Si la suppression des parties discutables n’est pas une option, travaillez directement avec les propriétaires de packages pour parvenir à un accord

  • Une fois le consensus atteint :

    • Assurez-vous que la demande d’extraction ros2/design a été fusionnée, le cas échéant

    • Mettre à jour et fermer le problème GitHub associé à cette tâche de conception

Mise en œuvre

Avant de commencer, consultez la section « Demandes d’extraction »_ pour connaître les meilleures pratiques.

  • Pour chaque dépôt à modifier :

    • Modifiez le code, passez à l’étape suivante si vous avez terminé ou à intervalles réguliers pour sauvegarder votre travail.

    • Auto-examen vos modifications en utilisant git add -i.

    • Créez un nouveau commit signé en utilisant git commit -s.

      • Une demande d’extraction doit contenir un minimum de commits sémantiquement significatifs (par exemple, un grand nombre de commits d’une ligne n’est pas acceptable). Créez de nouveaux commits de correction tout en itérant sur les commentaires, ou éventuellement, modifiez les commits existants en utilisant git commit --amend si vous ne voulez pas créer un nouveau commit à chaque fois.

      • Chaque commit doit avoir un message de commit correctement écrit et significatif. Plus d’instructions ici.

      • Le déplacement des fichiers doit être effectué dans un commit séparé, sinon git risque de ne pas suivre avec précision l’historique des fichiers.

      • Soit la description de la demande d’extraction, soit le message de validation doit contenir une référence au problème ros2 associé, de sorte qu’il est automatiquement fermé lorsque la demande d’extraction est fusionnée. Voir ce doc pour plus de détails.

      • Poussez les nouveaux commits.

Revue de code

Une fois que le changement est prêt pour la révision du code :

  • Ouvrez une demande d’extraction pour chaque référentiel modifié.

    • N’oubliez pas de suivre les meilleures pratiques relatives aux « demandes d’extraction ».

    • GitHub peut être utilisé pour créer des demandes d’extraction à partir de la ligne de commande.

    • S’il est prévu que la tâche soit publiée avec une version spécifique de ROS, ces informations doivent être incluses dans chaque demande d’extraction.

  • Les propriétaires de packages qui ont examiné le document de conception doivent être mentionnés dans la demande d’extraction.

  • SLO de révision du code : bien que la révision des demandes d’extraction soit un effort optimal, il est utile que les réviseurs commentent les demandes d’extraction dans un délai d’une semaine et que les auteurs de code répondent aux commentaires dans un délai d’une semaine, afin qu’il n’y ait pas de perte de contexte.

  • Itérer sur les commentaires comme d’habitude, modifier et mettre à jour la branche de développement si nécessaire.

  • Une fois le PR approuvé, les mainteneurs de paquets fusionneront les changements dans.

Construire une introduction à la ferme

La ferme de construction est située sur ci.ros2.org.

Chaque nuit, nous exécutons des tâches nocturnes qui construisent et exécutent tous les tests dans différents scénarios sur différentes plates-formes. De plus, nous testons toutes les demandes d’extraction sur ces plates-formes avant de les fusionner.

Il s’agit de l’ensemble actuel de plates-formes et d’architectures cibles, bien qu’il évolue au fil du temps :

  • Ubuntu 22.04 Jammy

    • amdshch

    • aarch64

  • Windows 10

    • amdshch

Il existe plusieurs catégories d’emplois sur le buildfarm :

  • tâches manuelles (déclenchées manuellement par les développeurs) :

    • ci_linux : compiler + tester le code sur Ubuntu Xenial

    • ci_linux-aarch64 : compilez + testez le code sur Ubuntu Xenial sur une machine ARM 64 bits (aarch64) ;

    • ci_linux_coverage : build + test + génération de couverture de test

    • ci_windows : compiler + tester le code sur Windows 10

    • ci_launcher : déclenche toutes les tâches répertoriées ci-dessus

  • nightly (courir tous les soirs):

    • Debug : compilez + testez le code avec CMAKE_BUILD_TYPE=Debug

      • nightly_linux_debug

      • nightly_linux-aarch64_debug

      • nightly_win_deb

    • Release : compiler + tester le code avec CMAKE_BUILD_TYPE=Release

      • nightly_linux_release

      • nightly_linux-aarch64_release

      • nightly_win_rel

    • Répété : construisez puis exécutez chaque test jusqu’à 20 fois ou jusqu’à l’échec (aka flakiness hunter)

      • nightly_linux_repeated

      • nightly_linux-aarch64_repeated

      • nightly_win_rep

    • Couverture:

      • nightly_linux_coverage : construit + teste le code + analyse la couverture pour c/c++ et python

        • les résultats sont exportés sous forme de rapport cobertura

  • packaging (exécuté toutes les nuits ; le résultat est regroupé dans une archive) :

    • packaging_linux

    • packaging_windows

Deux fermes de construction supplémentaires prennent en charge l’écosystème ROS / ROS 2 en fournissant la construction de packages source et binaires, l’intégration continue, les tests et l’analyse.

Pour plus de détails, les questions fréquemment posées et le dépannage, consultez build farms.

Remarque sur les courses de couverture

Les packages ROS 2 sont organisés de manière à ce que le code de test d’un package donné soit non seulement contenu dans le package, mais puisse également être présent dans un package différent. En d’autres termes : les packages peuvent exercer du code appartenant à d’autres packages pendant la phase de test.

Pour atteindre le taux de couverture atteint par tout le code disponible dans les packages de base ROS 2, il est recommandé d’exécuter les builds à l’aide d’un ensemble fixe de référentiels proposés. Cet ensemble est défini dans les paramètres par défaut des tâches de couverture dans Jenkins.

Comment lire le taux de couverture à partir du rapport buildfarm

Pour voir le rapport de couverture pour un package donné :

  • Lorsque la construction de ci_linux_coverage se termine, cliquez sur Rapport de couverture

  • Faites défiler jusqu’au tableau Répartition de la couverture par forfait

  • Dans le tableau, regardez la première colonne intitulée « Nom »

Les rapports de couverture dans la buildfarm incluent tous les packages qui ont été utilisés dans l’espace de travail ROS. Le rapport de couverture comprend différents chemins correspondant à un même forfait :

  • Nommez les entrées sous la forme : src.*.<repository_name>.<package_name>.* Celles-ci correspondent aux exécutions de tests unitaires disponibles dans un package par rapport à son propre code source

  • Nommez les entrées sous la forme : build.<repository_name>.<package_name>.* Celles-ci correspondent aux exécutions de tests unitaires disponibles dans un package par rapport à ses fichiers générés au moment de la construction ou de la configuration

  • Nommer les entrées sous la forme : install.<package_name>.* Elles correspondent aux tests système/d’intégration provenant des séries de tests d’autres packages

Comment calculer le taux de couverture à partir du rapport buildfarm

Obtenez le taux de couverture unitaire combiné à l’aide du script automatique :

  • Depuis le build ci_linux_coverage Jenkins, copiez l’URL du build

  • Téléchargez le script get_coverage_ros2_pkg

  • Exécutez le script : ./get_coverage_ros2_pkg.py <jenkins_build_url> <ros2_package_name> (README)

  • Récupérez les résultats de la dernière ligne « Combined unit testing » dans la sortie du script

Alternative : obtenir le taux de couverture unitaire combiné à partir du rapport de couverture (nécessite un calcul manuel) :

  • Lorsque la construction de ci_linux_coverage est terminée, cliquez sur Cobertura Coverage Report

  • Faites défiler jusqu’au tableau Répartition de la couverture par forfait

  • Dans le tableau, sous la première colonne « Name », recherchez (où <package_name> est votre package en cours de test) :

    • tous les répertoires sous le modèle src.*.<repository_name>.<package_name>.* saisissez les deux valeurs absolues dans la colonne « Lines ».

    • tous les répertoires sous le modèle build/.<repository_name>.* récupèrent les deux valeurs absolues dans la colonne « Lines ».

  • Avec la sélection précédente : pour chaque cellule, la première valeur correspond aux lignes testées et la seconde au total des lignes de code. Agrégez toutes les lignes pour obtenir le total des lignes testées et le total des lignes de code testées. Diviser pour obtenir le taux de couverture.

Comment mesurer la couverture localement à l’aide de lcov (Ubuntu)

Pour mesurer la couverture sur votre propre machine, installez lcov.

sudo apt install -y lcov

Le reste de cette section suppose que vous travaillez depuis votre espace de travail colcon. Compiler en débogage avec des drapeaux de couverture. N’hésitez pas à utiliser les drapeaux colcon pour cibler des packages spécifiques.

colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} --coverage" -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} --coverage"

lcov nécessite une ligne de base initiale, que vous pouvez produire avec la commande suivante. Mettez à jour l’emplacement du fichier de sortie selon vos besoins.

lcov --no-external --capture --initial --directory . --output-file ~/ros2_base.info

Exécutez des tests pour les packages qui comptent pour vos mesures de couverture. Par exemple, si vous mesurez rclcpp également avec test_rclcpp

colcon test --packages-select rclcpp test_rclcpp

Capturez les résultats lcov avec une commande similaire, cette fois en supprimant le drapeau --initial.

lcov --no-external --capture --directory . --output-file ~/ros2.info

Combinez les fichiers de trace .info :

lcov --add-tracefile ~/ros2_base.info --add-tracefile ~/ros2.info --output-file ~/ros2_coverage.info

Générez du HTML pour une visualisation et une annotation faciles des lignes couvertes.

mkdir -p coverage
genhtml ~/ros2_coverage.info --output-directory coverage