การใช้มาโครเพื่อสร้างคำกริยาที่กำหนดเอง

รายงานปัญหา ดูแหล่งที่มา /3} /4} {3/4} {3/4} {3/4} {3/4} /4.

การโต้ตอบแบบวันต่อวันกับ Bazel จะเกิดขึ้นผ่านคำสั่ง 2-3 คำสั่งเป็นหลัก ได้แก่ build, test และ run แต่บางครั้งอาจมีข้อจำกัด เช่น พุชแพ็กเกจไปยังที่เก็บ เผยแพร่เอกสารสำหรับผู้ใช้ปลายทาง หรือทำให้แอปพลิเคชันใช้งานได้ด้วย Kubernetes แต่ Bazel ไม่มีคำสั่ง publish หรือ deploy การดำเนินการเหล่านี้เหมาะกับตำแหน่งใด

คำสั่งเรียกใช้ Bazel

การมุ่งเน้นของ Bazel ในด้านความสุจริต การทำซ้ำ และส่วนเพิ่มทำให้คำสั่ง build และ test ไม่มีประโยชน์ต่องานข้างต้น การดำเนินการเหล่านี้อาจทำงานในแซนด์บ็อกซ์โดยมีสิทธิ์เข้าถึงเครือข่ายที่จำกัด และไม่รับประกันว่าจะทำงานซ้ำในทุก bazel build

แต่ให้ใช้ bazel run แทน ซึ่งเป็นภาระงานที่คุณต้องการให้มีผลข้างเคียง ผู้ใช้ Bazel คุ้นเคยกับกฎที่สร้างคำสั่ง และผู้เขียนกฎสามารถทำตามชุดรูปแบบทั่วไปเพื่อขยายข้อความนี้ไปยัง "คำกริยาที่กำหนดเอง"

ป่าเถื่อน: rules_k8s

ตัวอย่างเช่น ลองพิจารณา rules_k8s กฎ Kubernetes สำหรับ Bazel สมมติว่าคุณมีเป้าหมายต่อไปนี้

# BUILD file in //application/k8s
k8s_object(
    name = "staging",
    kind = "deployment",
    cluster = "testing",
    template = "deployment.yaml",
)

กฎ k8s_object จะสร้างไฟล์ Kubernetes YAML มาตรฐานเมื่อมีการใช้ bazel build ในเป้าหมาย staging อย่างไรก็ตาม มาโคร k8s_object จะสร้างเป้าหมายเพิ่มเติมที่มีชื่ออย่างเช่น staging.apply และ :staging.delete ด้วย สคริปต์บิลด์เหล่านี้เพื่อดำเนินการดังกล่าว และเมื่อดำเนินการด้วย bazel run staging.apply สคริปต์เหล่านี้จะทำงานเหมือนคำสั่ง bazel k8s-apply หรือ bazel k8s-delete ของเราเอง

อีกตัวอย่างหนึ่ง: ts_api_guardian_test

รูปแบบนี้สามารถดูในโปรเจ็กต์ Angular ได้ด้วย มาโคร ts_api_guardian_test จะสร้างเป้าหมาย 2 รายการ รายการแรกคือเป้าหมาย nodejs_test มาตรฐาน ซึ่งจะเปรียบเทียบเอาต์พุตที่สร้างขึ้นบางรายการกับไฟล์ "สีทอง" (ซึ่งก็คือไฟล์ที่มีเอาต์พุตที่คาดไว้) ซึ่งสร้างและเรียกใช้ได้ด้วยการเรียกใช้ bazel test ปกติ ใน angular-cli คุณสามารถเรียกใช้เป้าหมายดังกล่าวด้วย bazel test //etc/api:angular_devkit_core_api

เมื่อเวลาผ่านไป คุณอาจต้องอัปเดตไฟล์ทองคำนี้ด้วยเหตุผลที่เหมาะสม การอัปเดตนี้ด้วยตัวเองเป็นเรื่องน่าเบื่อและเกิดข้อผิดพลาดได้ง่าย มาโครนี้จึงมีเป้าหมาย nodejs_binary ที่อัปเดตไฟล์ทองคำแทนที่จะเปรียบเทียบด้วย สามารถเขียนสคริปต์ทดสอบเดียวกันให้ทำงานในโหมด "ยืนยัน" หรือ "ยอมรับ" ได้อย่างมีประสิทธิภาพ โดยขึ้นอยู่กับลักษณะการเรียกใช้ ซึ่งเป็นไปตามรูปแบบที่คุณได้เรียนรู้ไปแล้ว กล่าวคือไม่มีคำสั่ง bazel test-accept ดั้งเดิม แต่จะได้ผลลัพธ์ที่เหมือนกันด้วย bazel run //etc/api:angular_devkit_core_api.accept

รูปแบบนี้อาจใช้ได้ผลดีมาก และค่อนข้างจะเป็นรูปแบบที่พบได้บ่อยเมื่อคุณเรียนรู้ที่จะจดจำ

การปรับกฎของคุณเอง

มาโครคือหัวใจของรูปแบบนี้ มาโครนั้นใช้เหมือนกับกฎ แต่สามารถสร้างเป้าหมายได้หลายเป้าหมาย โดยทั่วไปพวกเขาจะสร้างเป้าหมายด้วยชื่อที่ระบุ ซึ่งจะดำเนินการบิลด์หลัก ซึ่งอาจเป็นการสร้างไบนารีปกติ อิมเมจ Docker หรือที่เก็บถาวรของซอร์สโค้ด ในรูปแบบนี้ ระบบจะสร้างเป้าหมายเพิ่มเติมเพื่อสร้างสคริปต์ที่สร้างผลลัพธ์ข้างเคียงตามผลลัพธ์ของเป้าหมายหลัก เช่น การเผยแพร่ไบนารีที่เป็นผลลัพธ์หรืออัปเดตเอาต์พุตทดสอบที่คาดไว้

เพื่อให้เห็นภาพชัดขึ้น ให้รวมกฎสมมติที่สร้างเว็บไซต์ด้วย Sphinx กับมาโครเพื่อสร้างเป้าหมายเพิ่มเติมที่อนุญาตให้ผู้ใช้เผยแพร่เมื่อพร้อม พิจารณากฎที่มีอยู่ต่อไปนี้สำหรับการสร้างเว็บไซต์ที่มี Sphinx

_sphinx_site = rule(
     implementation = _sphinx_impl,
     attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
)

จากนั้น ให้พิจารณากฎต่อไปนี้ ซึ่งจะสร้างสคริปต์ที่เมื่อเรียกใช้ จะเผยแพร่หน้าเว็บที่สร้างขึ้น

_sphinx_publisher = rule(
    implementation = _publish_impl,
    attrs = {
        "site": attr.label(),
        "_publisher": attr.label(
            default = "//internal/sphinx:publisher",
            executable = True,
        ),
    },
    executable = True,
)

สุดท้าย ให้กำหนดมาโครต่อไปนี้เพื่อสร้างเป้าหมายสำหรับกฎทั้ง 2 ข้อข้างต้นร่วมกัน

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)

ในไฟล์ BUILD ให้ใช้มาโครเหมือนกับว่าเพียงแค่สร้างเป้าหมายหลัก

sphinx_site(
    name = "docs",
    srcs = ["index.md", "providers.md"],
)

ในตัวอย่างนี้ ระบบจะสร้างเป้าหมาย "เอกสาร" เช่นเดียวกับที่มาโครเป็นกฎ Bazel มาตรฐานเดียว เมื่อสร้างแล้ว กฎจะสร้างการกำหนดค่าบางอย่าง และเรียกใช้ Sphinx เพื่อสร้างเว็บไซต์ HTML ซึ่งพร้อมสำหรับการตรวจสอบด้วยตนเอง อย่างไรก็ตาม จะมีการสร้างเป้าหมาย "docs.publish" เพิ่มเติมด้วย ซึ่งจะสร้างสคริปต์สำหรับการเผยแพร่เว็บไซต์ เมื่อตรวจสอบเอาต์พุตของเป้าหมายหลักแล้ว คุณจะใช้ bazel run :docs.publish เพื่อเผยแพร่รายการดังกล่าวเพื่อการบริโภคแบบสาธารณะได้ เช่นเดียวกับคำสั่ง bazel publish ในจินตนาการ

แต่ยังไม่ทราบชัดเจนทันทีว่าการใช้งานกฎ _sphinx_publisher มีลักษณะอย่างไร การดำเนินการเช่นนี้มักจะเขียนสคริปต์เชลล์ Launcher โดยทั่วไปเมธอดนี้จะเกี่ยวข้องกับการใช้ ctx.actions.expand_template เพื่อเขียนสคริปต์ Shell แบบง่ายมาก ซึ่งในกรณีนี้จะเรียกใช้ไบนารีของผู้เผยแพร่โฆษณาที่มีเส้นทางไปยังเอาต์พุตของเป้าหมายหลัก วิธีนี้ทำให้การใช้งานของผู้เผยแพร่โฆษณายังคงเป็นแบบทั่วไป กฎ _sphinx_site จะสร้าง HTML ได้เท่านั้น และสคริปต์ขนาดเล็กนี้ก็เป็นสิ่งที่จำเป็นในการรวม 2 ทั้ง 2 อย่างไว้ด้วยกัน

ใน rules_k8s นี่คือสิ่งที่ .apply ทำจริงๆ expand_template เขียนสคริปต์ Bash แบบง่ายๆ โดยอิงจาก apply.sh.tpl ซึ่งเรียกใช้ kubectl พร้อมเอาต์พุตของเป้าหมายหลัก จากนั้นสคริปต์นี้จะสามารถสร้างและเรียกใช้ด้วย bazel run :staging.apply โดยมีคำสั่ง k8s-apply สำหรับเป้าหมาย k8s_object อย่างมีประสิทธิภาพ