Nota: Este é um guia de instalação para ambiente de desenvolvimento não suportado. Os guias oficialmente suportados para macOS estão aqui (nativo) e aqui (Docker). Proceda por sua conta e risco.
O objetivo deste guia é containerizar o PostgreSQL e o Redis, mas manter o Ruby fora dos containers.
Eu tentei a abordagem Discourse para Desenvolvimento usando Docker, mas foi simplesmente muito lento na minha máquina.
Em seguida, analisei o guia Discourse para Desenvolvimento no macOS. Mas a primeira coisa que o script faz é instalar o brew. O brew pode ser ótimo, mas uso o MacPorts há muito tempo e gostaria de continuar resistindo com sucesso à instalação do brew. Além disso, esse script também realizava instalações globais de coisas como PostgreSQL e Redis, que eu prefiro poder manter em uma base por projeto.
Então, aqui está o que funcionou para mim usando uma combinação de asdf e docker-compose. O resultado é um meio-termo entre as duas abordagens descritas acima. O PostgreSQL e o Redis são executados em um container usando docker-compose, para que possam ser fixados nas versões oficiais e nas instalações que o Discourse usa em produção. O Rails roda diretamente no sistema. Essa combinação é consideravelmente mais ágil para mim. Seu resultado pode variar (YMMV).
Se você quiser acompanhar, precisará ter o asdf e o Docker instalados na sua máquina. (Nossa, o asdf é realmente fantástico… você definitivamente deveria baixá-lo se tiver qualquer interesse em manter facilmente muitos ambientes de desenvolvimento diferentes. Ele substitui o renv, o nvm… aparentemente quase tudo, exceto o jenv.)
Se você olhar o que o script de instalação para macOS estava fazendo, pode separar o que está sendo instalado em três categorias:
- ambientes e ferramentas de linha de comando como
rubyeyarn. Vamos instalá-los e fixar suas versões no diretório do nosso projeto usandoasdf. - serviços—especificamente PostgreSQL e Redis. Vamos instalá-los usando Docker Compose, novamente para que possamos fixar suas versões no que precisamos para este projeto e também ter um ambiente de desenvolvimento que possamos iniciar e parar facilmente.
- outros—principalmente bibliotecas para manipulação de imagem como ImageMagick e otimização. Estas podem ser instaladas usando
brew,portou diretamente do código-fonte.
Também precisaremos reconfigurar levemente nosso ambiente de desenvolvimento para conectar ao servidor PostgreSQL executado pelo docker-compose.
Código Fonte do Discourse
Todas as etapas abaixo devem ser feitas dentro do seu diretório de origem do Discourse:
git clone https://github.com/discourse/discourse.git && cd discourse
Isso é importante, pois é aqui que o asdf salvará seu arquivo de configuração .tool-versions e onde criaremos nosso arquivo docker-compose.yml para o Docker.
asdf
Há três coisas que precisamos instalar usando asdf: ruby, yarn e postgres. Felizmente, o asdf facilita tanto a instalação de todos de uma vez quanto a fixação das versões no diretório do nosso projeto. Primeiro, crie o arquivo .tool-versions com este conteúdo:
yarn 1.22.2
ruby 2.6.5
postgres 10.12
Em seguida, basta executar asdf install.
Agora você deve ser capaz de realizar as etapas de instalação da biblioteca Ruby incluídas no script e mais tarde nas instruções:
gem update --system
gem install bundler
gem install rails
gem install mailcatcher
gem install pg -- --with-pg-config=$HOME/.asdf/installs/postgres/10.12/bin/pg_config
bundle install
Você pode precisar ajustar o caminho para pg_config dependendo de onde instalou o asdf.
docker-compose.yml
Em seguida, precisamos criar nosso arquivo docker-compose.yml configurado para iniciar o Redis e o PostgreSQL. O meu se parece com isto:
version: "3"
networks:
discourse:
driver: bridge
services:
data:
image: "geoffreychallen/discourse_data:latest"
command: /sbin/boot
ports:
- "5432:5432"
- "6379:6379"
volumes:
- "data_shared:/shared/"
- "data_logs:/var/log/"
networks:
- discourse
volumes:
data_shared:
driver: local
data_logs:
driver: local
Graças a @pfaffman pela sugestão de usar um container de dados padrão do Discourse. geoffreychallen/discourse_data:latest é construído a partir do Discourse Docker. Usei o arquivo de exemplo data.yml com duas alterações. Primeiro, defini a senha do usuário discourse como “discourse”. Segundo, tornei esse usuário um superusuário para que ele possa criar bancos de dados de teste. Aqui está a parte hooks do meu arquivo data.yml:
hooks:
after_postgres:
- exec:
stdin: |
alter user discourse with password 'discourse';
cmd: sudo -u postgres psql discourse
raise_on_fail: false
- exec:
stdin: |
alter user "discourse" with superuser;
cmd: sudo -u postgres psql discourse
raise_on_fail: false
Novamente, isso é apenas no caso de você querer construir seu próprio container de dados do Discourse e não usar o meu. Por favor, não use este container em produção—ele é completamente inseguro!
Nesta configuração, expomos as portas padrão do PostgreSQL e do Redis e executamos o comando boot que o container precisa para iniciar.
Depois que seu docker-compose.yml estiver no lugar, teste-o:
docker-compose up
Supondo que tudo esteja configurado corretamente, você deverá ver o Redis e o PostgreSQL iniciando. Pressione Control-C para cancelar ou execute docker-compose down se, por algum motivo, algo não for desligado corretamente.
Bibliotecas Diversas
A maioria das bibliotecas de otimização de imagem pode ser instalada usando port ou brew. Veja como fazer isso com port:
sudo port install imagemagick pngquant optipng jhead jpegoptim gifsicle
O svgo pode ser instalado assim que você tiver o npm. Não vou cobrir isso, pois é bastante direto.
A propósito, pelo que posso ver (FWIW AFAICT), nenhuma dessas ferramentas é obrigatória. Vejo avisos durante várias etapas posteriores sobre elas estarem faltando, mas nada parece explodir.
config/database.yml e spec/fixtures/multisite/two_dbs.yml
Finalmente, precisamos reconfigurar levemente nosso ambiente de desenvolvimento para conectar corretamente ao PostgreSQL. Por padrão, ele tenta usar um socket Unix, que não é exportado pelo nosso container.
Para corrigir isso, você precisa modificar o config/database.yml. Essencialmente, em todos os lugares onde você vê:
adapter: postgresql
Substitua por:
adapter: postgresql
host: localhost
username: discourse
password: discourse
A adição da host faz com que o Discourse não use um socket, e o username e password fazem com que o Discourse se conecte usando o usuário padrão do banco de dados do Discourse e a senha que definimos acima.
Eu tive que fazer essa alteração três vezes no config/database.yml: uma vez em development, depois em test e finalmente em profile. Para fazer a suíte de testes funcionar, também precisei fazer uma alteração semelhante em spec/fixtures/multisite/two_dbs.yml.
Vamos Lá…
Tudo bem, vamos lá! Em uma janela, inicie seu ambiente de desenvolvimento usando docker-compose:
docker-compose up
Em uma segunda janela, vamos executar as etapas de configuração do banco de dados:
bundle exec rake db:create
Supondo que funcionou, agora você pode continuar no ponto apropriado no guia para macOS baseado em brew.
Quando terminar de trabalhar, pare o docker-compose e você pode guardar seu ambiente de desenvolvimento até a próxima vez.
Se você quiser excluir permanentemente o banco de dados e o conteúdo do Redis, basta executar um docker-compose down -v para apagar os volumes persistentes junto com os próprios containers. Mas sem a flag -v, o docker-compose down manterá seu banco de dados persistente entre sessões de desenvolvimento.
Os Testes Passam?
Minha configuração falhou em dois casos de teste:
Failures:
1) UploadCreator#create_for pngquant should apply pngquant to optimized images
Failure/Error: expect(upload.filesize).to eq(9558)
expected: 9558
got: 9550
(compared using ==)
# ./spec/lib/upload_creator_spec.rb:115:in `block (4 levels) in <main>'
2) tasks/uploads uploads:secure_upload_analyse_and_update when store is external when secure media is enabled rebakes the posts attached
Failure/Error: expect(post1.reload.baked_at).not_to eq(post1_baked)
expected: value != 2020-03-08 03:20:01.777117000 +0000
got: 2020-03-08 03:20:01.777117000 +0000
(compared using ==)
Diff:
<The diff is empty, are your objects producing identical `#inspect` output?>
# ./spec/tasks/uploads_spec.rb:90:in `block (5 levels) in <main>'
Finished in 19 minutes 21 seconds (files took 13.67 seconds to load)
4297 examples, 2 failures, 11 pending
Para mim, o primeiro parece que o pngquant está funcionando um pouco melhor do que o esperado. Não sei por que isso representa uma falha. O segundo eu também não entendo. Mas isso parece sensato para mim.
Bom hacking!