A interação diária com o Bazel acontece principalmente por meio de alguns comandos:
build
, test
e run
. Às vezes, porém, estes podem parecer limitados: você pode
querem enviar pacotes para um repositório, publicar documentação para usuários finais ou
implantar um aplicativo com o Kubernetes. Mas o Bazel não tem um publish
ou
Comando deploy
: onde essas ações se encaixam?
O comando bazel run
O foco do Bazel em hermeticidade, reprodutibilidade e incrementabilidade representa a
Os comandos build
e test
não são úteis para as tarefas acima. Essas ações
podem ser executados em sandbox, com acesso limitado à rede, e não têm garantia de serem
executada novamente a cada bazel build
.
Em vez disso, confie na bazel run
, o elemento mais importante para as tarefas que você quer ter.
efeitos colaterais. Os usuários do Bazel estão acostumados com regras que criam executáveis e
os autores de regras podem seguir um conjunto comum de padrões
"verbos personalizados".
Em ação: rules_k8s
Por exemplo, considere rules_k8s
,
as regras do Kubernetes para o Bazel. Suponha que você tenha a seguinte meta:
# BUILD file in //application/k8s
k8s_object(
name = "staging",
kind = "deployment",
cluster = "testing",
template = "deployment.yaml",
)
A regra k8s_object
cria uma
arquivo YAML padrão do Kubernetes quando bazel build
é usado no staging
alvo. No entanto, os destinos adicionais também são criados pelo k8s_object
.
com nomes como staging.apply
e :staging.delete
. Esses constroem
para realizar essas ações e, quando executados com bazel run
staging.apply
, se comportam como nossos próprios comandos bazel k8s-apply
ou bazel
k8s-delete
.
Outro exemplo: ts_api_guardian_test
Esse padrão também pode ser visto no projeto do Angular. A
Macro ts_api_guardian_test
produz dois destinos. O primeiro é um destino nodejs_test
padrão que compara
a saída gerada com uma expressão (ou seja, um arquivo que contém o
ou saída esperada). Isso pode ser criado e executado com uma invocação bazel
test
normal. No angular-cli
, é possível executar uma dessas
destino
com bazel test //etc/api:angular_devkit_core_api
.
Com o tempo, esse arquivo dourado pode precisar ser atualizado por motivos legítimos.
A atualização manual é tediosa e propensa a erros. Portanto, essa macro também fornece
um destino nodejs_binary
que atualiza o arquivo dourado, em vez de comparar
contra ele. Efetivamente, o mesmo script de teste pode ser escrito para ser executado em "verificar"
ou "aceitar" com base em como ele é invocado. Isso segue o mesmo padrão
que você já aprendeu: não existe um comando bazel test-accept
nativo, mas o
o mesmo efeito pode ser alcançado
bazel run //etc/api:angular_devkit_core_api.accept
.
Esse padrão pode ser bastante poderoso e acaba sendo bastante comum quando você e aprenda a reconhecê-lo.
Adaptação de suas próprias regras
Macros são a essência desse padrão. As macros são usadas como mas podem criar vários destinos. Normalmente, eles criam um destino com o nome especificado que executa a ação de versão principal: talvez cria um binário normal, uma imagem Docker ou um arquivo de código-fonte. Em nesse padrão, destinos adicionais são criados para produzir scripts que executam efeitos com base na saída do alvo principal, como publicar ou atualizar a saída de teste esperada.
Para ilustrar isso, inclua uma regra imaginária que gere um site com Sphinx com uma macro para criar outro que permite ao usuário publicá-lo quando estiver pronto. Considere o seguinte regra existente para gerar um site com o Sphinx:
_sphinx_site = rule(
implementation = _sphinx_impl,
attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
)
Em seguida, considere uma regra como a seguinte, que cria um script que, quando executado, publica as páginas geradas:
_sphinx_publisher = rule(
implementation = _publish_impl,
attrs = {
"site": attr.label(),
"_publisher": attr.label(
default = "//internal/sphinx:publisher",
executable = True,
),
},
executable = True,
)
Por fim, defina a seguinte macro para criar destinos para ambos os itens acima regras juntas:
def sphinx_site(name, srcs = [], **kwargs):
# This creates the primary target, producing the Sphinx-generated HTML.
_sphinx_site(name = name, srcs = srcs, **kwargs)
# This creates the secondary target, which produces a script for publishing
# the site generated above.
_sphinx_publisher(name = "%s.publish" % name, site = name, **kwargs)
Nos arquivos BUILD
, use a macro como se ela apenas criasse a instância principal
destino:
sphinx_site(
name = "docs",
srcs = ["index.md", "providers.md"],
)
Neste exemplo, um "documentos" destino é criado, assim como se a macro fosse uma
regra simples e padrão do Bazel. Quando criada, a regra gera configurações
e executa o Sphinx para produzir um site HTML, pronto para inspeção manual. No entanto,
um "docs.publish" adicional o destino também é criado, o que constrói um script
publicar o site. Depois de verificar a saída do destino principal, é possível
use bazel run :docs.publish
para publicá-lo para consumo público, assim como
um comando bazel publish
imaginário.
Não fica imediatamente claro o que a implementação do _sphinx_publisher
pode ser a regra. Muitas vezes, ações como essa escrevem um script de shell do launcher.
Esse método normalmente envolve o uso de
ctx.actions.expand_template
escrever um script de shell muito simples, nesse caso, invocando o binário do editor
com um caminho para a saída do destino principal. Dessa forma, o editor
implementação possa permanecer genérica, a regra _sphinx_site
pode apenas produzir
HTML, e esse pequeno script é tudo que você precisa para combinar os dois
juntas.
Em rules_k8s
, isso é realmente o que .apply
faz:
expand_template
escreve um script Bash muito simples, baseado
apply.sh.tpl
,
que executa kubectl
com a saída do destino principal. Esse script pode
depois vão ser criadas e executadas com bazel run :staging.apply
, fornecendo efetivamente um
Comando k8s-apply
para destinos k8s_object
.