La interacción diaria con Bazel ocurre principalmente con algunos comandos:
build
, test
y run
. Sin embargo, a veces, pueden parecer limitados:
quieres enviar paquetes a un repositorio, publicar documentación para usuarios finales o
implementar una aplicación con Kubernetes. Pero Bazel no tiene un publish
ni
Comando deploy
: ¿Dónde encajan estas acciones?
El comando bazel run
El enfoque de Bazel en la hermeticidad, la reproducibilidad y la incrementalidad significa la
Los comandos build
y test
no son útiles para las tareas anteriores. Estas acciones
pueden ejecutarse en una zona de pruebas, con acceso limitado a la red, y no se garantiza que
volver a ejecutar con cada bazel build
.
En su lugar, confía en bazel run
, la herramienta de trabajo para las tareas que quieres tener.
efectos secundarios. Los usuarios de Bazel están acostumbrados a las reglas que crean ejecutables y
los autores de reglas pueden seguir un conjunto común de patrones para extender esto
"verbos personalizados".
En el mundo real: rules_k8s
Por ejemplo, considera rules_k8s
,
las reglas de Kubernetes para Bazel. Supongamos que tienes el siguiente objetivo:
# BUILD file in //application/k8s
k8s_object(
name = "staging",
kind = "deployment",
cluster = "testing",
template = "deployment.yaml",
)
La regla k8s_object
crea un
archivo YAML de Kubernetes estándar cuando se usa bazel build
en el staging
objetivo. Sin embargo, k8s_object
también crea los destinos adicionales.
una macro con nombres como staging.apply
y :staging.delete
. Estos se compilan
secuencias de comandos para realizar esas acciones y, cuando se ejecutan con bazel run
staging.apply
, estas se comportan como nuestros propios comandos bazel k8s-apply
o bazel
k8s-delete
.
Otro ejemplo: ts_api_guardian_test
Este patrón también se puede ver en el proyecto de Angular. El
Macro ts_api_guardian_test
produce dos objetivos. El primero es un objetivo nodejs_test
estándar que compara
alguna salida generada frente a una columna “dorada” archivo (es decir, un archivo que contiene el
el resultado esperado). Esto se puede compilar y ejecutar con una invocación bazel
test
normal. En angular-cli
, puedes ejecutar una de estas
destino
con bazel test //etc/api:angular_devkit_core_api
.
Con el tiempo, es posible que este archivo dorado deba actualizarse por motivos legítimos.
Actualizar esto de forma manual es tedioso y propenso a errores, por lo que esta macro también proporciona
un objetivo nodejs_binary
que actualiza el archivo dorado, en lugar de comparar
y defenderte. De hecho, se puede escribir la misma secuencia de comandos de prueba para que se ejecute en "verify"
o "aceptar" basado en la forma en que se invoca. Esto sigue el mismo patrón
que ya aprendiste: no hay un comando bazel test-accept
nativo, pero el
se puede lograr el mismo efecto con
bazel run //etc/api:angular_devkit_core_api.accept
Este patrón puede ser bastante poderoso y resulta bastante común una vez que aprender a reconocerlos.
Adapta tus propias reglas
Las macros son el núcleo de este patrón. Las macros se usan de la siguiente manera: pero pueden crear varios objetivos. Por lo general, crearán un destino con el nombre especificado que realiza la acción de compilación principal: tal vez compila un objeto binario normal, una imagen de Docker o un archivo de código fuente. En este patrón, se crean destinos adicionales para producir secuencias de comandos basados en el resultado del objetivo principal, como publicar el objeto binario resultante o actualizar el resultado de la prueba esperado.
Para ilustrar esto, une una regla imaginaria que genere un sitio web con Sphinx con una macro para crear una capa adicional objetivo que permite al usuario publicarlo cuando está listo. Ten en cuenta lo siguiente: Regla existente para generar un sitio web con Sphinx:
_sphinx_site = rule(
implementation = _sphinx_impl,
attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
)
Luego, considera una regla como la siguiente, que compila una secuencia de comandos que, cuando se ejecute, publica las páginas generadas:
_sphinx_publisher = rule(
implementation = _publish_impl,
attrs = {
"site": attr.label(),
"_publisher": attr.label(
default = "//internal/sphinx:publisher",
executable = True,
),
},
executable = True,
)
Por último, define la siguiente macro para crear objetivos para las dos opciones anteriores reglas 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)
En los archivos BUILD
, usa la macro como si solo creara la principal
objetivo:
sphinx_site(
name = "docs",
srcs = ["index.md", "providers.md"],
)
En este ejemplo, se llama “documento se crea un destino, como si la macro fuera
la regla de Bazel estándar y única. Cuando se compila, la regla genera alguna configuración
y ejecuta Sphinx para crear un sitio HTML listo para una inspección manual. Sin embargo,
un archivo "docs.publish" adicional también se crea un destino, que crea una secuencia de comandos para
publicar el sitio. Una vez que verifiques el resultado del destino principal, podrás
usarás bazel run :docs.publish
para publicarlo y que sea para consumo público, al igual que
un comando bazel publish
imaginario.
No es evidente de inmediato cuál es la implementación de _sphinx_publisher
la regla de firewall. A menudo, las acciones como esta escriben una secuencia de comandos de shell launcher.
Por lo general, este método implica usar
ctx.actions.expand_template
para escribir una secuencia de comandos de shell muy sencilla, que, en este caso, invoque el objeto binario del publicador.
con una ruta de acceso al resultado del destino principal. De esta manera, el editor
sigue siendo genérica, la regla _sphinx_site
solo produce
HTML. Esta pequeña secuencia de comandos es todo lo que se necesita para combinar las dos
entre sí.
En rules_k8s
, .apply
hace lo siguiente:
expand_template
escribe una secuencia de comandos Bash muy simple basada en
apply.sh.tpl
,
que ejecuta kubectl
con el resultado del destino principal. Esta secuencia de comandos puede
luego se compilarán y ejecutarán con bazel run :staging.apply
, lo que proporcionará efectivamente un
Comando k8s-apply
para destinos k8s_object
.