Interaksi sehari-hari dengan Bazel terutama terjadi melalui beberapa perintah:
build
, test
, dan run
. Namun, terkadang, fitur ini terasa terbatas: Anda mungkin ingin mengirim paket ke repositori, memublikasikan dokumentasi untuk pengguna akhir, atau men-deploy aplikasi dengan Kubernetes. Namun, Bazel tidak memiliki perintah publish
atau
deploy
– di mana tindakan ini dapat dilakukan?
Perintah bazel run
Fokus Bazel pada hermetisitas, reproduksibilitas, dan inkrementalitas berarti perintah
build
dan test
tidak berguna untuk tugas di atas. Tindakan ini
dapat berjalan di sandbox, dengan akses jaringan terbatas, dan tidak dijamin akan
dijalankan ulang dengan setiap bazel build
.
Sebagai gantinya, gunakan bazel run
: alat bantu untuk tugas yang ingin Anda miliki
efek sampingnya. Pengguna Bazel terbiasa dengan aturan yang membuat file yang dapat dieksekusi, dan
penulis aturan dapat mengikuti serangkaian pola umum untuk memperluasnya ke
"kata kerja kustom".
Di luar sana: rules_k8s
Misalnya, pertimbangkan rules_k8s
,
aturan Kubernetes untuk Bazel. Misalkan Anda memiliki target berikut:
# BUILD file in //application/k8s
k8s_object(
name = "staging",
kind = "deployment",
cluster = "testing",
template = "deployment.yaml",
)
Aturan k8s_object
membuat file YAML Kubernetes standar saat bazel build
digunakan pada target staging
. Namun, target tambahan juga dibuat oleh makro k8s_object
dengan nama seperti staging.apply
dan :staging.delete
. Skrip build ini untuk melakukan tindakan tersebut, dan saat dijalankan dengan bazel run
staging.apply
, skrip ini berperilaku seperti perintah bazel k8s-apply
atau bazel
k8s-delete
kita sendiri.
Contoh lainnya: ts_api_guardian_test
Pola ini juga dapat dilihat di project Angular. Makro
ts_api_guardian_test
menghasilkan dua target. Yang pertama adalah target nodejs_test
standar yang membandingkan
beberapa output yang dihasilkan dengan file "golden" (yaitu, file yang berisi
output yang diharapkan). Hal ini dapat dibangun dan dijalankan dengan pemanggilan bazel
test
normal. Di angular-cli
, Anda dapat menjalankan salah satu
target
dengan bazel test //etc/api:angular_devkit_core_api
.
Seiring waktu, file utama ini mungkin perlu diperbarui karena alasan yang sah.
Memperbarui ini secara manual sangat membosankan dan rentan terhadap error, jadi makro ini juga menyediakan target nodejs_binary
yang memperbarui file standar, bukan membandingkannya. Secara efektif, skrip pengujian yang sama dapat ditulis untuk dijalankan dalam mode "verifikasi"
atau "terima", berdasarkan cara pemanggilannya. Hal ini mengikuti pola yang sama
yang telah Anda pelajari: tidak ada perintah bazel test-accept
bawaan, tetapi
efek yang sama dapat dicapai dengan
bazel run //etc/api:angular_devkit_core_api.accept
.
Pola ini bisa sangat efektif, dan ternyata cukup umum setelah Anda belajar mengenalinya.
Menyesuaikan aturan Anda sendiri
Makro adalah inti dari pola ini. Makro digunakan seperti aturan, tetapi dapat membuat beberapa target. Biasanya, mereka akan membuat target dengan nama yang ditentukan yang melakukan tindakan build utama: mungkin target tersebut membangun biner normal, image Docker, atau arsip kode sumber. Dalam pola ini, target tambahan dibuat untuk menghasilkan skrip yang melakukan efek samping berdasarkan output target utama, seperti memublikasikan biner yang dihasilkan atau memperbarui output pengujian yang diharapkan.
Untuk mengilustrasikannya, gabungkan aturan imajiner yang menghasilkan situs dengan Sphinx dengan makro untuk membuat target tambahan yang memungkinkan pengguna memublikasikannya saat siap. Pertimbangkan aturan yang ada berikut untuk membuat situs dengan Sphinx:
_sphinx_site = rule(
implementation = _sphinx_impl,
attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
)
Selanjutnya, pertimbangkan aturan seperti berikut, yang membuat skrip yang, saat dijalankan, memublikasikan halaman yang dibuat:
_sphinx_publisher = rule(
implementation = _publish_impl,
attrs = {
"site": attr.label(),
"_publisher": attr.label(
default = "//internal/sphinx:publisher",
executable = True,
),
},
executable = True,
)
Terakhir, tentukan makro simbolik berikut (tersedia di Bazel 8 atau yang lebih baru) untuk membuat target untuk kedua aturan di atas secara bersamaan:
def _sphinx_site_impl(name, visibility, srcs, **kwargs):
# This creates the primary target, producing the Sphinx-generated HTML. We
# set `visibility = visibility` to make it visible to callers of the
# macro.
_sphinx_site(name = name, visibility = visibility, srcs = srcs, **kwargs)
# This creates the secondary target, which produces a script for publishing
# the site generated above. We don't want it to be visible to callers of
# our macro, so we omit visibility for it.
_sphinx_publisher(name = "%s.publish" % name, site = name, **kwargs)
sphinx_site = macro(
implementation = _sphinx_site_impl,
attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
# Inherit common attributes like tags and testonly
inherit_attrs = "common",
)
Atau, jika Anda perlu mendukung rilis Bazel yang lebih lama dari Bazel 8, Anda harus menentukan makro lama:
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)
Dalam file BUILD
, gunakan makro seolah-olah hanya membuat target
utama:
sphinx_site(
name = "docs",
srcs = ["index.md", "providers.md"],
)
Dalam contoh ini, target "docs" dibuat, sama seperti jika makro adalah
aturan Bazel standar tunggal. Saat dibuat, aturan ini akan menghasilkan beberapa konfigurasi
dan menjalankan Sphinx untuk menghasilkan situs HTML, yang siap untuk diperiksa secara manual. Namun,
target "docs.publish" tambahan juga dibuat, yang membuat skrip untuk
memublikasikan situs. Setelah memeriksa output target utama, Anda dapat
menggunakan bazel run :docs.publish
untuk memublikasikannya agar dapat digunakan oleh publik, seperti
perintah bazel publish
imajiner.
Tidak langsung terlihat seperti apa penerapan aturan _sphinx_publisher
tersebut. Biasanya, tindakan seperti ini akan menulis skrip shell peluncur.
Metode ini biasanya melibatkan penggunaan
ctx.actions.expand_template
untuk menulis skrip shell yang sangat sederhana, dalam hal ini memanggil biner penerbit
dengan jalur ke output target utama. Dengan demikian, penerapan penayang dapat tetap bersifat umum, aturan _sphinx_site
hanya dapat menghasilkan HTML, dan skrip kecil ini adalah semua yang diperlukan untuk menggabungkan keduanya.
Di rules_k8s
, memang inilah yang dilakukan .apply
:
expand_template
menulis skrip Bash yang sangat sederhana, berdasarkan
apply.sh.tpl
,
yang menjalankan kubectl
dengan output target utama. Skrip ini kemudian dapat dibangun dan dijalankan dengan bazel run :staging.apply
, sehingga secara efektif menyediakan perintah k8s-apply
untuk target k8s_object
.