diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index a47c164..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -### Test plan - - diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 84c87d6..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..8cea826 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"], + "customManagers": [ + { + "customType": "regex", + "fileMatch": ["^\\.github/workflows/ci\\.yaml$"], + "matchStrings": [ + "(?:repo|repository): (?[^\\s${]+)\\s+ref: (?[^\\s${]+)" + ], + "datasourceTemplate": "github-releases" + } + ], + "packageRules": [ + { + "matchManagers": ["custom.regex"], + "matchFileNames": [".github/workflows/ci.yaml"], + "schedule": ["* * 1 */3 *"] + }, + { + "matchPackageNames": ["tokio-rs/tokio"], + "extractVersion": "^tokio-(?\\d+\\.\\d+\\.\\d+)$" + } + ] +} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..26c6b77 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,131 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + flake-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: DeterminateSystems/nix-installer-action@v22 + with: + summarize: false + - uses: DeterminateSystems/magic-nix-cache-action@v13 + - run: nix flake check + + docker: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + - uses: DeterminateSystems/nix-installer-action@v22 + with: + summarize: false + - uses: DeterminateSystems/magic-nix-cache-action@v13 + + - name: Build docker image + run: nix build .#docker + + - name: Load image into Docker + run: docker load < result + + - name: Checkout target repo + uses: actions/checkout@v6 + with: + repository: BurntSushi/ripgrep + ref: 15.1.0 + path: target + + - name: Index target via Docker + run: docker run --rm -v "$PWD/target:/work" scip-rust:latest + + - name: Check index size + run: | + size=$(stat --format='%s' target/index.scip) + echo "Index size: $size bytes" + [ "$size" -ge 102400 ] || { echo "FAIL: index too small"; exit 1; } + + index: + strategy: + fail-fast: false + matrix: + include: + - name: ripgrep + repo: BurntSushi/ripgrep + ref: 15.1.0 + expect_file: crates/core/main.rs + - name: tokio + repo: tokio-rs/tokio + ref: tokio-1.52.3 + expect_file: tokio/src/lib.rs + - name: serde + repo: serde-rs/serde + ref: v1.0.228 + expect_file: serde/src/lib.rs + - name: ruff + repo: astral-sh/ruff + ref: 0.15.13 + expect_file: crates/ruff/src/main.rs + + runs-on: ubuntu-latest + name: ${{ matrix.name }} + timeout-minutes: 60 + + steps: + - uses: actions/checkout@v6 + - uses: DeterminateSystems/nix-installer-action@v22 + with: + summarize: false + - uses: DeterminateSystems/magic-nix-cache-action@v13 + + - name: Build scip-rust + run: nix build .#scip-rust + + - name: Download scip CLI + run: | + curl -fsSL https://github.com/sourcegraph/scip/releases/latest/download/scip-linux-amd64.tar.gz \ + | tar -xz -C /usr/local/bin scip + + - name: Checkout target repo + uses: actions/checkout@v6 + with: + repository: ${{ matrix.repo }} + ref: ${{ matrix.ref }} + path: target + + - name: Fetch dependencies + working-directory: target + run: cargo fetch + + - name: Run scip-rust + run: ./result/bin/scip-rust --output index.scip target + + - name: Validate index + run: | + size=$(stat --format='%s' index.scip) + echo "Index size: $size bytes" + [ "$size" -ge 1024 ] || { echo "FAIL: index too small"; exit 1; } + + scip stats --from index.scip --project-root target \ + | jq -e '.documents > 0 and .occurrences > 0 and .definitions > 0' + + scip print --json index.scip \ + | jq -e --arg f "${{ matrix.expect_file }}" \ + 'any(.documents[]; .relative_path == $f)' + + ci-pass: + if: always() + needs: [flake-check, docker, index] + runs-on: ubuntu-latest + steps: + - if: >- + contains(needs.*.result, 'failure') || + contains(needs.*.result, 'cancelled') + run: exit 1 diff --git a/.github/workflows/container-test.yml b/.github/workflows/container-test.yml deleted file mode 100644 index 4458a27..0000000 --- a/.github/workflows/container-test.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Container Test - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - container-test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Install Podman - run: | - sudo apt-get update - sudo apt-get install -y podman - - - name: Run container test - run: ./test-container.sh diff --git a/.github/workflows/pr-auditor.yml b/.github/workflows/pr-auditor.yml deleted file mode 100644 index e39ed38..0000000 --- a/.github/workflows/pr-auditor.yml +++ /dev/null @@ -1,28 +0,0 @@ -# See https://docs.sourcegraph.com/dev/background-information/ci#pr-auditor -name: pr-auditor -on: - pull_request_target: - types: [ closed, edited, opened, synchronize, ready_for_review ] - workflow_dispatch: - -jobs: - check-pr: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - repository: 'sourcegraph/devx-service' - token: ${{ secrets.PR_AUDITOR_TOKEN }} - - uses: actions/setup-go@v4 - with: { go-version: '1.22' } - - - run: 'go run ./cmd/pr-auditor' - env: - GITHUB_EVENT_PATH: ${{ env.GITHUB_EVENT_PATH }} - GITHUB_TOKEN: ${{ secrets.PR_AUDITOR_TOKEN }} - GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - report_failure: - needs: check-pr - if: ${{ failure() }} - uses: sourcegraph/workflows/.github/workflows/report-job-failure.yml@main - secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 25f21c1..976b7ad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,23 +9,23 @@ jobs: release-image: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: docker/setup-buildx-action@v1 + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@v22 - run: echo "PATCH=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV - run: echo "MINOR=${PATCH%.*}" >> $GITHUB_ENV - run: echo "MAJOR=${MINOR%.*}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and push - id: docker_build - uses: docker/build-push-action@v2 - with: - push: true - tags: | - sourcegraph/scip-rust:latest - sourcegraph/scip-rust:${{ env.PATCH }} - sourcegraph/scip-rust:${{ env.MINOR }} - sourcegraph/scip-rust:${{ env.MAJOR }} + - name: Build image with Nix + run: nix build .#docker + - name: Tag and push + run: | + set -eux + docker load < result + for TAG in latest "$PATCH" "$MINOR" "$MAJOR"; do + docker tag scip-rust:latest "sourcegraph/scip-rust:$TAG" + docker push "sourcegraph/scip-rust:$TAG" + done diff --git a/.gitignore b/.gitignore index e8ee010..d6944e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -scratch/ +/result* diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index fee0057..0000000 --- a/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM rust:1.89.0@sha256:e090f7b4adf86191313dba91260351d7f5e15cac0fe34f26706a805c0cb9641f - -COPY scip-rust /usr/local/bin/scip-rust - -RUN chmod +x /usr/local/bin/scip-rust - -RUN rustup component add rust-analyzer diff --git a/README.md b/README.md index b3d7698..f1a3b7a 100644 --- a/README.md +++ b/README.md @@ -3,5 +3,24 @@ At the moment, this is just a tiny wrapper around `rust-analyzer` to generate SCIP data, with the configuration set up for use by Sourcegraph. +## Usage + +Install [`rust-analyzer`](https://rust-analyzer.github.io/book/installation.html) (any recent +release works), make sure `cargo` and `rustc` are on `PATH`, then from the root of your +workspace run: + +```sh +rust-analyzer scip . +``` + +The [`scip-rust`](./scip-rust) script in this repo is the same one-liner with a few +preflight checks; you can drop it into `PATH` if you prefer a stable command name. + +For CI, the `sourcegraph/scip-rust` Docker image bundles everything: + +```sh +docker run --rm -v "$PWD:/work" sourcegraph/scip-rust +``` + If you want to upload LSIF to Sourcegraph.com in CI, check out [lsif-rust-action](https://github.com/sourcegraph/lsif-rust-action) instead. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..86c022c --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1778737229, + "narHash": "sha256-6xWoytx8jFW4PF1GjRm/i/53trbpKGfz6zjzQGBr4cI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d7a713c0b7e47c908258e71cba7a2d77cc8d71d5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3dd660f --- /dev/null +++ b/flake.nix @@ -0,0 +1,80 @@ +{ + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; + }; + + outputs = + { + self, + flake-utils, + nixpkgs, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + scip-rust = pkgs.writeShellApplication { + name = "scip-rust"; + runtimeEnv = { + SCIP_RUST_FALLBACK_CARGO = "${pkgs.cargo}/bin"; + SCIP_RUST_FALLBACK_RUSTC = "${pkgs.rustc}/bin"; + SCIP_RUST_FALLBACK_RUST_ANALYZER = "${pkgs.rust-analyzer}/bin"; + }; + text = builtins.readFile ./scip-rust; + }; + in + { + packages = { + inherit scip-rust; + default = scip-rust; + } + // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux { + docker = pkgs.dockerTools.buildLayeredImage { + name = "scip-rust"; + tag = "latest"; + contents = [ + scip-rust + pkgs.dockerTools.caCertificates + pkgs.git + ]; + fakeRootCommands = "mkdir -p /work /tmp"; + enableFakechroot = true; + config = { + Cmd = [ "scip-rust" ]; + WorkingDir = "/work"; + Env = [ "HOME=/tmp" ]; + }; + }; + }; + + checks = { + shellcheck = pkgs.runCommand "check-shellcheck" { } '' + ${pkgs.shellcheck}/bin/shellcheck ${./scip-rust} + touch $out + ''; + formatting = pkgs.runCommand "check-formatting" { } '' + ${pkgs.nixfmt}/bin/nixfmt --check ${./flake.nix} + ${pkgs.shfmt}/bin/shfmt -i 4 -ci -d ${./scip-rust} + touch $out + ''; + renovate = pkgs.runCommand "check-renovate" { } '' + LOG_LEVEL=warn ${pkgs.renovate}/bin/renovate-config-validator \ + ${./.github/renovate.json} + touch $out + ''; + }; + + devShells.default = pkgs.mkShellNoCC { + buildInputs = with pkgs; [ + cargo + nixfmt + rust-analyzer + rustc + shellcheck + shfmt + ]; + }; + } + ); +} diff --git a/scip-rust b/scip-rust index 3dc69a8..b2c5687 100755 --- a/scip-rust +++ b/scip-rust @@ -1,6 +1,26 @@ #!/usr/bin/env sh -set -eux +set -eu + +# Prefer tools already on PATH (so project-pinned toolchains via rustup or +# `rust-toolchain.toml` are honored). For any tool that is missing or broken +# (e.g. a rustup proxy whose component is not installed), prepend the per-tool +# path provided by the Nix package so it takes precedence; useful in CI +# environments without a fully provisioned local Rust toolchain. +for tool in cargo rust-analyzer rustc; do + if "$tool" --version >/dev/null 2>&1; then + continue + fi + case "$tool" in + cargo) export PATH="${SCIP_RUST_FALLBACK_CARGO:-}:${PATH}" ;; + rustc) export PATH="${SCIP_RUST_FALLBACK_RUSTC:-}:${PATH}" ;; + rust-analyzer) export PATH="${SCIP_RUST_FALLBACK_RUST_ANALYZER:-}:${PATH}" ;; + esac + if ! "$tool" --version >/dev/null 2>&1; then + echo "error: scip-rust requires '$tool' to be available." >&2 + exit 1 + fi +done # rust-analyzer's path lookup looks in subdirectories by default. For example, # in the general case, if you have multiple parallel workspaces, under say @@ -9,5 +29,10 @@ set -eux # and you run rust-analyzer with A/ as the project path, it will pick up all # crates (X1, X2, Y1 and Y2). So it is enough to run rust-analyzer once, # instead of once per workspace, or once per crate. - -rust-analyzer scip . > dump.scip +# +# Forward any extra args (e.g. `--output PATH`) to rust-analyzer; default +# to indexing the current directory if no path is given. +if [ $# -eq 0 ]; then + set -- . +fi +exec rust-analyzer scip "$@" diff --git a/test-container.sh b/test-container.sh deleted file mode 100755 index 053b20b..0000000 --- a/test-container.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${GREEN}Starting container test...${NC}" - -# Create scratch directory if it doesn't exist -if [[ ! -d "./scratch" ]]; then - echo -e "${YELLOW}Creating scratch directory...${NC}" - mkdir -p scratch -fi - -# Clone or update ripgrep repo -if [[ ! -d "./scratch/ripgrep" ]]; then - echo -e "${YELLOW}Cloning ripgrep repository...${NC}" - git clone https://github.com/BurntSushi/ripgrep.git ./scratch/ripgrep -else - echo -e "${YELLOW}Updating ripgrep repository...${NC}" - cd ./scratch/ripgrep - git fetch origin - git reset --hard origin/master - cd ../.. -fi - -# Build the container with linux/amd64 platform -echo -e "${YELLOW}Building container image...${NC}" -podman build --platform=linux/amd64 -t scip-rust-test . - -# Run the container against the ripgrep codebase -echo -e "${YELLOW}Running scip-rust against ripgrep codebase...${NC}" -podman run --platform=linux/amd64 --rm -v "./scratch/ripgrep:/workspace:z" scip-rust-test \ - /usr/local/bin/scip-rust /workspace - -echo -e "${GREEN}Container test completed successfully!${NC}"