Interaksi harian dengan Bazel terjadi terutama melalui beberapa perintah:
build
, test
, dan run
. Namun, terkadang hal ini bisa terasa terbatas: Anda mungkin
ingin mendorong 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 tersebut dapat dilakukan?
Perintah jalankan bazel
Fokus Bazel pada hermeticity, reproduktifitas, dan inkrementalitas berarti
perintah build
dan test
tidak membantu untuk tugas-tugas di atas. Tindakan ini dapat dijalankan di sandbox, dengan akses jaringan yang terbatas, dan tidak dijamin akan dijalankan kembali dengan setiap bazel build
.
Sebagai gantinya, andalkan bazel run
: pekerja lapangan untuk tugas yang Anda inginkan memiliki efek samping. Pengguna Bazel terbiasa dengan aturan yang membuat file yang dapat dieksekusi, dan penulis aturan dapat mengikuti kumpulan pola umum untuk memperluasnya ke "kata kerja kustom".
Di alam liar: 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
mem-build 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 dieksekusi dengan bazel run
staging.apply
, 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. 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). Ini dapat dibuat dan dijalankan dengan pemanggilan bazel
test
normal. Di angular-cli
, Anda dapat menjalankan salah satu target tersebut dengan bazel test //etc/api:angular_devkit_core_api
.
Seiring waktu, file emas ini mungkin perlu diperbarui untuk alasan yang sah.
Memperbaruinya secara manual sangat merepotkan dan rentan error, sehingga makro ini juga memberikan
target nodejs_binary
yang memperbarui file emas, bukan membandingkan
dengan file tersebut. Secara efektif, skrip pengujian yang sama dapat ditulis untuk dijalankan dalam mode "verifikasi"
atau "setujui", berdasarkan cara pemanggilannya. Hal ini mengikuti pola yang sama
dengan 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 cukup efektif, dan ternyata cukup umum setelah Anda mempelajarinya.
Mengadaptasi aturan Anda sendiri
Makro adalah inti dari pola ini. Makro digunakan seperti aturan, tetapi dapat membuat beberapa target. Biasanya, class ini akan membuat target dengan nama tertentu yang melakukan tindakan build utama: mungkin membuat biner normal, image Docker, atau arsip kode sumber. Dalam pola ini, target tambahan dibuat untuk menghasilkan skrip yang menjalankan efek samping berdasarkan output target utama, seperti memublikasikan biner yang dihasilkan atau memperbarui output pengujian yang diharapkan.
Sebagai ilustrasinya, gabungkan aturan imajiner yang menghasilkan situs dengan Sphinx dengan makro untuk membuat target tambahan, sehingga pengguna dapat memublikasikannya saat sudah 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 berjalan, memublikasikan halaman yang dihasilkan:
_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 aturan di atas:
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 makro hanya membuat target utama:
sphinx_site(
name = "docs",
srcs = ["index.md", "providers.md"],
)
Dalam contoh ini, target "dokumen" dibuat, seolah-olah makro adalah aturan Bazel tunggal standar. Ketika di-build, aturan tersebut menghasilkan beberapa konfigurasi
dan menjalankan Sphinx untuk menghasilkan situs HTML, yang siap untuk diperiksa secara manual. Namun, target "docs.publish" tambahan juga akan dibuat, yang membuat skrip untuk memublikasikan situs. Setelah memeriksa output target utama, Anda dapat
menggunakan bazel run :docs.publish
untuk memublikasikannya untuk konsumsi publik, seperti
perintah bazel publish
fiktif.
Tidak langsung terlihat seperti apa penerapan aturan _sphinx_publisher
. Sering kali, tindakan seperti ini menulis skrip shell launcher.
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, penerapan
penayang dapat tetap bersifat umum, aturan _sphinx_site
hanya dapat menghasilkan
HTML, dan skrip kecil inilah yang diperlukan untuk menggabungkan keduanya.
Di rules_k8s
, hal 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 selanjutnya dapat dibuat dan dijalankan dengan bazel run :staging.apply
, yang secara efektif memberikan perintah k8s-apply
untuk target k8s_object
.