Escrevendo seu primeiro patch para Django¶
Introdução¶
Interessado em retribuir um pouco para a comunidade? Talvez você tenha encontrado uma falha no Django que você gostaria de ver corrigida, ou talvez exista uma pequena funcionalidade que poderia ser adicionada.
A melhor maneira de ver os seus próprios problemas serem resolvidos é contribuindo com o Django. Isto pode parecer assustador no começo, mas na verdade é bem simples. Nós lhe guiaremos por todo o processo para que você possa aprender através de exemplos.
Para quem se destina este tutorial?¶
Ver também
Se você está procurando por uma referência sobre como enviar pacotes, veja a Enviando patches documentação.
Para este tutorial, esperamos que você tenha ao menos um conhecimento básico de como o Django funciona. Isso significa que você precisa estar confortável com o tutoriai “Escrevendo sua primeira aplicação Django</intro/tutorial01>”. Além disso, você deve ter um bom conhecimento em Python. Mas se não tiver, “Dive Into Python” é um livro online fantástico (e gratuito) para iniciantes em Python.
Aqueles que não estão familiarizados com sistemas de controle de versão e Trac irão encontrar neste tutorial, e seus links inclusos, informações suficientes para iniciar. Entretanto, se você esta planejando contribuir com o Django regularmente, provavelmente você vai querer ler mais a respeito das destas diferentes ferramentas.
Para a maior parte, porém, este tutorial tenta explicar o máximo possível, tal que possa ser usado por um público mais amplo.
Onde obter ajuda:
Se você estiver enfrentando problemas durante este tutorial, por favor envie um mensagem par django-developers ou acesse `#django-dev on irc.freenode.net`__ para conversar com outros usuários de Django que podem ser capazes de ajudá-lo.
O que este tutorial cobre?¶
Nós iremos guir você para que contribua com um “patch” para o Django pela primeira vez. Ao final deste tutorial, você deve possuir o conhecimento básico tanto para as ferramentas quanto para os processos envolvidos. Nós iremos cobrir especialmente os seguintes tópicos:
Instalando Git.
Como baixar uma cópia de desenvolvimento do Django.
Executando suite de testes do Django.
Escrevendo um teste para o seu patch.
Escrevendo o código para o seu patch.
Testando o seu patch.
- Submitting a pull request.
Onde encontrar mais informações.
Uma vez que você terminar este tutorial, você pode olhar o restante da Documentação do Django sobre contribuição Ela contém muitas informações úteis e deve ser lida por quem deseja se tornar um contribuidor do Django. Caso tenha perguntas, a documentação provavelmente contem as respostas.
Python 3 é requerido!
Este tutorial acredita que você já está usando o Python 3. Obtenha a última versão do Python na sua página de download <https://www.python.org/download/>` ou com seu sistema de controle de pacotes.
Para usuários do Windows
Quando instalar o Python no Windows, tenha certeza que você marcou a opção “Add python.exe to Path”, então ele sempre vai estar disponível na linha de comando.
Código de Conduta¶
Como um contribuidor, você pode nos ajudar a manter a comunidade Django aberta e solidária. Por favor, leia e siga nosso ‘Código de conduta’ <https://www.djangoproject.com/conduct/>`_.
Instalando Git¶
Para este tutorial será necessário ter o Git instalado para fazer o download da versão corrente de desenvolvimento do Django e para gerar arquivos de “patch” para as mudanças que você faça.
Para verificar se o Git está instalado ou não no seu sistema, digite git
na linha de comando. Se o resultado for uma mensagem dizendo que o comando não pode ser encontrado, você terá que fazer o download e instalar o Git. Dê uma olhada em `Git’s download page`__.
Para usuários do Windows
Ao instalar o Git no Windows, é recomendável que você escolha a opção “Git Bash” para que o Git seja executado em seu próprio shell. Este tutorial assume que foi assim que você instalou.
Caso não esteja familiar com o Git, você sempre pode achar mais sobre seus comandos (uma vez que estiver instalado) digitando “git help” na linha de comando.
Obtendo uma cópia da versão de desenvolvimento do Django¶
O primeiro passo para contribuir com o Django é ter uma cópia dos arquivos do código fonte. Primeiro, faça um fork do projeto Django no GitHub. Então, a aprtir da linha de comando, use o comando cd
para ir até o diretório onde você quer que fique sua cópia do projeto Django.
Baixe o código fonte do repositório do Django usando o seguinte comando:
$ git clone git@github.com:YourGitHubName/django.git
Agora que você tem uma cópia local do Django, você pode instalá-lo da mesma forma que você instalaria qualquer pacote usando pip
. A maneira mais conveniente de fazer isso é usando um ambiente virtual (ou virtualenv) que é um recurso embutido no Python que permite que você mantenha um diretório separado para os pacotes instalados de cada um dos seus projetos para que uns não interfiram com os outros.
É uma boa idéia mater todos os seus virtualenvs em um lugar, por exemplo em .virtualenvs/
no seu diretório pessoal. Crie-o se ele ainda não existe:
$ mkdir ~/.virtualenvs
Agora crie uma nova virtualenv executando:
$ python3 -m venv ~/.virtualenvs/djangodev
O caminho é o local onde o novo ambiente será salvo em seu computador.
Para usuários do Windows
Usando o módulo embutido venv
não irá funcionar se você também estiver usando o Git Bash shell no Windows, já que os scripts de ativação só são criados para o shell do sistema (.bat
)e para o PowerShell (.ps1
). Em vez disso use o pacote virtualenv
:
$ pip install virtualenv
$ virtualenv ~/.virtualenvs/djangodev
Para usuários Ubuntu.
Em algumas versões do Ubuntu pode ser que o comando acima falhe. Ao invés disso use o pacote virtualenv
, antes certifique-se que você tem o pip3
:
$ sudo apt-get install python3-pip
$ # Prefix the next command with sudo if it gives a permission denied error
$ pip3 install virtualenv
$ virtualenv --python=`which python3` ~/.virtualenvs/djangodev
O passo final na criação da sua virtualenv é ativá-la:
$ source ~/.virtualenvs/djangodev/bin/activate
Se o comando source
não estiver disponível, você pode tentar usar um ponto em vez disso:
$ . ~/.virtualenvs/djangodev/bin/activate
Para usuários do Windows
Para ativar seu virtualenv no Windows, rode:
$ source ~/virtualenvs/djangodev/Scripts/activate
Você tem que ativar o virtualenv sempre que abrir uma nova janela de terminal. virtualenvwrapper__ é uma ferramenta útil para deixar isso mais conveniente.
Tudo o que você instalar através do pip
a partir de agora será instalado no seu novo virtualenv, isolado de outros ambientes e pacotes de todo o sistema. Além disso, o nome do virtualenv atualmente ativado é exibido na linha de comando para lhe ajudar a saber qual deles você está usando. Vá em frente e instale a cópia previamente clonada do Django:
$ pip install -e /path/to/your/local/clone/django/
A versão instalada do Django agora está apontando para a sua cópia local. Você verá as mudanças que fizer de forma imediata, o que é uma grande ajuda quando se está escrevendo o primeiro patch
Revertendo para uma revisão anterior do Django¶
Para este tutorial usaremos o ticket #24788 como caso de estudo, então iremos voltar no histórico de versão do Django no git para antes que o “patch” deste ticket tenha sido aplicado. Isso nos possibilitará ir através de todos os passos envolvidos em escrever um patch do início, incluindo rodar a suíte de testes do Django.
Tenha em mente que enquanto estamos usando uma revisão antiga da árvore do Django, para o propósito do tutorial abaixo, você deve sempre usar a versão corrente da árvore de desenvolvimento quando for trabalhar no seu próprio patch para um ticket!
Nota
O patch para este ticket foi escrito por Paweł Marczewskie foi aplicado ao Django como `commit 4df7e8483b2679fc1cba3410f08960bac6f51115`__. Consequentemente, usaremos a revisão anterior a esta, `commit 4ccfc4439a7add24f8db4ef3960d02ef8ae09887`__.
Navegue até o diretório raiz do Django (o diretório que contém ‘django’, ‘docs, ‘testes’, ‘autores’ e etc). Pode-se verificar então a revisão mais antiga do Django que utilizaremos no tutorial abaixo:
$ git checkout 4ccfc4439a7add24f8db4ef3960d02ef8ae09887
Executando a suíte de testes do Django pela primeira vez¶
Quando contribuir para o Django é muito imoprtante que suas mudanças no código não introduzam bugs em outras área do Django. Uma maneira de verificar se o Django ainda funciona depois de adicionar suas alterações é executando a suite de testes do Django. Se ainda passa em todos os testes, então você pode ter uma certeza razoável de que suas alterações não quebraram completamente o Django. Se você nunca rodou os testes antes, é uma boa idéia executá-los uma vez só para estar familiarizado com o que a sua saída deveria parecer.
Antes de rodar a suíte de testes, instale suas dependências primeiramente entrando no diretório tests/
do Django e então executando-a.
$ pip install -r requirements/py3.txt
Se encontrar algum erro durante a instalação, talvez esteja faltando no seu sistema alguma dependência de um ou mais pacotes Python. Consulte a documentação de pacotes faltantes ou procure na Web a mensagem de erro que encontrou.
Agora estamos prontos para executar a suíte de testes. Se você estiver usando o GNU/Linux, Mac OS X ou alguma outra distribuiçao do UNIX, execute:
$ ./runtests.py
Agora sente e relaxe. A suíte de testes do Django tem mais de 9.600 testes diferentes, por isso pode levar de 5 a 15 minutos para ser executado, dependendo da velocidade do seu computador.
Enquanto a suíte de testes do Django estiver sendo executada, você verá um fluxo de caracteres representando o status de cada teste conforme vão sendo executados. “E” indica que foi lançado um erro durante o teste, “F” indica que as asserções do teste falharam. Ambos são considerados como se o teste tivesse falhado. Enquanto que “x” e “s” indicam falhas esperadas e testes ignorados, respectivamente. Pontos indicam que o teste passou.
Normalmente testes são pulados quando faltam bibliotecas externas necessárias para executar o teste; veja Rodando todos os testes para uma lista de dependências e para se certificar de instalar qualquer dependência relacionada com suas mudanças (nós não necessitamos de nenhuma para este tutorial). Alguns testes são específicos para um backend de uma data base de dados e serão ignorados se não testado com aquele backend. SQLite é a base de dados backend padrão nas configurações. Para executar os testes usando diferentes backends, veja Usando outro módulo settings.
Uma vez que os testes estejam completos, você deve ser informado através de uma mensagem se o seu teste passou ou falhou. Uma vez que você não fez nenhuma alteração no código do Django, todo a suíte de teste deve passar. Se você recebeu falhas ou erros verifique se você seguiu todos os passos anteriores corretamente. Para mais informações veja o Rodando os testes unitários. Se estiver usando Python 3.5+, haverá algum alerta sobre falhas relacionadas a alertas de pontos obsoletos que você pode ignorar. Estas falhas já foram corrigidas no Django.
Perceba que o trunk mais recente do Django pode nem sempre estar estável. Quando estiver desenvolvendo utilizando o trunk você pode checar `builds de integração contínua do Django`__ para determinar se as falhas são específicas à sua máquina ou se elas estão presentes também nas builds oficiais do Django. Se você clicar para visualizar uma build em particular, você pode visualizar a “Matriz de Configuração”, que mostra falhas discriminadas por versão de Python e backend de banco de dados.
Nota
Para este tutorial e para o ticket em que iremos trabalhar, testar usando o SQLite é suficiente. Entretanto, é possível (e às vezes necessário) usar um banco de dados diferente para testes.
Creating a branch for your patch¶
Antes de fazer qualquer alteração, crie uma nova branch para o ticket:
$ git checkout -b ticket_24788
You can choose any name that you want for the branch, “ticket_24788” is an example. All changes made in this branch will be specific to the ticket and won’t affect the main copy of the code that we cloned earlier.
Escrevendo alguns testes para o seu ticket¶
Na maioria dos casos, para um patch ser aceito no Django, ele tem que incluir testes. Para patches de correção de erros, significa escrever um teste de regressão para garantir que o erro nunca mais seja reintroduzido no Django mais tarde. Um teste de regressão deve ser escrito de tal forma que irá falhar enquanto o erro ainda existir e passar uma vez que o erro foi corrigido. Para patches contendo novos recursos, você precisa incluir testes que garantem que os novos recursos estão funcionando corretamente. Eles também devem falhar quando o novo recurso não estiver presente, e em seguida passar, uma vez que foi implementado.
Uma boa maneira de fazer isso é escrever seus novos testes primeiro, antes de realizar quaisquer modificações no código. Este estilo de desenvolvimento é chamado `desenvolvimento orientado a testes`__ e pode ser aplicado tanto a projetos inteiros quanto a patches isolados. Após escrever seus testes você os roda para garantir que eles realmente falham (uma vez que você ainda não consertou o bug ou adicionou a nova funcionalidade). Se seus novos testes não falharem, você terá de corrigí-los para que falhem. Afinal, um teste de regressão que passa independentemente de um bug estar presente não é muito útil na prevenção de que um bug ocorra novamente no futuro.
Agora para nosso exemplo mão-na-massa.
Escrevendo alguns testes para o ticket #24788¶
Ticket #24788 propõe uma pequena adição: a habilidade de especificar o atributo de classe prefix
nas classes de Form, então que:
[…] forms which ship with apps could effectively namespace themselves such
that N overlapping form fields could be POSTed at once and resolved to the
correct form.
Para resolver este ticket, iremos adicionar um atributo prefix
a classe BaseForm
. Quando criar instancias desta classe, passando um prefixo para o método __init__()
ainda será setado o prefixo na instancia criada. Mas não passando um prefix (ou passando None
) será usado o prefixo da classe. Antes de fazermos estas mudanças, nós iremos escrever alguns testes para verificar que nossas modificações funcionam corretamente e continuem funcionando corretamente no futuro.
Navegue para o diretório tests/forms_tests/tests/
do Django e abra o arquivo test_forms.py
. Adicione o seguinte código na linha 1674 logo antes da função test_forms_with_null_boolean
function:
def test_class_prefix(self):
# Prefix can be also specified at the class level.
class Person(Form):
first_name = CharField()
prefix = 'foo'
p = Person()
self.assertEqual(p.prefix, 'foo')
p = Person(prefix='bar')
self.assertEqual(p.prefix, 'bar')
Este novo teste verifica que a configuração de um prefixo nível de classe funciona como esperado, e que passando um parâmetro `` prefix`` ao criar uma instância ainda funciona também.
Mas esse lance de testar parece difícil...
Caso você nunca tenha lidado com testes anteriormente, num primeiro momento eles podem parecer um pouco difíceis de escrever . Felizmente, testes são um assunto muito extenso em programação de computadores, então existe muita informção por aí:
Uma boa introdução em testes para Django pode ser encontrada na documentação Writing and running tests.
Megulhando no Python (um livro gratuito online para desenvolvedores iniciantes de Python) inclui uma ótima `introdução ao Teste de Unidade`__.
Após essa leitura, se desejar algo a mais para se aprofundar, sempre há a documentação do Python sobre
unittest
.
Executando o seu novo teste¶
Lembre que na verdade ainda não fizemos nenhuma modificação no BaseForm
, então os testes irão falhar. Vamos rodar todos os testes no diretório forms_tests
para ter ceteza que é isso que acontecerá. Na linha de comando, acesse o diretório tests/
do Django e execute:
$ ./runtests.py forms_tests
Se os testes foram executados corretamente, você deverá ver uma falha que corresponde ao método de teste que adicionamos. Se todos estes testes passaram, então você deverá ter certeza que você adicionou o novo teste mostrado acima no diretório e classe apropriados.
Escrevendo o código para o seu ticket¶
Em seguida nós iremos adicionar a funcionalidade descrita no ticket #24788 ao Django.
Escrevendo o código para o ticket #24788¶
Vá até o diretório django/django/forms/` e abra o arquivo ``forms.py
. Ache a classe BaseForm
a linha 72 e adicione o atributo de classe prefix
logo após o field_order
attribute:
class BaseForm(object):
# This is the main implementation of all the Form logic. Note that this
# class is different than Form. See the comments by the Form class for
# more information. Any improvements to the form API should be made to
# *this* class, not to the Form class.
field_order = None
prefix = None
Verificando se o seu teste passa agora¶
Uma vez que tenha modificado o Django, precisamos ter ceteza que os testes que escreveu anteriormente passem, então você poder ver se o código que escrevemos anteriormente está funcionando corretamente. Para rodar os testes no diretório forms_tests
, acesse (cd
) o diretório tests/
do Django e execute:
$ ./runtests.py forms_tests
Opa, ainda bem que escrevemos esses testes! Você ainda deve ver uma falha com a seguinte exceção
AssertionError: None != 'foo'
Esquecemos de adicionar comando de condição no método __init__
. Vá em frente e altere self.prefix = prefix
que está agora na linha 87 do django/forms/forms.py
, adicionando o comando de condição.
if prefix is not None:
self.prefix = prefix
Re-execute os testes e tudo deve passar. Caso contrário, tenha certeza que modificou corretamente a classe BaseForm
como mostrado acima e copiado o novo teste corretamente.
Executando a suíte de testes do Django pela segunda vez¶
Depois de verificar que seu patch e seu teste estão funcionando corretamente, é uma boa ídeia executar toda a suite de testes do Django apenas para verificar se sua mudança não introduziu algum erro em outras áreas do Django. Ao passar com sucesso em toda a suite de testes, não garante que seu código esteja livre de erros, ele ajuda identificar muitos erros e regressões que poderiam passar despercebidos.
Para executar toda a suíte de testes do Django, `` cd`` no diretório `` testes / `` do Django e execute:
$ ./runtests.py
Contanto que você não veja qualquer falha, você está pronto para seguir.
Escrevendo Documentação¶
Isos é uma funcionalidade nova, então deve ser documentada. Adicione a seguinte seção na linha 1068 (no final do arquivo) do django/docs/ref/forms/api.txt
:
The prefix can also be specified on the form class::
>>> class PersonForm(forms.Form):
... ...
... prefix = 'person'
.. versionadded:: 1.9
The ability to specify ``prefix`` on the form class was added.
Já que essa nova funcionalidade estará em uma próxima revisão esta é também adicionada nas notas de release do Django 1.9, na linha 164 sob a seção “Forms” no arquivo docs/releases/1.9.txt
:
* A form prefix can be specified inside a form class, not only when
instantiating a form. See :ref:`form-prefix` for details.
Para mais informações sobre escrita de documentação, incluindo uma explicação sobre o que versionadded
significa, verifique Escrevendo a documentação. Essa página também inclui uma explicação sobre como construir uma cópia local da documentação, de maneira que você possa pré-visualizar o HTML que será gerado.
Visualizando suas alterações¶
Now it’s time to go through all the changes made in our patch. To display the differences between your current copy of Django (with your changes) and the revision that you initially checked out earlier in the tutorial:
$ git diff
Use as teclas direcionais para mover para cima e para baixo.
diff --git a/django/forms/forms.py b/django/forms/forms.py
index 509709f..d1370de 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -75,6 +75,7 @@ class BaseForm(object):
# information. Any improvements to the form API should be made to *this*
# class, not to the Form class.
field_order = None
+ prefix = None
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
@@ -83,7 +84,8 @@ class BaseForm(object):
self.data = data or {}
self.files = files or {}
self.auto_id = auto_id
- self.prefix = prefix
+ if prefix is not None:
+ self.prefix = prefix
self.initial = initial or {}
self.error_class = error_class
# Translators: This is the default suffix added to form field labels
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 3bc39cd..008170d 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -1065,3 +1065,13 @@ You can put several Django forms inside one ``<form>`` tag. To give each
>>> print(father.as_ul())
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
+
+The prefix can also be specified on the form class::
+
+ >>> class PersonForm(forms.Form):
+ ... ...
+ ... prefix = 'person'
+
+.. versionadded:: 1.9
+
+ The ability to specify ``prefix`` on the form class was added.
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 5b58f79..f9bb9de 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -161,6 +161,9 @@ Forms
:attr:`~django.forms.Form.field_order` attribute, the ``field_order``
constructor argument , or the :meth:`~django.forms.Form.order_fields` method.
+* A form prefix can be specified inside a form class, not only when
+ instantiating a form. See :ref:`form-prefix` for details.
+
Generic Views
^^^^^^^^^^^^^
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index 690f205..e07fae2 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -1671,6 +1671,18 @@ class FormsTestCase(SimpleTestCase):
self.assertEqual(p.cleaned_data['last_name'], 'Lennon')
self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9))
+ def test_class_prefix(self):
+ # Prefix can be also specified at the class level.
+ class Person(Form):
+ first_name = CharField()
+ prefix = 'foo'
+
+ p = Person()
+ self.assertEqual(p.prefix, 'foo')
+
+ p = Person(prefix='bar')
+ self.assertEqual(p.prefix, 'bar')
+
def test_forms_with_null_boolean(self):
# NullBooleanField is a bit of a special case because its presentation (widget)
# is different than its data. This is handled transparently, though.
When you’re done previewing the patch, hit the q
key to return to the
command line. If the patch’s content looked okay, it’s time to commit the
changes.
Cometendo as alterações no patch¶
Para cometer as alterações:
$ git commit -a
This opens up a text editor to type the commit message. Follow the commit message guidelines and write a message like:
Fixed #24788 -- Allowed Forms to specify a prefix at the class level.
Pushing the commit and making a pull request¶
After committing the patch, send it to your fork on GitHub (substitute “ticket_24788” with the name of your branch if it’s different):
$ git push origin ticket_24788
You can create a pull request by visiting the Django GitHub page. You’ll see your branch under “Your recently pushed branches”. Click “Compare & pull request” next to it.
Please don’t do it for this tutorial, but on the next page that displays a preview of the patch, you would click “Create pull request”.
Próximos passos¶
Congratulations, you’ve learned how to make a pull request to Django! Details of more advanced techniques you may need are in Trabalhando com Git e GitHub.
Agora você pode contribuir para ajudar a melhorar a base de código do Django.
Mais informações para novos contribuidores¶
Antes que você mergulhe na escrita de patches para o Django há mais algumas informações sobre contribuição que você provavelmente deveria dar uma olhada:
Você deve certificar-se de ler a documentação do Django em reinvidicando tickets e enviando patches. Ela abrange etiqueta Trac, como reivindicar bilhetes para si mesmo, estilo de codificação prevista para patches, e muitos outros detalhes importantes.
Os contribuidores de primeira viagem devem ler o documentação sobre contribuidores de primeira viagem. Ele tem muitos bons conselhos para aqueles que são novos para ajudar com Django.
Depois disso, se você ainda estiver ansioso para obter mais informações sobre como contribuir, você sempre pode navegar pelo resto da documentação do Django em contribuição. Ele contém um monte de informações úteis e deve ser sua primeira fonte para responder quaisquer perguntas que você possa ter.
Encontrando o seu primeiro ticket¶
Uma vez que tenha dado uma olhada nessa documentação, você estará pronto para ir procurar um ticket para escrever um “patch”. Preste especial atenção aos tickets marcados com o critério “easy pickings”. Estes tickets são em geral de natureza simples e bons para novos contribuidores. Uma vez que estiver familiarizado com contribuir para o Django, você pode ir adiante escrevendo “patches” para tickets mais difíceis e complicados.
Se você já quer começar agora (e ninguém iria culpá-lo!), tente dar uma olhada na lista de `tickets fáceis que precisam de patches`__ e os `tickets fáceis que têm patches que precisam de melhorias`__. Se você estiver familiarizado com a escrita de testes, você também pode olhar para a lista de `tickets simples que precisam de testes`__. Apenas lembre-se de seguir as orientações sobre a reivindicação de bilhetes que foram mencionados no link para a documentação do Django em reivindicar tickets e submeter patches.
O que vem depois de criar um pull request?¶
After a ticket has a patch, it needs to be reviewed by a second set of eyes. After submitting a pull request, update the ticket metadata by setting the flags on the ticket to say “has patch”, “doesn’t need tests”, etc, so others can find it for review. Contributing doesn’t necessarily always mean writing a patch from scratch. Reviewing existing patches is also a very helpful contribution. See Triangulando tickets for details.