diff --git a/.github/workflows/gcp-deploy-staging.yml b/.github/workflows/gcp-deploy-staging.yml new file mode 100644 index 00000000..2173cb31 --- /dev/null +++ b/.github/workflows/gcp-deploy-staging.yml @@ -0,0 +1,38 @@ +name: GCP Deploy (staging) + +on: + workflow_run: + workflows: ["Publish to ghcr (staging)"] + types: + - completed + +jobs: + deploy: + name: Deploy staging app to GCP + runs-on: ubuntu-latest + + steps: + - name: Configure SSH + run: | + mkdir -p ~/.ssh/ + echo "${{ secrets.GCP_STAGING_SSH_PRIVATE_KEY }}" > ~/.ssh/private.key + chmod 600 ~/.ssh/private.key + echo "${{ secrets.GCP_STAGING_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts + + - name: Deploy to GCP + run: | + ssh -i ~/.ssh/private.key ${{ secrets.GCP_STAGING_USERNAME }}@${{ secrets.GCP_STAGING_HOST }} << 'EOF' + # Stop and remove any existing container + docker stop -t 60 sourcebot-staging || true + docker rm sourcebot-staging || true + + # Run new container + docker run -d \ + -p 80:3000 \ + --rm \ + --pull always \ + --env-file .env.staging \ + -v /mnt/data:/data \ + --name sourcebot-staging \ + ghcr.io/sourcebot-dev/sourcebot:staging + EOF \ No newline at end of file diff --git a/.github/workflows/ghcr-publish.yml b/.github/workflows/ghcr-publish.yml index 0863a349..dc740fa2 100644 --- a/.github/workflows/ghcr-publish.yml +++ b/.github/workflows/ghcr-publish.yml @@ -14,7 +14,7 @@ env: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.runs-on}} permissions: contents: read packages: write @@ -23,9 +23,14 @@ jobs: id-token: write strategy: matrix: - platform: - - linux/amd64 - - linux/arm64 + platform: [linux/amd64, linux/arm64] + include: + - platform: linux/amd64 + runs-on: ubuntu-latest + - platform: linux/arm64 + runs-on: ubuntu-24.04-arm + + steps: - name: Prepare @@ -76,7 +81,7 @@ jobs: build-args: | SOURCEBOT_VERSION=${{ github.ref_name }} POSTHOG_PAPIK=${{ secrets.POSTHOG_PAPIK }} - + - name: Export digest run: | mkdir -p /tmp/digests diff --git a/.github/workflows/staging-ghcr-public.yml b/.github/workflows/staging-ghcr-public.yml index b75532df..f29b56fa 100644 --- a/.github/workflows/staging-ghcr-public.yml +++ b/.github/workflows/staging-ghcr-public.yml @@ -70,7 +70,8 @@ jobs: outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true build-args: | SOURCEBOT_VERSION=${{ github.ref_name }} - POSTHOG_PAPIK=${{ secrets.STAGING_POSTHOG_PAPIK }} + POSTHOG_PAPIK=${{ secrets.POSTHOG_PAPIK }} + SOURCEBOT_ENCRYPTION_KEY=${{ secrets.STAGING_SOURCEBOT_ENCRYPTION_KEY }} - name: Export digest run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index b64bd46b..084bb8e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.8.4] - 2025-03-14 + +### Fixed + +- Fixed bug where Sourcebot Cloud card was shown to self-hosted users + +## [2.8.3] - 2025-03-13 + +### Fixed + +- Made syntax reference guide keyboard shortcut hints clickable. ([#229](https://github.com/sourcebot-dev/sourcebot/pull/229)) + +## [2.8.2] - 2025-02-20 + +### Fixed + +- Remove `repo_synced` telemetry event. + +## [2.8.1] - 2025-01-28 + +### Added + +- Added `maxTrigramCount` to the config to control the maximum allowable of trigrams per document. + +### Fixed + +- Fixed issue with version upgrade toast not appearing without a hard refresh. ([#179](https://github.com/sourcebot-dev/sourcebot/pull/179)) + +## [2.8.0] - 2025-01-17 + +### Added + +- Added a syntax reference guide. The guide can be opened using the hotkey "Cmd + /" ("Ctrl + /" on Windows). ([#169](https://github.com/sourcebot-dev/sourcebot/pull/169)) + +## [2.7.1] - 2025-01-15 + +### Fixed + +- Fixed issue where we crash on startup if the install / upgrade PostHog event fails to send. ([#159](https://github.com/sourcebot-dev/sourcebot/pull/159)) +- Fixed issue with broken file links. ([#161](https://github.com/sourcebot-dev/sourcebot/pull/161)) + ## [2.7.0] - 2025-01-10 ### Added diff --git a/Dockerfile b/Dockerfile index de5bd950..d5886578 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,7 @@ ENV NEXT_TELEMETRY_DISABLED=1 # @see: https://phase.dev/blog/nextjs-public-runtime-variables/ ARG NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED=BAKED_NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED ARG NEXT_PUBLIC_SOURCEBOT_VERSION=BAKED_NEXT_PUBLIC_SOURCEBOT_VERSION +ENV NEXT_PUBLIC_PUBLIC_SEARCH_DEMO=BAKED_NEXT_PUBLIC_PUBLIC_SEARCH_DEMO ENV NEXT_PUBLIC_POSTHOG_PAPIK=BAKED_NEXT_PUBLIC_POSTHOG_PAPIK ENV NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=BAKED_NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ENV NEXT_PUBLIC_SENTRY_ENVIRONMENT=BAKED_NEXT_PUBLIC_SENTRY_ENVIRONMENT @@ -93,6 +94,10 @@ ARG SOURCEBOT_VERSION=unknown ENV SOURCEBOT_VERSION=$SOURCEBOT_VERSION RUN echo "Sourcebot Version: $SOURCEBOT_VERSION" +ARG PUBLIC_SEARCH_DEMO=false +ENV PUBLIC_SEARCH_DEMO=$PUBLIC_SEARCH_DEMO +RUN echo "Public Search Demo: $PUBLIC_SEARCH_DEMO" + # Valid values are: debug, info, warn, error ENV SOURCEBOT_LOG_LEVEL=info diff --git a/demo-site-config.json b/demo-site-config.json index ebc3a3b3..169e4c93 100644 --- a/demo-site-config.json +++ b/demo-site-config.json @@ -209,140 +209,19 @@ "atom/atom", "Eugeny/tabby", "lodash/lodash", - "chrislgarry/Apollo-11", - "xingshaocheng/architect-awesome", - "comfyanonymous/ComfyUI", - "h5bp/Front-end-Developer-Interview-Questions", - "adam-p/markdown-here", - "binhnguyennus/awesome-scalability", - "jquery/jquery", - "bradtraversy/design-resources-for-developers", - "danielmiessler/SecLists", "caddyserver/caddy", "sindresorhus/awesome-nodejs", "rust-unofficial/awesome-rust", - "mastodon/mastodon", - "Stirling-Tools/Stirling-PDF", - "iamkun/dayjs", - "romkatv/powerlevel10k", - "algorithm-visualizer/algorithm-visualizer", - "charlax/professional-programming", - "poteto/hiring-without-whiteboards", - "FFmpeg/FFmpeg", - "laurent22/joplin", - "serverless/serverless", - "justjavac/awesome-wechat-weapp", - "minimaxir/big-list-of-naughty-strings", - "agalwood/Motrix", - "JuliaLang/julia", - "square/okhttp", - "firstcontributions/first-contributions", - "geekan/MetaGPT", - "appwrite/appwrite", - "starship/starship", - "PowerShell/PowerShell", - "Avik-Jain/100-Days-Of-ML-Code", - "ziishaned/learn-regex", - "typescript-cheatsheets/react", - "go-gitea/gitea", - "kamranahmedse/design-patterns-for-humans", - "v2ray/v2ray-core", - "karan/Projects", - "WerWolv/ImHex", - "gogs/gogs", - "x64dbg/x64dbg", - "PaddlePaddle/PaddleOCR", - "AlistGo/alist", - "android/architecture-samples", - "meteor/meteor", - "jestjs/jest", - "ColorlibHQ/AdminLTE", - "pixijs/pixijs", - "slab/quill", - "FuelLabs/fuels-ts", - "FuelLabs/fuels-rs", - "pandas-dev/pandas", - "huginn/huginn", - "type-challenges/type-challenges", - "nlohmann/json", - "parcel-bundler/parcel", - "Asabeneh/30-Days-Of-JavaScript", - "vercel/hyper", - "aymericdamien/TensorFlow-Examples", - "jakevdp/PythonDataScienceHandbook", - "astaxie/build-web-application-with-golang", - "babel/babel", - "Asabeneh/30-Days-Of-Python", - "toeverything/AFFiNE", - "google/zx", - "hashicorp/terraform", - "square/retrofit", - "dkhamsing/open-source-ios-apps", - "isocpp/CppCoreGuidelines", - "brillout/awesome-react-components", - "TanStack/query", - "dypsilon/frontend-dev-bookmarks", - "discourse/discourse", - "akullpp/awesome-java", - "skylot/jadx", - "grpc/grpc", "streamich/react-use", "pocketbase/pocketbase", "serhii-londar/open-source-mac-os-apps", "lllyasviel/Fooocus", "k88hudson/git-flight-rules", "react-hook-form/react-hook-form", - "yangshun/front-end-interview-handbook", - "clash-verge-rev/clash-verge-rev", - "Homebrew/brew", - "Unitech/pm2", - "Leaflet/Leaflet", - "hacksider/Deep-Live-Cam", - "kelseyhightower/kubernetes-the-hard-way", - "yarnpkg/yarn", - "Alamofire/Alamofire", - "lyswhut/lx-music-desktop", - "oobabooga/text-generation-webui", - "bailicangdu/vue2-elm", - "jeecgboot/JeecgBoot", - "GitSquared/edex-ui", - "RocketChat/Rocket.Chat", - "dbeaver/dbeaver", - "THUDM/ChatGLM-6B", - "microsoft/monaco-editor", - "faif/python-patterns", - "LeCoupa/awesome-cheatsheets", - "styled-components/styled-components", - "apache/dubbo", - "DovAmir/awesome-design-patterns", - "nwjs/nw.js", - "alex/what-happens-when", - "sudheerj/reactjs-interview-questions", - "dcloudio/uni-app", - "apache/spark", - "dotnet/aspnetcore", - "novuhq/novu", - "naptha/tesseract.js", - "babysor/MockingBird", - "freeCodeCamp/devdocs", - "SimplifyJobs/Summer2025-Internships", - "zhongyang219/TrafficMonitor", - "denysdovhan/wtfjs", - "ziglang/zig", - "expo/expo", - "lukasz-madon/awesome-remote-job", - "geekxh/hello-algorithm", - "alvarotrigo/fullPage.js", - "coollabsio/coolify", - "shadowsocks/shadowsocks-android", "koajs/koa", "SheetJS/sheetjs", "trpc/trpc", "LC044/WeChatMsg", - "rasbt/LLMs-from-scratch", - "microsoft/AI-For-Beginners", - "Kong/insomnia", - "usememos/memos", "airbnb/lottie-android", "huihut/interview", "jgm/pandoc", @@ -353,39 +232,6 @@ "files-community/Files", "sahat/hackathon-starter", "appsmithorg/appsmith", - "formulahendry/955.WLB", - "lapce/lapce", - "jondot/awesome-react-native", - "bumptech/glide", - "carbon-app/carbon", - "unknwon/the-way-to-go_ZH_CN", - "chenfei-wu/TaskMatrix", - "typeorm/typeorm", - "gradio-app/gradio", - "google-research/google-research", - "colinhacks/zod", - "sharkdp/fd", - "saadeghi/daisyui", - "nodejs/node-v0.x-archive", - "ray-project/ray", - "rapid7/metasploit-framework", - "maybe-finance/maybe", - "OpenBB-finance/OpenBB", - "gofiber/fiber", - "junegunn/vim-plug", - "halo-dev/halo", - "DIYgod/RSSHub", - "goabstract/Awesome-Design-Tools", - "docker/compose", - "helix-editor/helix", - "penpot/penpot", - "httpie/cli", - "BVLC/caffe", - "hankcs/HanLP", - "AykutSarac/jsoncrack.com", - "zenorocha/clipboard.js", - "jaredpalmer/formik", - "testerSunshine/12306", "ultralytics/ultralytics", "slidevjs/slidev", "xitu/gold-miner", @@ -395,30 +241,11 @@ "shadowsocks/shadowsocks", "ccxt/ccxt", "netty/netty", - "PKUanonym/REKCARC-TSC-UHT", "tw93/Pake", "fxsjy/jieba", "atlassian/react-beautiful-dnd", "ToolJet/ToolJet", "markedjs/marked", - "Blankj/AndroidUtilCode", - "AFNetworking/AFNetworking", - "alebcay/awesome-shell", - "spacedriveapp/spacedrive", - "adobe/brackets", - "karanpratapsingh/system-design", - "xkcoding/spring-boot-demo", - "halfrost/LeetCode-Go", - "XX-net/XX-Net", - "gulpjs/gulp", - "immutable-js/immutable-js", - "nushell/nushell", - "calcom/cal.com", - "2noise/ChatTTS", - "zxing/zxing", - "alibaba/easyexcel", - "GitHubDaily/GitHubDaily", - "sqlmapproject/sqlmap", "typicode/husky", "laravel/framework", "TheAlgorithms/JavaScript", @@ -428,152 +255,6 @@ "huggingface/pytorch-image-models", "shadowsocks/ShadowsocksX-NG", "carbon-language/carbon-lang", - "chatchat-space/Langchain-Chatchat", - "jaywcjlove/linux-command", - "FlowiseAI/Flowise", - "harness/harness", - "fengdu78/Coursera-ML-AndrewNg-Notes", - "google/material-design-lite", - "freqtrade/freqtrade", - "bayandin/awesome-awesomeness", - "KRTirtho/spotube", - "geekcomputers/Python", - "Pythagora-io/gpt-pilot", - "reworkd/AgentGPT", - "python-poetry/poetry", - "TeamNewPipe/NewPipe", - "facebookresearch/faiss", - "astral-sh/uv", - "kilimchoi/engineering-blogs", - "zhayujie/chatgpt-on-wechat", - "vllm-project/vllm", - "The-Run-Philosophy-Organization/run", - "certbot/certbot", - "upscayl/upscayl", - "beego/beego", - "zsh-users/zsh-autosuggestions", - "Trinea/android-open-project", - "Chanzhaoyu/chatgpt-web", - "CMU-Perceptual-Computing-Lab/openpose", - "hashicorp/vault", - "ryanhanwu/How-To-Ask-Questions-The-Smart-Way", - "swc-project/swc", - "portainer/portainer", - "milvus-io/milvus", - "hasura/graphql-engine", - "ibraheemdev/modern-unix", - "makeplane/plane", - "ziadoz/awesome-php", - "qishibo/AnotherRedisDesktopManager", - "ehang-io/nps", - "yewstack/yew", - "SeleniumHQ/selenium", - "mattermost/mattermost", - "blueimp/jQuery-File-Upload", - "TheAlgorithms/C-Plus-Plus", - "lllyasviel/ControlNet", - "ReactiveX/rxjs", - "pola-rs/polars", - "SerenityOS/serenity", - "amix/vimrc", - "pcottle/learnGitBranching", - "microsoft/MS-DOS", - "dockur/windows", - "mqyqingfeng/Blog", - "facebookresearch/detectron2", - "jax-ml/jax", - "jqlang/jq", - "niklasvh/html2canvas", - "geekan/HowToLiveLonger", - "veggiemonk/awesome-docker", - "vercel/swr", - "airbnb/lottie-web", - "facebookresearch/fairseq", - "lizongying/my-tv", - "gedoor/legado", - "zbezj/HEU_KMS_Activator", - "alibaba/p3c", - "karpathy/LLM101n", - "alibaba/nacos", - "lib-pku/libpku", - "explosion/spaCy", - "mathiasbynens/dotfiles", - "yunjey/pytorch-tutorial", - "huiyadanli/RevokeMsgPatcher", - "ityouknow/spring-boot-examples", - "Binaryify/NeteaseCloudMusicApi", - "floating-ui/floating-ui", - "remix-run/remix", - "cockroachdb/cockroach", - "remoteintech/remote-jobs", - "binarywang/WxJava", - "0xAX/linux-insides", - "labstack/echo", - "balena-io/etcher", - "ianstormtaylor/slate", - "myshell-ai/OpenVoice", - "ShareX/ShareX", - "pnpm/pnpm", - "joshbuchea/HEAD", - "coolsnowwolf/lede", - "qier222/YesPlayMusic", - "microsoft/calculator", - "symfony/symfony", - "aseprite/aseprite", - "SortableJS/Sortable", - "v2fly/v2ray-core", - "open-mmlab/mmdetection", - "vuejs/vue-cli", - "webtorrent/webtorrent", - "layui/layui", - "payloadcms/payload", - "foundation/foundation-sites", - "tatsu-lab/stanford_alpaca", - "sequelize/sequelize", - "donnemartin/interactive-coding-challenges", - "kubernetes/minikube", - "llvm/llvm-project", - "pbatard/rufus", - "gchq/CyberChef", - "react-boilerplate/react-boilerplate", - "parallax/jsPDF", - "ariya/phantomjs", - "zeromicro/go-zero", - "square/leakcanary", - "dokku/dokku", - "lovell/sharp", - "elsewhencode/project-guidelines", - "aosabook/500lines", - "AMAI-GmbH/AI-Expert-Roadmap", - "dromara/hutool", - "fabricjs/fabric.js", - "transloadit/uppy", - "IanLunn/Hover", - "apolloconfig/apollo", - "lukehoban/es6features", - "VincentGarreau/particles.js", - "standard/standard", - "OAI/OpenAPI-Specification", - "influxdata/influxdb", - "CSSEGISandData/COVID-19", - "apache/kafka", - "trailofbits/algo", - "JushBJJ/Mr.-Ranedeer-AI-Tutor", - "codex-team/editor.js", - "herrbischoff/awesome-macos-command-line", - "mckaywrigley/chatbot-ui", - "linexjlin/GPTs", - "mpv-player/mpv", - "refinedev/refine", - "alan2207/bulletproof-react", - "jobbole/awesome-python-cn", - "tqdm/tqdm", - "kodecocodes/swift-algorithm-club", - "outline/outline", - "qbittorrent/qBittorrent", - "facebook/rocksdb", - "xinntao/Real-ESRGAN", - "cheeriojs/cheerio", "s0md3v/roop", "ascoders/weekly", "backstage/backstage", @@ -582,89 +263,6 @@ "tastejs/todomvc", "lutzroeder/netron", "alibaba/canal", - "Lightning-AI/pytorch-lightning", - "encode/django-rest-framework", - "postcss/postcss", - "facebook/folly", - "kenwheeler/slick", - "Ebazhanov/linkedin-skill-assessments-quizzes", - "alpinejs/alpine", - "GoogleChrome/lighthouse", - "AllThingsSmitty/css-protips", - "Mintplex-Labs/anything-llm", - "hashicorp/consul", - "charmbracelet/bubbletea", - "realpython/python-guide", - "mifi/lossless-cut", - "wuyouzhuguli/SpringAll", - "vuejs/vuex", - "microsoft/Data-Science-For-Beginners", - "usebruno/bruno", - "directus/directus", - "fastapi/full-stack-fastapi-template", - "MonitorControl/MonitorControl", - "OWASP/CheatSheetSeries", - "schollz/croc", - "codepath/android_guides", - "k3s-io/k3s", - "numpy/numpy", - "pmndrs/react-spring", - "YunaiV/ruoyi-vue-pro", - "surrealdb/surrealdb", - "ZuzooVn/machine-learning-for-software-engineers", - "caolan/async", - "google/comprehensive-rust", - "ageron/handson-ml2", - "jashkenas/backbone", - "alibaba/spring-cloud-alibaba", - "acheong08/ChatGPT", - "GorvGoyl/Clone-Wars", - "alibaba/druid", - "docsifyjs/docsify", - "jamiebuilds/the-super-tiny-compiler", - "xuxueli/xxl-job", - "iawia002/lux", - "google-ai-edge/mediapipe", - "hiroi-sora/Umi-OCR", - "ueberdosis/tiptap", - "digitalocean/nginxconfig.io", - "wesbos/JavaScript30", - "immerjs/immer", - "viraptor/reverse-interview", - "pmndrs/react-three-fiber", - "derailed/k9s", - "JedWatson/react-select", - "nextcloud/server", - "Pierian-Data/Complete-Python-3-Bootcamp", - "ChartsOrg/Charts", - "nagadomi/waifu2x", - "mobxjs/mobx", - "donnemartin/data-science-ipython-notebooks", - "DevToys-app/DevToys", - "zadam/trilium", - "cfenollosa/os-tutorial", - "google-research/tuning_playbook", - "meta-llama/llama3", - "lenve/vhr", - "mli/paper-reading", - "Advanced-Frontend/Daily-Interview-Question", - "YMFE/yapi", - "spf13/viper", - "eugeneyan/applied-ml", - "MichaelCade/90DaysOfDevOps", - "utmapp/UTM", - "jashkenas/underscore", - "vadimdemedes/ink", - "geekcompany/ResumeSample", - "tokio-rs/tokio", - "GitbookIO/gitbook", - "statelyai/xstate", - "cloudcommunity/Free-Certifications", - "google/python-fire", - "mouredev/Hello-Python", - "Tencent/weui", - "nothings/stb", - "helm/helm", "tinygrad/tinygrad", "ManimCommunity/manim", "filebrowser/filebrowser", @@ -674,151 +272,26 @@ "crossoverJie/JCSprout", "mantinedev/mantine", "Automattic/mongoose", - "zhiwehu/Python-programming-exercises", - "michalsnik/aos", - "Homebrew/legacy-homebrew", - "mudler/LocalAI", - "HeyPuter/puter", - "mindsdb/mindsdb", - "restic/restic", - "codemirror/codemirror5", - "CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers", - "tj/commander.js", - "rethinkdb/rethinkdb", - "dnSpy/dnSpy", - "fzaninotto/Faker", - "angular/angular-cli", - "ajaxorg/ace", - "coder2gwy/coder2gwy", - "qianguyihao/Web", - "houshanren/hangzhou_house_knowledge", - "swagger-api/swagger-ui", - "sampotts/plyr", - "IceWhaleTech/CasaOS", - "nvie/gitflow", - "go-kit/kit", - "imDazui/Tvlist-awesome-m3u-m3u8", - "exelban/stats", - "huggingface/diffusers", - "vercel/turborepo", - "AmruthPillai/Reactive-Resume", - "getredash/redash", - "python-telegram-bot/python-telegram-bot", - "telegramdesktop/tdesktop", - "mongodb/mongo", - "bvaughn/react-virtualized", - "firecracker-microvm/firecracker", - "openai/CLIP", - "fish-shell/fish-shell", - "dmlc/xgboost", - "fastai/fastai", - "tailwindlabs/headlessui", - "medusajs/medusa", - "xyflow/xyflow", - "remy/nodemon", - "hashicorp/vagrant", - "XIU2/TrackersListCollection", - "LadybirdBrowser/ladybird", - "facebookresearch/Detectron", - "dragonflydb/dragonfly", - "motiondivision/motion", - "grafana/k6", - "AvaloniaUI/Avalonia", - "qiurunze123/miaosha", - "ggreer/the_silver_searcher", - "vnpy/vnpy", - "rstacruz/nprogress", - "Asabeneh/30-Days-Of-React", - "microsoft/cascadia-code", - "rxhanson/Rectangle", - "openssl/openssl", - "spipm/Depix", - "svc-develop-team/so-vits-svc", - "XTLS/Xray-core", - "sunface/rust-course", - "quasarframework/quasar", - "deezer/spleeter", - "getcursor/cursor", - "cmderdev/cmder", - "kuchin/awesome-cto", - "Textualize/textual", - "facebookresearch/fastText", - "ossrs/srs", - "sindresorhus/awesome-electron", - "emscripten-core/emscripten", - "AdguardTeam/AdGuardHome", - "danielmiessler/fabric", - "select2/select2", - "pjreddie/darknet", - "OpenBMB/ChatDev", - "awesome-foss/awesome-sysadmin", - "airbnb/lottie-ios", - "dwmkerr/hacker-laws", - "powerline/fonts", - "vbenjs/vue-vben-admin", - "VSCodium/vscodium", - "wailsapp/wails", - "alibaba/fastjson", - "JakeChampion/fetch", - "signalapp/Signal-Android", - "t3-oss/create-t3-app", - "littlecodersh/ItChat", - "ValdikSS/GoodbyeDPI", - "jumpserver/jumpserver", - "request/request", - "chatanywhere/GPT_API_free", - "Modernizr/Modernizr", - "tmrts/go-patterns", - "taichi-dev/taichi", - "DigitalPlatDev/FreeDomain", - "haizlin/fe-interview", - "terryum/awesome-deep-learning-papers", - "DataTalksClub/data-engineering-zoomcamp", - "JakeWharton/butterknife", - "discordjs/discord.js", - "ChrisTitusTech/winutil", - "ycm-core/YouCompleteMe", - "Vision-CAIR/MiniGPT-4", - "DrKLO/Telegram", - "mozilla/DeepSpeech", - "hwdsl2/setup-ipsec-vpn", - "nginx/nginx", - "rollup/rollup", - "mbeaudru/modern-js-cheatsheet", - "ZuodaoTech/everyone-can-use-english", - "apache/incubator-seata", - "TanStack/table", - "hollischuang/toBeTopJavaer", - "fyne-io/fyne", - "sdras/awesome-actions", - "academic/awesome-datascience", - "ApolloAuto/apollo", - "zyedidia/micro", - "akveo/ngx-admin", - "kataras/iris", - "refined-github/refined-github", - "openfaas/faas", - "infiniflow/ragflow", - "ageron/handson-ml", - "locustio/locust", "eslint/eslint", "nextauthjs/next-auth", - "viatsko/awesome-vscode", "flameshot-org/flameshot", - "envoyproxy/envoy", - "RVC-Project/Retrieval-based-Voice-Conversion-WebUI", - "valinet/ExplorerPatcher", - "react-native-elements/react-native-elements", - "NvChad/NvChad", - "marmelab/react-admin", - "feathericons/feather", - "datasciencemasters/go", - "OpenZeppelin/openzeppelin-contracts", - "SDWebImage/SDWebImage", - "celery/celery", - "drizzle-team/drizzle-orm", - "nsqio/nsq" + "envoyproxy/envoy" ] + }, + { + "type": "gitlab", + "token": { + "env": "GITLAB_TOKEN" + }, + "groups": [ + "fdroid" + ], + "exclude": { + "projects": [ + "fdroid/wiki", + "Matrixcoffee/internal-twif-preview" + ] + } } ] } \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index f3f24641..9cb6e416 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -70,14 +70,16 @@ if [ ! -f "$FIRST_RUN_FILE" ]; then # If this is our first run, send a `install` event to PostHog # (if telemetry is enabled) if [ -z "$SOURCEBOT_TELEMETRY_DISABLED" ]; then - curl -L -s --header "Content-Type: application/json" -d '{ + if ! ( curl -L --output /dev/null --silent --fail --header "Content-Type: application/json" -d '{ "api_key": "'"$POSTHOG_PAPIK"'", "event": "install", "distinct_id": "'"$SOURCEBOT_INSTALL_ID"'", "properties": { "sourcebot_version": "'"$SOURCEBOT_VERSION"'" } - }' https://us.i.posthog.com/capture/ > /dev/null + }' https://us.i.posthog.com/capture/ ) then + echo -e "\e[33m[Warning] Failed to send install event.\e[0m" + fi fi else export SOURCEBOT_INSTALL_ID=$(cat "$FIRST_RUN_FILE" | jq -r '.install_id') @@ -88,7 +90,7 @@ else echo -e "\e[34m[Info] Upgraded from version $PREVIOUS_VERSION to $SOURCEBOT_VERSION\e[0m" if [ -z "$SOURCEBOT_TELEMETRY_DISABLED" ]; then - curl -L -s --header "Content-Type: application/json" -d '{ + if ! ( curl -L --output /dev/null --silent --fail --header "Content-Type: application/json" -d '{ "api_key": "'"$POSTHOG_PAPIK"'", "event": "upgrade", "distinct_id": "'"$SOURCEBOT_INSTALL_ID"'", @@ -96,7 +98,9 @@ else "from_version": "'"$PREVIOUS_VERSION"'", "to_version": "'"$SOURCEBOT_VERSION"'" } - }' https://us.i.posthog.com/capture/ > /dev/null + }' https://us.i.posthog.com/capture/ ) then + echo -e "\e[33m[Warning] Failed to send upgrade event.\e[0m" + fi fi fi fi @@ -117,6 +121,11 @@ echo "{\"version\": \"$SOURCEBOT_VERSION\", \"install_id\": \"$SOURCEBOT_INSTALL export NEXT_PUBLIC_SOURCEBOT_VERSION="$SOURCEBOT_VERSION" fi + # Infer NEXT_PUBLIC_PUBLIC_SEARCH_DEMO if it is not set + if [ -z "$NEXT_PUBLIC_PUBLIC_SEARCH_DEMO" ] && [ ! -z "$PUBLIC_SEARCH_DEMO" ]; then + export NEXT_PUBLIC_PUBLIC_SEARCH_DEMO="$PUBLIC_SEARCH_DEMO" + fi + # Always infer NEXT_PUBLIC_POSTHOG_PAPIK export NEXT_PUBLIC_POSTHOG_PAPIK="$POSTHOG_PAPIK" @@ -139,6 +148,7 @@ echo "{\"version\": \"$SOURCEBOT_VERSION\", \"install_id\": \"$SOURCEBOT_INSTALL sed -i "s|BAKED_NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY|${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}|g" "$file" sed -i "s|BAKED_NEXT_PUBLIC_SENTRY_ENVIRONMENT|${NEXT_PUBLIC_SENTRY_ENVIRONMENT}|g" "$file" sed -i "s|BAKED_NEXT_PUBLIC_SENTRY_WEBAPP_DSN|${NEXT_PUBLIC_SENTRY_WEBAPP_DSN}|g" "$file" + sed -i "s|BAKED_NEXT_PUBLIC_PUBLIC_SEARCH_DEMO|${NEXT_PUBLIC_PUBLIC_SEARCH_DEMO}|g" "$file" done } diff --git a/packages/backend/package.json b/packages/backend/package.json index f5866d9a..bf6b130d 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -18,7 +18,7 @@ "tsc-watch": "^6.2.0", "tsx": "^4.19.1", "typescript": "^5.6.2", - "vitest": "^2.1.4" + "vitest": "^2.1.9" }, "dependencies": { "@gitbeaker/rest": "^40.5.1", diff --git a/packages/backend/src/constants.ts b/packages/backend/src/constants.ts index 05c67dce..3b719122 100644 --- a/packages/backend/src/constants.ts +++ b/packages/backend/src/constants.ts @@ -12,5 +12,6 @@ export const DEFAULT_SETTINGS: Settings = { configSyncConcurrencyMultiple: 3, gcConcurrencyMultiple: 1, gcGracePeriodMs: 10 * 1000, // 10 seconds - repoIndexTimeoutMs: 1000 * 60 * 60 * 2 // 2 hours + repoIndexTimeoutMs: 1000 * 60 * 60 * 2, // 2 hours + maxTrigramCount: 20000, } \ No newline at end of file diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 0f4dcced..2c16515d 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -16,9 +16,13 @@ export type AppContext = { export type Settings = { /** - * The maximum size of a file (in bytes) to be indexed. Files that exceed this maximum will not be inexed. + * The maximum size of a file (in bytes) to be indexed. Files that exceed this maximum will not be indexed. */ maxFileSize: number; + /** + * The maximum number of trigrams per document. Files that exceed this maximum will not be indexed. + */ + maxTrigramCount: number; /** * The interval (in milliseconds) at which the indexer should re-index all repositories. */ diff --git a/packages/backend/src/zoekt.ts b/packages/backend/src/zoekt.ts index a3606418..974fb1b3 100644 --- a/packages/backend/src/zoekt.ts +++ b/packages/backend/src/zoekt.ts @@ -58,7 +58,7 @@ export const indexGitRepository = async (repo: Repo, ctx: AppContext) => { revisions = revisions.slice(0, 64); } - const command = `zoekt-git-index -allow_missing_branches -index ${ctx.indexPath} -file_limit ${DEFAULT_SETTINGS.maxFileSize} -branches ${revisions.join(',')} -tenant_id ${repo.orgId} -shard_prefix ${shardPrefix} ${repoPath}`; + const command = `zoekt-git-index -allow_missing_branches -index ${ctx.indexPath} -max_trigram_count ${DEFAULT_SETTINGS.maxTrigramCount} -file_limit ${DEFAULT_SETTINGS.maxFileSize} -branches ${revisions.join(',')} -tenant_id ${repo.orgId} -shard_prefix ${shardPrefix} ${repoPath}`; return new Promise<{ stdout: string, stderr: string }>((resolve, reject) => { exec(command, (error, stdout, stderr) => { diff --git a/packages/schemas/src/v2/index.schema.ts b/packages/schemas/src/v2/index.schema.ts index 88d220f5..1773e440 100644 --- a/packages/schemas/src/v2/index.schema.ts +++ b/packages/schemas/src/v2/index.schema.ts @@ -595,6 +595,17 @@ const schema = { "default": 2097152, "minimum": 1 }, + "maxTrigramCount": { + "type": "integer", + "description": "The maximum amount of trigrams per document. Documents that exceed this maximum will not be indexed. Defaults to 20000", + "default": 20000, + "minimum": 1 + }, + "autoDeleteStaleRepos": { + "type": "boolean", + "description": "Automatically delete stale repositories from the index. Defaults to true.", + "default": true + }, "reindexInterval": { "type": "integer", "description": "The interval (in milliseconds) at which the indexer should re-index all repositories. Repositories are always indexed when first added. Defaults to 1 hour (3600000 milliseconds).", diff --git a/packages/schemas/src/v2/index.type.ts b/packages/schemas/src/v2/index.type.ts index e5b5ddf6..98ed997c 100644 --- a/packages/schemas/src/v2/index.type.ts +++ b/packages/schemas/src/v2/index.type.ts @@ -40,6 +40,14 @@ export interface Settings { * The maximum size of a file (in bytes) to be indexed. Files that exceed this maximum will not be inexed. Defaults to 2MB (2097152 bytes). */ maxFileSize?: number; + /** + * The maximum amount of trigrams per document. Documents that exceed this maximum will not be indexed. Defaults to 20000 + */ + maxTrigramCount?: number; + /** + * Automatically delete stale repositories from the index. Defaults to true. + */ + autoDeleteStaleRepos?: boolean; /** * The interval (in milliseconds) at which the indexer should re-index all repositories. Repositories are always indexed when first added. Defaults to 1 hour (3600000 milliseconds). */ diff --git a/packages/web/src/app/[domain]/components/editorContextMenu.tsx b/packages/web/src/app/[domain]/components/editorContextMenu.tsx index 513abf31..d567198c 100644 --- a/packages/web/src/app/[domain]/components/editorContextMenu.tsx +++ b/packages/web/src/app/[domain]/components/editorContextMenu.tsx @@ -115,7 +115,7 @@ export const EditorContextMenu = ({ description: "✅ Copied link to selection", }); - captureEvent('share_link_created', {}); + captureEvent('wa_share_link_created', {}); // Reset the selection view.dispatch( diff --git a/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx b/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx index 4f179808..d6235ba5 100644 --- a/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx +++ b/packages/web/src/app/[domain]/components/searchBar/searchBar.tsx @@ -43,6 +43,7 @@ import { Separator } from "@/components/ui/separator"; import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"; import { Toggle } from "@/components/ui/toggle"; import { useDomain } from "@/hooks/useDomain"; +import { KeyboardShortcutHint } from "../keyboardShortcutHint"; interface SearchBarProps { className?: string; @@ -266,6 +267,7 @@ export const SearchBar = ({ indentWithTab={false} autoFocus={autoFocus ?? false} /> + ) => { const [highlightedSuggestionIndex, setHighlightedSuggestionIndex] = useState(0); + const { onOpenChanged } = useSyntaxGuide(); const { suggestions, isHighlightEnabled, descriptionPlacement, DefaultIcon, onSuggestionClicked } = useMemo(() => { if (!isEnabled) { @@ -391,7 +393,10 @@ const SearchSuggestionsBox = forwardRef(({ className="my-2" />
-
+
onOpenChanged(true)} + >

Syntax help:

diff --git a/packages/web/src/app/[domain]/components/syntaxGuideProvider.tsx b/packages/web/src/app/[domain]/components/syntaxGuideProvider.tsx new file mode 100644 index 00000000..cd0c2c8b --- /dev/null +++ b/packages/web/src/app/[domain]/components/syntaxGuideProvider.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { createContext, useContext, useCallback, useState } from 'react'; + +interface SyntaxGuideContextType { + isOpen: boolean; + onOpenChanged: (isOpen: boolean) => void; +} + +const SyntaxGuideContext = createContext(null); + +export const useSyntaxGuide = () => { + const context = useContext(SyntaxGuideContext); + if (!context) { + throw new Error('useSyntaxGuide must be used within a SyntaxGuideProvider'); + } + return context; +}; + +export const SyntaxGuideProvider = ({ children }: { children: React.ReactNode }) => { + const [isOpen, setIsOpen] = useState(false); + + const onOpenChanged = useCallback((isOpen: boolean) => { + setIsOpen(isOpen); + }, []); + + return ( + + {children} + + ); +}; \ No newline at end of file diff --git a/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx b/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx index d2225799..bde0a67f 100644 --- a/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx +++ b/packages/web/src/app/[domain]/components/syntaxReferenceGuide.tsx @@ -12,30 +12,31 @@ import { } from "@/components/ui/table"; import clsx from "clsx"; import Link from "next/link"; -import { useCallback, useRef, useState } from "react"; +import { useCallback, useRef } from "react"; import { useHotkeys } from "react-hotkeys-hook"; +import { useSyntaxGuide } from "./syntaxGuideProvider"; const LINGUIST_LINK = "https://github.com/github-linguist/linguist/blob/main/lib/linguist/languages.yml"; const CTAGS_LINK = "https://ctags.io/"; export const SyntaxReferenceGuide = () => { - const [isOpen, setIsOpen] = useState(false); + const { isOpen, onOpenChanged } = useSyntaxGuide(); const previousFocusedElement = useRef(null); const openDialog = useCallback(() => { previousFocusedElement.current = document.activeElement as HTMLElement; - setIsOpen(true); - }, []); + onOpenChanged(true); + }, [onOpenChanged]); const closeDialog = useCallback(() => { - setIsOpen(false); + onOpenChanged(false); // @note: Without requestAnimationFrame, focus was not being returned // to codemirror elements for some reason. requestAnimationFrame(() => { previousFocusedElement.current?.focus(); }); - }, []); + }, [onOpenChanged]); const handleOpenChange = useCallback((isOpen: boolean) => { if (isOpen) { diff --git a/packages/web/src/app/[domain]/components/syntaxReferenceGuideHint.tsx b/packages/web/src/app/[domain]/components/syntaxReferenceGuideHint.tsx new file mode 100644 index 00000000..fab0264a --- /dev/null +++ b/packages/web/src/app/[domain]/components/syntaxReferenceGuideHint.tsx @@ -0,0 +1,17 @@ +'use client'; + +import { useSyntaxGuide } from "./syntaxGuideProvider"; +import { KeyboardShortcutHint } from "../../components/keyboardShortcutHint"; + +export const SyntaxReferenceGuideHint = () => { + const { isOpen, onOpenChanged } = useSyntaxGuide(); + + return ( +
onOpenChanged(!isOpen)} + > + Reference guide: +
+ ) +} \ No newline at end of file diff --git a/packages/web/src/app/[domain]/components/upgradeToast.tsx b/packages/web/src/app/[domain]/components/upgradeToast.tsx index 73342266..e3b8bf29 100644 --- a/packages/web/src/app/[domain]/components/upgradeToast.tsx +++ b/packages/web/src/app/[domain]/components/upgradeToast.tsx @@ -2,9 +2,10 @@ import { useToast } from "@/components/hooks/use-toast"; import { ToastAction } from "@/components/ui/toast"; -import { NEXT_PUBLIC_SOURCEBOT_VERSION } from "@/lib/environment.client"; import { useEffect } from "react"; import { useLocalStorage } from "usehooks-ts"; +import { getVersion } from "@/app/api/(client)/client"; +import { useQuery } from "@tanstack/react-query"; const GITHUB_TAGS_URL = "https://api.github.com/repos/sourcebot-dev/sourcebot/tags"; const SEMVER_REGEX = /^v(\d+)\.(\d+)\.(\d+)$/; @@ -23,8 +24,18 @@ export const UpgradeToast = () => { new Date(0).toUTCString() ); + const { data: versionString } = useQuery({ + queryKey: ["version"], + queryFn: () => getVersion(), + select: (data) => data.version, + }) + useEffect(() => { - const currentVersion = getVersionFromString(NEXT_PUBLIC_SOURCEBOT_VERSION); + if (!versionString) { + return; + } + + const currentVersion = getVersionFromString(versionString); if (!currentVersion) { return; } @@ -71,7 +82,7 @@ export const UpgradeToast = () => { setUpgradeToastLastShownDate(new Date().toUTCString()); }); - }, [setUpgradeToastLastShownDate, toast, upgradeToastLastShownDate]); + }, [setUpgradeToastLastShownDate, toast, upgradeToastLastShownDate, versionString]); return null; } diff --git a/packages/web/src/app/[domain]/layout.tsx b/packages/web/src/app/[domain]/layout.tsx index 7aefbbc9..e04a0dd7 100644 --- a/packages/web/src/app/[domain]/layout.tsx +++ b/packages/web/src/app/[domain]/layout.tsx @@ -11,6 +11,7 @@ import { getSelectorsByUserAgent } from "react-device-detect"; import { MobileUnsupportedSplashScreen } from "./components/mobileUnsupportedSplashScreen"; import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME } from "@/lib/constants"; import { SyntaxReferenceGuide } from "./components/syntaxReferenceGuide"; +import { SyntaxGuideProvider } from "./components/syntaxGuideProvider"; interface LayoutProps { children: React.ReactNode, @@ -81,9 +82,9 @@ export default async function Layout({ ) } return ( - <> + {children} - + ) } \ No newline at end of file diff --git a/packages/web/src/app/[domain]/page.tsx b/packages/web/src/app/[domain]/page.tsx index 02a37787..3d380d4b 100644 --- a/packages/web/src/app/[domain]/page.tsx +++ b/packages/web/src/app/[domain]/page.tsx @@ -8,7 +8,7 @@ import { PageNotFound } from "./components/pageNotFound"; import { Footer } from "@/app/components/footer"; import { SourcebotLogo } from "../components/sourcebotLogo"; import { RepositorySnapshot } from "./components/repositorySnapshot"; -import { KeyboardShortcutHint } from "./components/keyboardShortcutHint"; +import { SyntaxReferenceGuideHint } from "./components/syntaxReferenceGuideHint"; export default async function Home({ params: { domain } }: { params: { domain: string } }) { const org = await getOrgFromDomain(domain); @@ -88,9 +88,7 @@ export default async function Home({ params: { domain } }: { params: { domain: s
-
- Reference guide: -
+