Contribuez à Rails 6 !

Younes Serraj
Younes Serraj20 mai 2019

Il était une fois un développeur Rails qui voulait devenir un contributeur Rails. Au fond de lui, il voulait même devenir membre de l'équipe centrale de Rails ! Un jour, il a donc décidé de faire un premier pas : il a téléchargé le code source de Ruby on Rails !

1 2wkHbbtIeZaINzdFjCRfHQ

Contribuer à Rails 6

J'ai donc téléchargé le code source de Rails :

$ git clone [email protected]com:rails/rails.git
$ cd rails
$ ls
actioncable
actionmailbox
actionmailer
actionpack
actiontext
actionview
activejob
activemodel
activerecord
activestorage
activesupport
Brewfile
ci
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Gemfile
Gemfile.lock
guides
MIT-LICENSE
package.json
rails.gemspec
RAILS_VERSION
railties
Rakefile
README.md
RELEASING_RAILS.md
tasks
tmp
tools
version.rb
yarn.lock

Merde... il y a tellement de choses ici... Je connais la plupart des composants de Rails, mais il y a aussi quelques nouveautés. Heureusement, Rails a plusieurs guides pour m'aider à combler les lacunes.

  • ActionCable est un wrapper WebSocket qui permet aux applications Rails de communiquer en temps réel avec le serveur et les clients. Si vous voulez que votre page web reçoive des notifications de votre serveur sans appels AJAX, c'est ce dont vous avez besoin.

  • ActionMailbox permet à votre application de recevoir des e-mails et de les traiter dans des contrôleurs.

  • ActionMailer permet d'envoyer des e-mails à partir de votre application.

  • ActionPack regroupe deux composants principaux : ActionDispatch et ActionController.

  • ActionDispatch est chargé d'acheminer une demande entrante vers le contrôleur/action approprié pour le traitement.

  • ActionController a la responsabilité de traiter la demande et de fournir une réponse (MVC).

  • ActionText fournit une zone de texte riche à vos formulaires (une zone de texte où vous pouvez mettre du texte stylé, des images, etc.)

  • ActionView est un ensemble d'outils (layouts, partiels, form builders, ..) pour compiler la réponse du contrôleur (MVC).

  • ActiveJob est une interface pour la planification de tâches asynchrones.

  • ActiveModel fournit des aides pour vous aider à structurer vos classes de modèles (définition d'attributs, mise en place de validations et de callbacks, ...).

  • ActiveRecord est un ORM, c'est-à-dire qu'il s'agit de la couche qui permet à vos contrôleurs de parler à votre/vos base(s) de données (MVC).

  • ActiveStorage s'occupe du téléchargement de fichiers pour vous.

  • ActiveSupport rend la programmation Ruby encore plus agréable en y ajoutant de nombreuses fonctionnalités intéressantes.

  • Railties est le noyau du framework Rails. Il fournit plusieurs hooks pour étendre Rails et/ou modifier le processus d'initialisation. Cela permet aux composants mentionnés ci-dessus et à toute gemme incluse dans votre application Rails d'étendre le framework Rails.

  • Les autres fichiers ne sont pas pertinents pour moi à ce stade, j'ai juste besoin d'avoir une idée de la façon dont le code source de Rails est organisé.

Ok, j'ai donc une vue d'ensemble de la structure du référentiel Rails. Et maintenant ?

Eh bien, mon objectif est de contribuer à Rails. La contribution la plus simple -mais toujours utile- que l'on puisse apporter à un projet open source est une contribution à la documentation. Commençons par cela.

Rails, je dois le cloner et le configurer pour avoir un moyen facile de le mettre à jour en amont :

$ cd
$ mv rails rails_upstream
$ git clone [email protected]com:<username>/rails.git rails_fork
$ cd rails_fork
$ git remote add upstream [email protected]com:rails/rails.git
$ git fetch upstream

Maintenant, quand j'ai besoin de mettre à jour ma fourche, je vais faire ce qui suit :

$ git checkout master
$ git pull upstream master
$ git push

Et quand on me demande de rebaser ma branche sur master, je fais ce qui suit :

$ git checkout master
$ git pull upstream master
$ git push
$ git checkout <my-branch>
$ git rebase master <my-branch>
$ git push -f


Contribution à la documentation

En lisant le code source d'ActiveStorage (activestorage/lib/active_storage/service.rb), j'ai remarqué un appel à ActiveSupport::Notifications.instrument. Je ne savais pas ce que c'était, alors j'ai fait des recherches :

L'API d'instrumentation fournie par Active Support permet aux développeurs de fournir des crochets auxquels d'autres développeurs peuvent s'accrocher. Il en existe plusieurs dans le cadre de Rails. Avec cette API, les développeurs peuvent choisir d'être notifiés lorsque certains événements se produisent dans leur application ou dans un autre morceau de code Ruby.

C'est cool. Il y a plusieurs hooks ajoutés par ActiveStorage, donc peut-être qu'ils ne sont pas tous mentionnés dans le guide Active Support Instrumentation.J'ai deviné juste, il manque trois hooks :

  • service_download_chunk.active_storage

  • service_update_metadata.active_storage

  • preview.active_storage

Je pense avoir trouvé ma première contribution à Rails :D

$ git checkout -b add-activestorage-instrumentation-hooks-to-guide
$ # apply wanted modifications to guides/source/active_support_instrumentation.md
$ git add guides/source/active_support_instrumentation.md
$ git commit
$ git push -u origin add-activestorage-instrumentation-hooks-to-guide

Important : puisque ce commit ne modifie que la documentation, il est important d'ajouter [ci skip] au message de commit afin que le CI ne soit pas surchargé inutilement.Maintenant que ma branche est poussée, je dois aller sur  https://github.com/rails/rails et ouvrir une nouvelle demande de tirage.Pull Request: https://github.com/rails/rails/pull/36010

commit 78260d5663702f153f6bae64073f9659de366946
Author: Younes SERRAJ <[email protected]>
Date:   Wed Apr 17 19:25:46 2019 +0200

    Mention more ActiveStorage hooks in Active Support Instrumentation guide [ci skip]

    Hooks added:
    - `service_download_chunk.active_storage`
    - `service_update_metadata.active_storage`
    - `preview.active_storage`

diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md
index e5ed283c45..4868b00bbe 100644
--- a/guides/source/active_support_instrumentation.md
+++ b/guides/source/active_support_instrumentation.md
@@ -545,6 +545,14 @@ Active Storage
 | `:key`       | Secure token        |
 | `:service`   | Name of the service |

+### service_download_chunk.active_storage
+
+| Key          | Value                           |
+| ------------ | ------------------------------- |
+| `:key`       | Secure token                    |
+| `:service`   | Name of the service             |
+| `:range`     | Byte range attempted to be read |
+
 ### service_download.active_storage

 | Key          | Value               |
@@ -582,6 +590,23 @@ Active Storage
 | `:service`   | Name of the service |
 | `:url`       | Generated URL       |

+### service_update_metadata.active_storage
+
+| Key             | Value                          |
+| --------------- | ------------------------------ |
+| `:key`          | Secure token                   |
+| `:service`      | Name of the service            |
+| `:content_type` | HTTP Content-Type field        |
+| `:disposition`  | HTTP Content-Disposition field |
+
+INFO. The only ActiveStorage service that provides this hook so far is GCS.
+
+### preview.active_storage
+
+| Key          | Value               |
+| ------------ | ------------------- |
+| `:key`       | Secure token        |
+
 Railties
 --------

Il reste maintenant une chose très difficile à faire : attendre. Attendre qu'un membre de l'équipe centrale examine la demande de retrait et la commente ou la fusionne. Attendre sans recharger la page Github toutes les 5 secondes. Il suffit de passer à autre chose et d'attendre une notification par e-mail : la demande a été fusionnée.

Contribuer à un composant Rails


Contribuer à un composant Rails

J'ai commencé avec ActiveStorage, je vais m'y tenir pour l'instant. Je n'ai pas de fonctionnalité à lui ajouter, alors de temps en temps, je vérifie les problèmes sur Github pour trouver l'inspiration. Le bogue que j'ai trouvé, lié à ActiveStorage et assez facile à corriger, est le suivant : https://github.com/rails/rails/issues/35953

Super ! J'ai maintenant ma prochaine contribution et cette fois, c'est le code. Le code va de pair avec les tests, je dois donc préparer mon environnement de développement pour exécuter la suite de tests de Rails. Effrayant, mais rien d'irréalisable :)

https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#setting-up-a-development-environment

Il y a principalement deux voies pour cela : on peut soit installer toutes les dépendances, soit tout exécuter dans une machine virtuelle. Personnellement, je vais faire les deux pour le bien de l'apprentissage, mais je ne mentionnerai que la méthode la plus simple dans ce blog, celle de la machine virtuelle.J'ai d'abord suivi ce guide: https://github.com/rails/rails-dev-box

Après avoir installé VirtualBox et Vagrant sur ma Debian 9.8, j'ai exécuté les commandes suivantes :

$ # in the host:
$ cd
$ git clone https://github.com/rails/rails-dev-box.git
$ cd rails-dev-box
$ cp -r ~/rails_fork ./rails
$ vagrant up
$ vagrant ssh
$ # once in the virtual machine:
$ cd /vagrant/rails
$ bundle

Remarquez que j'ai copié mon répertoire rails_fork à l'intérieur du répertoire rails-dev-box afin de pouvoir me connecter en ssh à la machine virtuelle et accéder au code source sur lequel je travaille (pour exécuter les tests).Ok, maintenant que j'ai mon environnement de développement prêt à fonctionner, je dois exécuter les tests avant toute chose. Je veux m'assurer que les tests s'exécutent avec succès avant de modifier le code source d'ActiveStorage (ainsi, en cas d'échec, je saurai que c'est à cause de mes modifications de code et non d'une erreur de configuration).

$ # in the virtual machine:
$ cd /vagrant/rails
$ bundle exec rake

Et encore : attendre. Juste... attendre... que... ça... fonctionne.


Please be green

Fait. Oui, c'est vert ! Note : comme conseillé dans la documentation, je vais éditer le code dans l'hôte et exécuter les tests dans la machine virtuelle. De cette façon, je n'installe aucun logiciel sur la machine virtuelle et j'évite les changements accidentels de versions de paquets et autres.


$ git checkout -b active-storage-bmp-variants-support

Je peux maintenant ajouter les modifications suivantes :

  • modifier activestorage/lib/active_storage/engine.rb pour corriger le problème (ici, je mets en liste blanche un type de mime pour qu'ActiveStorage sache qu'il peut créer des variantes BMP)

  • modifier activestorage/test/models/variant_test.rb pour tester qu'ActiveStorage réussit effectivement à créer une variante BMP

  • ajouter activestorage/test/fixtures/files/colors.bmp qui sera utilisé par le test ci-dessus

  • modifier activestorage/CHANGELOG.md pour informer les développeurs Rails des changements introduits par mon commit.

Il n'a pas été très difficile d'écrire ce patch. La seule partie qui m'a donné un peu de fil à retordre est celle des tests, car je suis habitué à RSpec, pas à minitest. J'ai lu les tests existants pour savoir comment écrire les miens, puis j'ai cherché sur Google comment tester un seul fichier. Dans mon cas, j'ai exécuté :

$ cd /vagrant/rails/activestorage
$ bundle exec ruby -Itest ./test/models/variant_test.rb`

Vert. J'aime ça. Je peux maintenant commiter et pousser vers Github :


$ cd /vagrant/rails
$ git add ./activestorage
$ git commit
$ git push -u origin active-storage-bmp-variants-support

Pull request: https://github.com/rails/rails/pull/36051

commit bcf370d689673031073ba2ac5588afe41cc315c9
Author: Younes SERRAJ <[email protected]>
Date:   Sun Apr 21 19:07:22 2019 +0200

    Allow ActiveStorage to generate variants of BMP images

diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md
index 54fc949172..d524ecf7d6 100644
--- a/activestorage/CHANGELOG.md
+++ b/activestorage/CHANGELOG.md
@@ -1,3 +1,7 @@
+*   Permit generating variants of BMP images.
+
+    *Younes Serraj*
+
 ## Rails 6.0.0.beta3 (March 11, 2019) ##

 *   No changes.
diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb
index fc75a8f816..cbb205627e 100644
--- a/activestorage/lib/active_storage/engine.rb
+++ b/activestorage/lib/active_storage/engine.rb
@@ -33,6 +33,7 @@ class Engine < Rails::Engine # :nodoc:
       image/jpeg
       image/pjpeg
       image/tiff
+      image/bmp
       image/vnd.adobe.photoshop
       image/vnd.microsoft.icon
     )
@@ -56,6 +57,7 @@ class Engine < Rails::Engine # :nodoc:
       image/jpg
       image/jpeg
       image/tiff
+      image/bmp
       image/vnd.adobe.photoshop
       image/vnd.microsoft.icon
       application/pdf
diff --git a/activestorage/test/fixtures/files/colors.bmp b/activestorage/test/fixtures/files/colors.bmp
new file mode 100644
index 0000000000..3cc1e8764d
Binary files /dev/null and b/activestorage/test/fixtures/files/colors.bmp differ
diff --git a/activestorage/test/models/variant_test.rb b/activestorage/test/models/variant_test.rb
index d98935eb9f..92e3384042 100644
--- a/activestorage/test/models/variant_test.rb
+++ b/activestorage/test/models/variant_test.rb
@@ -144,6 +144,17 @@ class ActiveStorage::VariantTest < ActiveSupport::TestCase
     assert_equal 33, image.height
   end

+  test "resized variation of BMP blob" do
+    blob = create_file_blob(filename: "colors.bmp")
+    variant = blob.variant(resize: "15x15").processed
+    assert_match(/colors\.bmp/, variant.service_url)
+
+    image = read_image(variant)
+    assert_equal "BMP", image.type
+    assert_equal 15, image.width
+    assert_equal 8, image.height
+  end
+
   test "optimized variation of GIF blob" do
     blob = create_file_blob(filename: "image.gif", content_type: "image/gif")

Remarque : il arrive que vous ayez plusieurs commits dans votre demande de modification. On peut vous demander de les écraser pour aider à garder l'historique aussi propre que possible. Si on vous le demande, git rebase -i et git commit --amend sont vos amis. J'ai donc ouvert une pull request et... j'ai attendu. Oui, il y a beaucoup d'attente dans les contributions open source. Gardez à l'esprit que les contributeurs principaux ont leur travail rémunéré à prendre en charge, leur vie personnelle, et un tas de problèmes à lire, et un tas de pull requests à examiner, et leurs propres pull requests à travailler, et des listes de diffusion à tenir à jour, etc. Oui, cela prend du temps. Oui, nous les aimons pour le travail génial qu'ils font. Oui, lorsque nous commençons à contribuer, il est frustrant d'attendre et nous sommes presque bannis de Github pour avoir rafraîchi trop souvent notre page de demande de publication, mais ce n'est pas grave. Nous contribuons à Rails et c'est un sentiment formidable parce que nous pouvons aider d'autres développeurs, nous apprenons plus sur Rails et nous apprécions encore plus le travail que tous ces contributeurs ont fait avant nous.


Note de clôture

Tout d'abord, un grand merci à @eileencodes ❤ pour sa conférence à la RailsConf 2015 Breaking Down the Barrier : Démystifier la contribution à Rails :  https://www.youtube.com/watch?v=7zoD6NZy6vY Guys, si vous jouez avec Rails depuis deux ou trois ans, vous pouvez probablement contribuer. Mon conseil est le suivant : lisez les problèmes sur Github, testez-les pour confirmer qu'ils sont reproductibles ou demandez plus de détails si nécessaire, lisez les pull requests, lorsque vous trouvez quelque chose de nouveau pour vous, ne vous contentez pas de lire les tutoriels et la documentation mais allez également lire le code source. Peu importe si vous ne comprenez pas tout ce qui se passe, au moins vous accumulez des connaissances et construisez lentement une compréhension intuitive du fonctionnement de Rails. Avant que vous ne le sachiez, vous serez tellement familier avec le système que contribuer à Ruby on Rails sera un jeu d'enfant.

Peace and love mes amis.

Partager
Younes Serraj
Younes Serraj20 mai 2019

Blog de Capsens

Capsens est une agence spécialisée dans le développement de solutions fintech. Nous aimons les startups, la méthodologie scrum, le Ruby et le React.