diff --git a/.github/workflows/daily-cronjobs.yml b/.github/workflows/daily-cronjobs.yml new file mode 100644 index 0000000000..3a91e7fa7c --- /dev/null +++ b/.github/workflows/daily-cronjobs.yml @@ -0,0 +1,129 @@ +name: daily-cronjobs + +# Daily cronjobs workflow. Individual jobs can be added here over time. +on: + workflow_dispatch: + schedule: + - cron: "0 4 * * *" + # TODO: remove the temporary push and pull_request triggers; only schedule + # will remain once this is no longer being used for branch testing. + push: + branches: [ master, feature/ci-dev ] + pull_request: + +jobs: + postprocess-test-and-cache: + runs-on: ubuntu-latest + + env: + # TODO: remove once postprocess can pick its own model defaults again. + C2RUST_POSTPROCESS_MODEL: ${{ vars.C2RUST_POSTPROCESS_MODEL }} + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + C2RUST_POSTPROCESS_CACHE_PREFIX: postprocess-${{ vars.C2RUST_POSTPROCESS_MODEL }}-cache- + # Generates new cache and tests fresh model responses. + + # Steps represent a sequence of tasks that will be executed as part of the job. + steps: + - name: Require GEMINI key + if: ${{ env.GEMINI_API_KEY == '' }} + run: exit 1 + + - name: Checkout c2rust + uses: actions/checkout@v4 + with: + submodules: false + + - name: Restore postprocess cache + uses: actions/cache/restore@v4 + with: + path: c2rust-postprocess/tests/llm-cache + key: ${{ env.C2RUST_POSTPROCESS_CACHE_PREFIX }}${{ github.run_id }}-${{ github.run_attempt }} + restore-keys: | + ${{ env.C2RUST_POSTPROCESS_CACHE_PREFIX }} + + # TODO: remove once cache/ref debugging is finished. + - name: Report workflow context + run: | + echo "event_name=$GITHUB_EVENT_NAME" + echo "ref=$GITHUB_REF" + echo "ref_name=$GITHUB_REF_NAME" + echo "head_ref=${GITHUB_HEAD_REF:-}" + echo "base_ref=${GITHUB_BASE_REF:-}" + + - name: Checkout submodules + run: | + git submodule update --init --checkout tests/integration/tests/json-c/repo + + - uses: astral-sh/setup-uv@v6 + + - run: uv python install + + - uses: Swatinem/rust-cache@v2 + with: + cache-workspace-crates: true + + - name: Install Rust toolchains + run: | + rustup toolchain install nightly-2022-11-03 \ + --profile minimal --component rustfmt,rustc-dev + rustup toolchain install nightly-2023-04-15 \ + --profile minimal --component rustfmt + + - name: Provision Debian Packages + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: | + build-essential + libbrotli-dev + libbz2-dev + libclang-18-dev + libdb-dev + libgcrypt20 + libgdbm-dev + libreadline-dev + libidn2-dev + libldap2-dev + liblzma-dev + libnghttp2-dev + libpcre3-dev + libpsl-dev + librtmp-dev + libtool + llvm + llvm-dev + libzstd-dev + rcs + tcl-dev + tk-dev + zlib1g-dev + + - name: Install build-essential + run: | + sudo apt-get -qq update + sudo apt-get -qq install build-essential + + - name: Build c2rust + env: + LLVM_CONFIG_PATH: /usr/bin/llvm-config-18 + run: cargo build --release + + - name: Build tools + run: | + (cd tools && cargo build --release --manifest-path split_rust/Cargo.toml) + (cd tools && cargo build --release --manifest-path merge_rust/Cargo.toml) + + - name: Run json-c testsuite + run: | + export PATH=$PWD/target/release:$PWD/c2rust-postprocess:$HOME/.local/bin:$PATH + export C2RUST_DIR=$PWD + # TODO: remove once the temporary narrow postprocess test surface is + # no longer needed. + export C2RUST_POSTPROCESS_ARGS="--ident-filter '^(json_object_set_userdata|json_object_to_file)$'" + (cd tests/integration && ./test.py json-c) + + - name: Save postprocess cache + if: ${{ success() }} + uses: actions/cache/save@v4 + with: + path: c2rust-postprocess/tests/llm-cache + key: ${{ env.C2RUST_POSTPROCESS_CACHE_PREFIX }}${{ github.run_id }}-${{ github.run_attempt }} diff --git a/.github/workflows/internal-testsuite.yml b/.github/workflows/internal-testsuite.yml index 18b36294ed..0cdb3048a6 100644 --- a/.github/workflows/internal-testsuite.yml +++ b/.github/workflows/internal-testsuite.yml @@ -29,6 +29,14 @@ jobs: # The type of runner that the job will run on runs-on: ${{ matrix.runner }} + env: + # TODO: remove once postprocess can pick its own model defaults again. + C2RUST_POSTPROCESS_MODEL: ${{ vars.C2RUST_POSTPROCESS_MODEL }} + # Uses cache-only responses; skips uncached work and exercises cached + # postprocess output usage. + C2RUST_POSTPROCESS_ARGS: --on-error warn + C2RUST_POSTPROCESS_CACHE_PREFIX: postprocess-${{ vars.C2RUST_POSTPROCESS_MODEL }}-cache- + # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -40,7 +48,7 @@ jobs: # `update = none` is set, which makes this not work, so we need to update them manually. # See `.gitmodules` for more info. submodules: false - + - name: Checkout submodules run: | git submodule update --init --checkout tests/integration/tests/curl/repo @@ -52,6 +60,30 @@ jobs: git submodule update --init --checkout tests/integration/tests/python2/repo git submodule update --init --checkout tests/integration/tests/libmcs/repo + - name: Restore postprocess cache + id: postprocess-cache + uses: actions/cache/restore@v4 + with: + path: c2rust-postprocess/tests/llm-cache + key: ${{ env.C2RUST_POSTPROCESS_CACHE_PREFIX }}${{ github.run_id }}-${{ github.run_attempt }} + restore-keys: | + ${{ env.C2RUST_POSTPROCESS_CACHE_PREFIX }} + + # TODO: remove once cache/ref debugging is finished. + - name: Report postprocess cache restore + run: | + echo "postprocess cache prefix: $C2RUST_POSTPROCESS_CACHE_PREFIX" + echo "postprocess cache hit: ${{ steps.postprocess-cache.outputs.cache-hit }}" + + # TODO: remove once cache/ref debugging is finished. + - name: Report workflow context + run: | + echo "event_name=$GITHUB_EVENT_NAME" + echo "ref=$GITHUB_REF" + echo "ref_name=$GITHUB_REF_NAME" + echo "head_ref=${GITHUB_HEAD_REF:-}" + echo "base_ref=${GITHUB_BASE_REF:-}" + - uses: astral-sh/setup-uv@v6 - run: uv python install diff --git a/c2rust-postprocess/postprocess/transforms/base.py b/c2rust-postprocess/postprocess/transforms/base.py index 16a144a4f4..2182d64307 100644 --- a/c2rust-postprocess/postprocess/transforms/base.py +++ b/c2rust-postprocess/postprocess/transforms/base.py @@ -102,9 +102,11 @@ def apply_file( continue if ident_regex and not ident_regex.search(identifier): + # TODO: remove this temporary ident-filter log once the + # narrow cronjob test surface is gone. logging.info( - f"Skipping Rust fn {identifier} in {rust_source_file}" - f"due to ident filter {ident_filter}" + f"Skipping Rust fn {identifier} in {rust_source_file} " + "due to ident filter" ) continue diff --git a/c2rust-postprocess/postprocess/transforms/comments.py b/c2rust-postprocess/postprocess/transforms/comments.py index d750d03f98..8a632b92c0 100644 --- a/c2rust-postprocess/postprocess/transforms/comments.py +++ b/c2rust-postprocess/postprocess/transforms/comments.py @@ -105,12 +105,17 @@ def apply_ident( model=model, messages=messages, ): + # TODO: remove this temporary cache-hit logging once the cronjob + # postprocess path is no longer being debugged in CI. + logging.info(f"Cache hit for {identifier}; using cached response") return response = self.model.generate_with_tools(messages) if response is None: if api_key_from_env(model) is None: + # TODO: remove this temporary cache-miss warning once the + # cache-only consumer path is no longer being exercised in CI. # No API key set: skip uncached entries instead of failing. logging.warning( f"Cache miss for {identifier}; skipping since no API key was set..." diff --git a/tests/integration/tests/__init__.py b/tests/integration/tests/__init__.py index b00de1ff15..0f1801b03f 100644 --- a/tests/integration/tests/__init__.py +++ b/tests/integration/tests/__init__.py @@ -138,12 +138,16 @@ def print_outcome(outcome: str, color: str): # noinspection PyBroadException try: + # TODO: remove once postprocess testing no longer needs special log + # visibility in CI. + stdout = subprocess.DEVNULL + stderr = subprocess.DEVNULL + if stage in ["postprocess", "cargo.postprocess"]: + stdout = None + stderr = None if verbose: stdout = None stderr = None - else: - stdout = subprocess.DEVNULL - stderr = subprocess.DEVNULL subprocess.check_call( cwd=self.dir, args=[script_path], diff --git a/tests/integration/tests/templates.py b/tests/integration/tests/templates.py index 3dd85aa1e8..192afe2b31 100644 --- a/tests/integration/tests/templates.py +++ b/tests/integration/tests/templates.py @@ -201,12 +201,24 @@ def autogen_postprocess( params = {"args": ""} + # TODO: remove this temporary forwarding block and revert the whole file + # diff once the cronjob-specific postprocess flags are no longer needed. + model = os.getenv("C2RUST_POSTPROCESS_MODEL") + if model: + params["args"] = shlex.join(["--llm-model", model]) + + extra_args = os.getenv("C2RUST_POSTPROCESS_ARGS") + if extra_args: + args = shlex.split(params["args"]) if params["args"] else [] + args.extend(shlex.split(extra_args)) + params["args"] = shlex.join(args) + exclude_file = conf.with_name("postprocess-exclude.yml") if exclude_file.exists(): + args = shlex.split(params["args"]) if params["args"] else [] # args are relative to script dir - params["args"] = shlex.join( - ["--exclude-file", str(exclude_file.relative_to(conf.parent))] - ) + args.extend(["--exclude-file", str(exclude_file.relative_to(conf.parent))]) + params["args"] = shlex.join(args) if verbose: params["args"] = f"--log-level DEBUG {params['args']}".rstrip()