From 351071d9cdcf06a715f93a92b1cc5149ba82dc9f Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Mon, 16 Sep 2019 12:55:43 -0700 Subject: [PATCH] Let's try a github action to build things (#743) Summary: This commit adds a getdeps command that is able to generate a workflow file for the GitHub Actions CI environment. The workflow file could be expressed more simply using the matrix syntax and with three steps (checkout, build, test), but I chose to break out the steps for each of the dependencies because the UX while waiting on the build is much nicer that way: the steps show during and live log tailing for the section of the build that is underway. If they were all lumped into a single build step then the logs from the boost section of the build dominate and make the github UI work very hard. Pull Request resolved: https://github.com/facebook/watchman/pull/743 Test Plan: https://github.com/facebook/watchman/pull/743 successfully executes the github actions CI flow. ``` $ opensource/fbcode_builder/getdeps.py generate-github-actions --output-file watchman/.github/workflows/main.yml watchman ``` Reviewed By: simpkins Differential Revision: D17384915 Pulled By: wez fbshipit-source-id: 9a9e5a3e806c18f6cc38ba1cb7059740cda01ad4 --- build/fbcode_builder/getdeps.py | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/build/fbcode_builder/getdeps.py b/build/fbcode_builder/getdeps.py index 105aa435a..4a19b00ac 100755 --- a/build/fbcode_builder/getdeps.py +++ b/build/fbcode_builder/getdeps.py @@ -527,6 +527,108 @@ class TestCmd(ProjectCmdBase): parser.add_argument("--test-owner", help="Owner for testpilot") +@cmd("generate-github-actions", "generate a GitHub actions configuration") +class GenerateGitHubActionsCmd(ProjectCmdBase): + def run_project_cmd(self, args, loader, manifest): + platforms = [ + HostType("linux", "ubuntu", "18"), + HostType("darwin", None, None), + HostType("windows", None, None), + ] + + with open(args.output_file, "w") as out: + # Deliberate line break here because the @ and the generated + # symbols are meaningful to our internal tooling when they + # appear in a single token + out.write("# This file was @") + out.write("generated by getdeps.py\n") + out.write( + """ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: +""" + ) + for p in platforms: + build_opts = setup_build_options(args, p) + self.write_job_for_platform(out, args, build_opts) + + def write_job_for_platform(self, out, args, build_opts): + ctx_gen = build_opts.get_context_generator() + loader = ManifestLoader(build_opts, ctx_gen) + manifest = loader.load_manifest(args.project) + manifest_ctx = loader.ctx_gen.get_context(manifest.name) + + # Some projects don't do anything "useful" as a leaf project, only + # as a dep for a leaf project. Check for those here; we don't want + # to waste the effort scheduling them on CI. + # We do this by looking at the builder type in the manifest file + # rather than creating a builder and checking its type because we + # don't know enough to create the full builder instance here. + if manifest.get("build", "builder", ctx=manifest_ctx) == "nop": + return None + + if build_opts.is_linux(): + job_name = "linux" + runs_on = "ubuntu-18.04" + elif build_opts.is_windows(): + # We're targeting the windows-2016 image because it has + # Visual Studio 2017 installed, and at the time of writing, + # the version of boost in the manifests (1.69) is not + # buildable with Visual Studio 2019 + job_name = "windows" + runs_on = "windows-2016" + else: + job_name = "mac" + runs_on = "macOS-latest" + + out.write(" %s:\n" % job_name) + out.write(" runs-on: %s\n" % runs_on) + out.write(" steps:\n") + out.write(" - uses: actions/checkout@v1\n") + + projects = loader.manifests_in_dependency_order() + + for m in projects: + if m != manifest: + out.write(" - name: Fetch %s\n" % m.name) + out.write( + " run: python build/fbcode_builder/getdeps.py fetch " + "--no-tests %s\n" % m.name + ) + + for m in projects: + if m != manifest: + out.write(" - name: Build %s\n" % m.name) + out.write( + " run: python build/fbcode_builder/getdeps.py build " + "--no-tests %s\n" % m.name + ) + + out.write(" - name: Build %s\n" % manifest.name) + out.write( + " run: python build/fbcode_builder/getdeps.py build --src-dir=. %s\n" + % manifest.name + ) + + out.write(" - name: Test %s\n" % manifest.name) + out.write( + " run: python build/fbcode_builder/getdeps.py test --src-dir=. %s\n" + % manifest.name + ) + + def setup_project_cmd_parser(self, parser): + parser.add_argument("--output-file", help="The name of the yaml file") + + def get_arg_var_name(args): for arg in args: if arg.startswith("--"):