Interaksi sehari-hari dengan Bazel terutama terjadi melalui beberapa perintah:
build
, test
, dan run
. Namun, terkadang, ini terasa terbatas: Anda mungkin
ingin mendorong paket ke repositori, mempublikasikan dokumentasi untuk pengguna akhir, atau
men-deploy aplikasi dengan Kubernetes. Namun, Bazel tidak memiliki publish
atau
Perintah deploy
– di mana fungsi tindakan ini?
Perintah{i> bazel run<i}
Fokus Bazel pada kehermetisitas, reproduksi, dan inkrementalitas berarti
Perintah build
dan test
tidak membantu untuk tugas di atas. Tindakan ini
dapat berjalan di sandbox, dengan akses jaringan yang terbatas, dan tidak dijamin
dijalankan kembali setiap bazel build
.
Sebagai gantinya, andalkan bazel run
: pekerja keras untuk tugas-tugas yang ingin Anda miliki
efek samping. Pengguna Bazel sudah terbiasa dengan aturan
yang membuat {i>executable<i}, dan
penulis aturan dapat mengikuti seperangkat
pola umum untuk memperluas ini ke
"custom verbs".
Secara umum: 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 staging
target. Namun, target tambahan juga dibuat oleh k8s_object
makro dengan nama seperti staging.apply
dan :staging.delete
. Alat-alat tersebut
skrip untuk melakukan tindakan tersebut, dan jika dieksekusi dengan bazel run
staging.apply
, skrip ini berperilaku seperti perintah bazel k8s-apply
atau bazel
k8s-delete
kita sendiri.
Contoh lain: ts_api_guardian_test
Pola ini juga dapat dilihat di project Angular. Tujuan
Makro ts_api_guardian_test
menghasilkan dua target. Yang pertama adalah target nodejs_test
standar yang membandingkan
beberapa output yang dihasilkan terhadap (yaitu, file yang berisi
output yang diharapkan). Fungsi ini dapat dibangun dan dijalankan dengan pemanggilan bazel
test
normal. Di angular-cli
, Anda dapat menjalankan salah satu contoh
target
dengan bazel test //etc/api:angular_devkit_core_api
.
Seiring waktu, file emas ini mungkin perlu diperbarui untuk alasan yang sah.
Memperbarui ini secara manual merepotkan dan rentan terhadap kesalahan, sehingga makro ini juga memberikan
target nodejs_binary
yang memperbarui file emas, bukan membandingkan
terhadapnya. Secara efektif, skrip pengujian yang sama dapat ditulis untuk dijalankan di "verify"
atau "setuju" berdasarkan bagaimana ia dipanggil. Ini mengikuti pola yang sama
yang telah Anda pelajari: tidak ada perintah bazel test-accept
native, tetapi
efek yang sama
dapat dicapai dengan
bazel run //etc/api:angular_devkit_core_api.accept
.
Pola ini bisa sangat ampuh, dan ternyata cukup umum setelah Anda belajar mengenalinya.
Mengadaptasi 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 Cloud Build membangun biner normal, image Docker, atau arsip kode sumber. Di beberapa pola ini, target tambahan dibuat untuk menghasilkan skrip yang menjalankan efek berdasarkan output target utama, seperti memublikasikan biner yang dihasilkan atau memperbarui output pengujian yang diharapkan.
Untuk mengilustrasikan hal ini, gabungkan aturan imajiner yang menghasilkan {i>website<i} dengan Sphinx dengan makro untuk membuat target yang memungkinkan pengguna mempublikasikannya jika sudah siap. Pertimbangkan hal berikut aturan yang ada untuk membuat situs web 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 berikut untuk membuat target bagi kedua hal di atas aturan bersama-sama:
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)
Di file BUILD
, gunakan makro seolah-olah hanya akan membuat
target:
sphinx_site(
name = "docs",
srcs = ["index.md", "providers.md"],
)
Dalam contoh ini, "dokumen" dibuat, seolah-olah makro adalah
aturan Bazel tunggal standar. Saat dibuat, aturan menghasilkan beberapa konfigurasi
dan menjalankan Sphinx untuk menghasilkan situs HTML, yang siap untuk pemeriksaan manual. Namun,
"docs.publish" tambahan target juga dibuat, yang membangun skrip untuk
memublikasikan situs. Setelah memeriksa output target utama, Anda dapat
menggunakan bazel run :docs.publish
untuk memublikasikannya agar dapat diakses oleh publik, seperti
perintah bazel publish
imajiner.
Anda tidak bisa langsung memahami seperti apa implementasi dari _sphinx_publisher
aturan tersebut. Sering kali, 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 penayang
dengan jalur ke output target utama. Dengan cara ini, penayang
implementasi dapat tetap bersifat umum, aturan _sphinx_site
hanya dapat menghasilkan
HTML, dan skrip kecil ini adalah yang
diperlukan untuk menggabungkan keduanya
secara
bersamaan.
Di rules_k8s
, 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 dapat
di-build dan dijalankan dengan bazel run :staging.apply
, yang secara efektif menyediakan
Perintah k8s-apply
untuk target k8s_object
.