Skip to content

Commit 272ceea

Browse files
committed
merge main
2 parents f74ae98 + 4cf557b commit 272ceea

File tree

9 files changed

+640
-28
lines changed

9 files changed

+640
-28
lines changed

.github/workflows/ghcr-publish.yml

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@ on:
99
# schedule:
1010
# - cron: '18 10 * * *'
1111
push:
12-
branches: [ "main" ]
12+
branches: ["main"]
1313
# Publish semver tags as releases.
14-
tags: [ 'v*.*.*' ]
14+
tags: ["v*.*.*"]
1515
pull_request:
16-
branches: [ "main" ]
16+
branches: ["main"]
1717

1818
env:
1919
# Use docker.io for Docker Hub if empty
20-
REGISTRY: ghcr.io
21-
IMAGE_NAME: ${{ github.repository }}
22-
20+
REGISTRY_IMAGE: ghcr.io/sourcebot
2321

2422
jobs:
2523
build:
@@ -32,53 +30,74 @@ jobs:
3230
id-token: write
3331
strategy:
3432
matrix:
35-
architecture: [amd64, arm64]
33+
platform:
34+
- linux/amd64
35+
- linux/arm64
3636

3737
steps:
38+
- name: Prepare
39+
run: |
40+
platform=${{ matrix.platform }}
41+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
42+
3843
- name: Checkout repository
3944
uses: actions/checkout@v4
4045
with:
41-
submodules: 'true'
42-
46+
submodules: "true"
47+
4348
# Extract metadata (tags, labels) for Docker
4449
# https://github.com/docker/metadata-action
4550
- name: Extract Docker metadata
4651
id: meta
4752
uses: docker/metadata-action@v5
4853
with:
49-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
54+
images: ${{ env.REGISTRY_IMAGE }}
5055

5156
# Install the cosign tool except on PR
5257
# https://github.com/sigstore/cosign-installer
5358
- name: Install cosign
5459
if: github.event_name != 'pull_request'
5560
uses: sigstore/[email protected]
5661
with:
57-
cosign-release: 'v2.2.4'
62+
cosign-release: "v2.2.4"
5863

5964
- name: Set up Docker Buildx
60-
uses: docker/setup-buildx-action@v1
61-
65+
uses: docker/setup-buildx-action@v3
66+
6267
- name: Login to GitHub Packages Docker Registry
6368
uses: docker/login-action@v1
6469
if: github.event_name != 'pull_request'
6570
with:
66-
registry: ${{ env.REGISTRY }}
71+
registry: ghcr.io
6772
username: ${{ github.actor }}
6873
password: ${{ secrets.GITHUB_TOKEN }}
6974

7075
- name: Build and push Docker image
71-
id: build-and-push
72-
uses: docker/build-push-action@v5
76+
id: build
77+
uses: docker/build-push-action@v6
7378
with:
7479
context: .
75-
push: ${{ github.event_name != 'pull_request' }}
7680
tags: ${{ steps.meta.outputs.tags }}
7781
labels: ${{ steps.meta.outputs.labels }}
7882
cache-from: type=gha
7983
cache-to: type=gha,mode=max
80-
platforms: linux/${{ matrix.architecture }}
81-
84+
platforms: ${{ matrix.platform }}
85+
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
86+
87+
- name: Export digest
88+
run: |
89+
mkdir -p /tmp/digests
90+
digest="${{ steps.build.outputs.digest }}"
91+
touch "/tmp/digests/${digest#sha256:}"
92+
93+
- name: Upload digest
94+
uses: actions/upload-artifact@v4
95+
with:
96+
name: digests-${{ env.PLATFORM_PAIR }}
97+
path: /tmp/digests/*
98+
if-no-files-found: error
99+
retention-days: 1
100+
82101
# Sign the resulting Docker image digest except on PRs.
83102
# This will only write to the public Rekor transparency log when the Docker
84103
# repository is public to avoid leaking data. If you would like to publish
@@ -89,7 +108,46 @@ jobs:
89108
env:
90109
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
91110
TAGS: ${{ steps.meta.outputs.tags }}
92-
DIGEST: ${{ steps.build-and-push.outputs.digest }}
111+
DIGEST: ${{ steps.build.outputs.digest }}
93112
# This step uses the identity token to provision an ephemeral certificate
94113
# against the sigstore community Fulcio instance.
95-
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
114+
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
115+
116+
merge:
117+
runs-on: ubuntu-latest
118+
if: github.event_name != 'pull_request'
119+
needs:
120+
- build
121+
steps:
122+
- name: Download digests
123+
uses: actions/download-artifact@v4
124+
with:
125+
path: /tmp/digests
126+
pattern: digests-*
127+
merge-multiple: true
128+
129+
- name: Set up Docker Buildx
130+
uses: docker/setup-buildx-action@v3
131+
132+
- name: Extract Docker metadata
133+
id: meta
134+
uses: docker/metadata-action@v5
135+
with:
136+
images: ${{ env.REGISTRY_IMAGE }}
137+
138+
- name: Login to GitHub Packages Docker Registry
139+
uses: docker/login-action@v1
140+
with:
141+
registry: ghcr.io
142+
username: ${{ github.actor }}
143+
password: ${{ secrets.GITHUB_TOKEN }}
144+
145+
- name: Create manifest list and push
146+
working-directory: /tmp/digests
147+
run: |
148+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
149+
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
150+
151+
- name: Inspect image
152+
run: |
153+
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"private": true,
55
"scripts": {
66
"dev": "npm-run-all --print-label --parallel next:dev zoekt:webserver zoekt:indexserver",
7-
"zoekt:webserver": "export PATH=\"$(PWD)/bin:$PATH\" && zoekt-webserver -index .sourcebot/index -rpc",
8-
"zoekt:indexserver": "export PATH=\"$(PWD)/bin:$PATH\" && export CTAGS_COMMAND=ctags && zoekt-indexserver -data_dir .sourcebot -mirror_config config.json",
7+
"zoekt:webserver": "export PATH=\"$PWD/bin:$PATH\" && zoekt-webserver -index .sourcebot/index -rpc",
8+
"zoekt:indexserver": "export PATH=\"$PWD/bin:$PATH\" && export CTAGS_COMMAND=ctags && zoekt-indexserver -data_dir .sourcebot -mirror_config config.json",
99
"next:dev": "next dev",
1010
"build": "next build",
1111
"start": "next start",
@@ -34,6 +34,8 @@
3434
"class-variance-authority": "^0.7.0",
3535
"client-only": "^0.0.1",
3636
"clsx": "^2.1.1",
37+
"embla-carousel-auto-scroll": "^8.3.0",
38+
"embla-carousel-react": "^8.3.0",
3739
"escape-string-regexp": "^5.0.0",
3840
"http-status-codes": "^2.3.0",
3941
"lucide-react": "^0.435.0",

src/app/navigationMenu.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ export const NavigationMenu = () => {
3030
src={logoDark}
3131
className="h-11 w-auto hidden dark:block"
3232
alt={"Sourcebot logo"}
33+
priority={true}
3334
/>
3435
<Image
3536
src={logoLight}
3637
className="h-11 w-auto block dark:hidden"
3738
alt={"Sourcebot logo"}
39+
priority={true}
3840
/>
3941
</div>
4042

src/app/page.tsx

Lines changed: 152 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,183 @@
1+
import { listRepositories } from "@/lib/server/searchService";
2+
import { isServiceError } from "@/lib/utils";
13
import Image from "next/image";
4+
import { Suspense } from "react";
25
import logoDark from "../../public/sb_logo_dark_large.png";
36
import logoLight from "../../public/sb_logo_light_large.png";
47
import { NavigationMenu } from "./navigationMenu";
8+
import { RepositoryCarousel } from "./repositoryCarousel";
59
import { SearchBar } from "./searchBar";
10+
import { Separator } from "@/components/ui/separator";
611

7-
export default function Home() {
12+
13+
export default async function Home() {
814
return (
915
<div className="h-screen flex flex-col items-center">
1016
{/* TopBar */}
1117
<NavigationMenu />
12-
13-
<div className="flex flex-col justify-center items-center p-4 mt-48">
18+
19+
<div className="flex flex-col justify-center items-center mt-8 md:mt-32 max-w-[90%]">
1420
<div className="max-h-44 w-auto">
1521
<Image
1622
src={logoDark}
1723
className="w-full h-full hidden dark:block"
1824
alt={"Sourcebot logo"}
25+
priority={true}
1926
/>
2027
<Image
2128
src={logoLight}
2229
className="w-full h-full block dark:hidden"
2330
alt={"Sourcebot logo"}
31+
priority={true}
2432
/>
2533
</div>
2634
<div className="w-full flex flex-row mt-4">
2735
<SearchBar
2836
autoFocus={true}
2937
/>
3038
</div>
39+
<div className="mt-8">
40+
<Suspense fallback={<div>...</div>}>
41+
<RepositoryList />
42+
</Suspense>
43+
</div>
44+
<Separator className="mt-5 mb-8" />
45+
<div className="flex flex-col items-center w-fit gap-6">
46+
<span className="font-semibold">How to search</span>
47+
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
48+
<HowToSection
49+
title="Search in files or paths"
50+
>
51+
<QueryExample>
52+
<Query query="test todo">test todo</Query> <QueryExplanation>(both test and todo)</QueryExplanation>
53+
</QueryExample>
54+
<QueryExample>
55+
<Query query="test or todo">test <Highlight>or</Highlight> todo</Query> <QueryExplanation>(either test or todo)</QueryExplanation>
56+
</QueryExample>
57+
<QueryExample>
58+
<Query query={`"exit boot"`}>{`"exit boot"`}</Query> <QueryExplanation>(exact match)</QueryExplanation>
59+
</QueryExample>
60+
<QueryExample>
61+
<Query query="TODO case:yes">TODO <Highlight>case:</Highlight>yes</Query> <QueryExplanation>(case sensitive)</QueryExplanation>
62+
</QueryExample>
63+
</HowToSection>
64+
<HowToSection
65+
title="Filter results"
66+
>
67+
<QueryExample>
68+
<Query query="file:README setup"><Highlight>file:</Highlight>README setup</Query> <QueryExplanation>(by filename)</QueryExplanation>
69+
</QueryExample>
70+
<QueryExample>
71+
<Query query="repo:torvalds/linux test"><Highlight>repo:</Highlight>torvalds/linux test</Query> <QueryExplanation>(by repo)</QueryExplanation>
72+
</QueryExample>
73+
<QueryExample>
74+
<Query query="lang:typescript"><Highlight>lang:</Highlight>typescript</Query> <QueryExplanation>(by language)</QueryExplanation>
75+
</QueryExample>
76+
<QueryExample>
77+
<Query query="branch:HEAD"><Highlight>branch:</Highlight>HEAD</Query> <QueryExplanation>(by branch)</QueryExplanation>
78+
</QueryExample>
79+
</HowToSection>
80+
<HowToSection
81+
title="Advanced"
82+
>
83+
<QueryExample>
84+
<Query query="file:\.py$"><Highlight>file:</Highlight>{`\\.py$`}</Query> <QueryExplanation>{`(files that end in ".py")`}</QueryExplanation>
85+
</QueryExample>
86+
<QueryExample>
87+
<Query query="sym:main"><Highlight>sym:</Highlight>main</Query> <QueryExplanation>{`(symbols named "main")`}</QueryExplanation>
88+
</QueryExample>
89+
<QueryExample>
90+
<Query query="todo -lang:c">todo <Highlight>-lang:c</Highlight></Query> <QueryExplanation>(negate filter)</QueryExplanation>
91+
</QueryExample>
92+
<QueryExample>
93+
<Query query="content:README"><Highlight>content:</Highlight>README</Query> <QueryExplanation>(search content only)</QueryExplanation>
94+
</QueryExample>
95+
</HowToSection>
96+
</div>
97+
</div>
3198
</div>
3299
</div>
33100
)
34101
}
102+
103+
const RepositoryList = async () => {
104+
const _repos = await listRepositories();
105+
106+
if (isServiceError(_repos)) {
107+
return null;
108+
}
109+
110+
const repos = _repos.List.Repos.map((repo) => repo.Repository);
111+
112+
if (repos.length === 0) {
113+
return <span>
114+
Get started
115+
<a
116+
href="https://github.com/TaqlaAI/sourcebot/blob/main/README.md"
117+
className="text-blue-500"
118+
>
119+
{` configuring Sourcebot.`}
120+
</a>
121+
</span>;
122+
}
123+
124+
return (
125+
<div className="flex flex-col items-center gap-3">
126+
<span className="text-sm">
127+
{`Search ${repos.length} `}
128+
<a
129+
href="/repos"
130+
className="text-blue-500"
131+
>
132+
{repos.length > 1 ? 'repositories' : 'repository'}
133+
</a>
134+
</span>
135+
<RepositoryCarousel repos={repos} />
136+
</div>
137+
)
138+
}
139+
140+
const HowToSection = ({ title, children }: { title: string, children: React.ReactNode }) => {
141+
return (
142+
<div className="flex flex-col gap-1">
143+
<span className="dark:text-gray-300 text-sm mb-2 underline">{title}</span>
144+
{children}
145+
</div>
146+
)
147+
148+
}
149+
150+
const Highlight = ({ children }: { children: React.ReactNode }) => {
151+
return (
152+
<span className="text-blue-700 dark:text-blue-500">
153+
{children}
154+
</span>
155+
)
156+
}
157+
158+
const QueryExample = ({ children }: { children: React.ReactNode }) => {
159+
return (
160+
<span className="text-sm font-mono">
161+
{children}
162+
</span>
163+
)
164+
}
165+
166+
const QueryExplanation = ({ children }: { children: React.ReactNode }) => {
167+
return (
168+
<span className="text-gray-500 dark:text-gray-400 ml-3">
169+
{children}
170+
</span>
171+
)
172+
}
173+
174+
const Query = ({ query, children }: { query: string, children: React.ReactNode }) => {
175+
return (
176+
<a
177+
href={`/search?query=${query}`}
178+
className="cursor-pointer hover:underline"
179+
>
180+
{children}
181+
</a>
182+
)
183+
}

0 commit comments

Comments
 (0)