Skip to content

Commit 54b264c

Browse files
committed
feat: azure deployment, added SEO, new file modal, and Coming Soon deploy badge
1 parent 2c40ce7 commit 54b264c

25 files changed

+5948
-97
lines changed

.dockerignore

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Git
2+
.git
3+
.gitignore
4+
.gitmodules
5+
6+
# Python
7+
**/.venv
8+
**/__pycache__
9+
**/*.pyc
10+
**/*.pyo
11+
**/*.pyd
12+
**/.Python
13+
**/build
14+
**/dist
15+
**/*.egg-info
16+
**/.eggs
17+
18+
# IDE
19+
.vscode
20+
.idea
21+
*.swp
22+
*.swo
23+
24+
# Node
25+
**/node_modules/
26+
**/npm-debug.log
27+
**/yarn-error.log
28+
29+
# OS
30+
.DS_Store
31+
Thumbs.db
32+
33+
# Tests
34+
**/tests
35+
**/.pytest_cache
36+
**/.coverage
37+
38+
# Documentation
39+
docs
40+
*.md
41+
!README.md
42+
43+
# Lock files (we install fresh)
44+
**/uv.lock
45+
**/poetry.lock
46+
47+
# Editor
48+
*.sublime-*
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
name: Deploy Web-IDE to Azure
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'web-ide/**'
9+
- 'playground/deps/**'
10+
- 'aj-lang/**'
11+
- 'examples/**'
12+
- 'sdk/**'
13+
- 'ajanta-build-tool/**'
14+
- '.github/workflows/deploy-web-ide.yml'
15+
workflow_dispatch:
16+
17+
env:
18+
AZURE_RESOURCE_GROUP: ajanta-web-ide-rg
19+
ACR_NAME: ajantawebideacr
20+
BACKEND_APP_NAME: ajanta-backend
21+
FRONTEND_APP_NAME: ajanta-frontend
22+
23+
jobs:
24+
build-and-deploy:
25+
runs-on: ubuntu-latest
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
31+
- name: Azure Login
32+
uses: azure/login@v2
33+
with:
34+
creds: ${{ secrets.AZURE_CREDENTIALS }}
35+
36+
- name: Get ACR credentials
37+
id: acr
38+
run: |
39+
ACR_LOGIN_SERVER=$(az acr show --name ${{ env.ACR_NAME }} --query loginServer --output tsv)
40+
ACR_USERNAME=$(az acr credential show --name ${{ env.ACR_NAME }} --query username --output tsv)
41+
ACR_PASSWORD=$(az acr credential show --name ${{ env.ACR_NAME }} --query "passwords[0].value" --output tsv)
42+
echo "login_server=$ACR_LOGIN_SERVER" >> $GITHUB_OUTPUT
43+
echo "username=$ACR_USERNAME" >> $GITHUB_OUTPUT
44+
echo "password=$ACR_PASSWORD" >> $GITHUB_OUTPUT
45+
46+
- name: Login to ACR
47+
uses: docker/login-action@v3
48+
with:
49+
registry: ${{ steps.acr.outputs.login_server }}
50+
username: ${{ steps.acr.outputs.username }}
51+
password: ${{ steps.acr.outputs.password }}
52+
53+
- name: Get Backend URL
54+
id: backend-url
55+
run: |
56+
BACKEND_URL=$(az containerapp show \
57+
--name ${{ env.BACKEND_APP_NAME }} \
58+
--resource-group ${{ env.AZURE_RESOURCE_GROUP }} \
59+
--query "properties.configuration.ingress.fqdn" \
60+
--output tsv)
61+
echo "url=https://$BACKEND_URL" >> $GITHUB_OUTPUT
62+
63+
- name: Build and push Backend
64+
uses: docker/build-push-action@v5
65+
with:
66+
context: .
67+
file: ./web-ide/backend/Dockerfile
68+
push: true
69+
tags: ${{ steps.acr.outputs.login_server }}/${{ env.BACKEND_APP_NAME }}:${{ github.sha }},${{ steps.acr.outputs.login_server }}/${{ env.BACKEND_APP_NAME }}:latest
70+
71+
- name: Build and push Frontend
72+
uses: docker/build-push-action@v5
73+
with:
74+
context: ./web-ide/frontend-next
75+
file: ./web-ide/frontend-next/Dockerfile
76+
push: true
77+
tags: ${{ steps.acr.outputs.login_server }}/${{ env.FRONTEND_APP_NAME }}:${{ github.sha }},${{ steps.acr.outputs.login_server }}/${{ env.FRONTEND_APP_NAME }}:latest
78+
build-args: |
79+
NEXT_PUBLIC_API_URL=${{ steps.backend-url.outputs.url }}
80+
81+
- name: Update Backend Container App
82+
run: |
83+
az containerapp update \
84+
--name ${{ env.BACKEND_APP_NAME }} \
85+
--resource-group ${{ env.AZURE_RESOURCE_GROUP }} \
86+
--image ${{ steps.acr.outputs.login_server }}/${{ env.BACKEND_APP_NAME }}:${{ github.sha }}
87+
88+
- name: Update Frontend Container App
89+
run: |
90+
az containerapp update \
91+
--name ${{ env.FRONTEND_APP_NAME }} \
92+
--resource-group ${{ env.AZURE_RESOURCE_GROUP }} \
93+
--image ${{ steps.acr.outputs.login_server }}/${{ env.FRONTEND_APP_NAME }}:${{ github.sha }}
94+
95+
- name: Get Frontend URL
96+
id: frontend-url
97+
run: |
98+
FRONTEND_URL=$(az containerapp show \
99+
--name ${{ env.FRONTEND_APP_NAME }} \
100+
--resource-group ${{ env.AZURE_RESOURCE_GROUP }} \
101+
--query "properties.configuration.ingress.fqdn" \
102+
--output tsv)
103+
echo "url=https://$FRONTEND_URL" >> $GITHUB_OUTPUT
104+
105+
- name: Test Frontend Accessibility
106+
run: |
107+
echo "Testing frontend accessibility..."
108+
sleep 30 # Wait for deployment to stabilize
109+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" ${{ steps.frontend-url.outputs.url }} || echo "000")
110+
echo "HTTP Status Code: $HTTP_CODE"
111+
if [ "$HTTP_CODE" = "200" ]; then
112+
echo "✅ Frontend is accessible!"
113+
else
114+
echo "⚠️ Frontend returned status $HTTP_CODE"
115+
fi
116+
117+
- name: Deployment Summary
118+
run: |
119+
echo "## 🎉 Deployment Complete!" >> $GITHUB_STEP_SUMMARY
120+
echo "" >> $GITHUB_STEP_SUMMARY
121+
echo "| Service | URL |" >> $GITHUB_STEP_SUMMARY
122+
echo "|---------|-----|" >> $GITHUB_STEP_SUMMARY
123+
echo "| Frontend | ${{ steps.frontend-url.outputs.url }} |" >> $GITHUB_STEP_SUMMARY
124+
echo "| Backend | ${{ steps.backend-url.outputs.url }} |" >> $GITHUB_STEP_SUMMARY

web-ide/backend/Dockerfile

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
FROM python:3.12-slim
2+
3+
WORKDIR /app
4+
5+
# Install system dependencies including build tools for Cython, Rust, and C/C++ (clang)
6+
RUN apt-get update && apt-get install -y --no-install-recommends \
7+
build-essential \
8+
curl \
9+
gcc \
10+
g++ \
11+
clang \
12+
llvm \
13+
lld \
14+
xz-utils \
15+
python3-dev \
16+
&& rm -rf /var/lib/apt/lists/*
17+
18+
# Install RISC-V cross-compiler toolchain (required by ajanta-build-tool)
19+
# Using riscv-collab/riscv-gnu-toolchain nightly releases
20+
RUN curl -L https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.11.27/riscv64-elf-ubuntu-22.04-gcc.tar.xz -o /tmp/riscv.tar.xz \
21+
&& mkdir -p /opt/riscv \
22+
&& tar -xJf /tmp/riscv.tar.xz -C /opt/riscv --strip-components=1 \
23+
&& rm /tmp/riscv.tar.xz \
24+
&& ln -s /opt/riscv/bin/riscv64-unknown-elf-gcc /opt/riscv/bin/riscv64-elf-gcc \
25+
&& ln -s /opt/riscv/bin/riscv64-unknown-elf-g++ /opt/riscv/bin/riscv64-elf-g++ \
26+
&& ln -s /opt/riscv/bin/riscv64-unknown-elf-ld /opt/riscv/bin/riscv64-elf-ld \
27+
&& ln -s /opt/riscv/bin/riscv64-unknown-elf-as /opt/riscv/bin/riscv64-elf-as
28+
29+
ENV PATH="/opt/riscv/bin:${PATH}"
30+
31+
# Install Rust
32+
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
33+
ENV PATH="/root/.cargo/bin:${PATH}"
34+
35+
# Install cython and build dependencies
36+
RUN pip install cython setuptools wheel mypy
37+
38+
# Copy and build ajanta-build-tool
39+
COPY ajanta-build-tool /app/ajanta-build-tool
40+
WORKDIR /app/ajanta-build-tool
41+
RUN cargo build --release
42+
RUN cp target/release/ajanta-build-tool /usr/local/bin/
43+
44+
# Copy the entire project structure needed by backend
45+
WORKDIR /app
46+
# Copy SDK for C/C++ headers (ajanta-build-tool expects sdk/src at CARGO_MANIFEST_DIR/../sdk)
47+
COPY sdk /app/sdk
48+
COPY playground/deps/tsrkit-types /app/playground/deps/tsrkit-types
49+
COPY playground/deps/tsrkit-pvm /app/playground/deps/tsrkit-pvm
50+
COPY playground/deps/tsrkit-asm /app/playground/deps/tsrkit-asm
51+
COPY playground/playground /app/playground/playground
52+
COPY aj-lang /app/aj-lang
53+
COPY examples /app/examples
54+
55+
# Copy backend code
56+
COPY web-ide/backend /app/web-ide/backend
57+
58+
# Install tsrkit-types first (it's a dependency)
59+
WORKDIR /app/playground/deps/tsrkit-types
60+
RUN pip install .
61+
62+
# Build tsrkit-pvm with Cython extensions explicitly
63+
WORKDIR /app/playground/deps/tsrkit-pvm
64+
ENV PVM_BUILD_MODE=cython
65+
RUN python setup.py build_ext --inplace && pip install .
66+
67+
# Install tsrkit-asm
68+
WORKDIR /app/playground/deps/tsrkit-asm
69+
RUN pip install .
70+
71+
# Install aj-lang (Python JAM compiler) and create 'ajanta' symlink
72+
WORKDIR /app/aj-lang
73+
RUN pip install . && ln -s $(which aj) /usr/local/bin/ajanta
74+
75+
# Set working directory to backend
76+
WORKDIR /app/web-ide/backend
77+
78+
# Install backend dependencies directly (no venv)
79+
RUN pip install fastapi uvicorn python-multipart websockets bitarray safe-pysha3
80+
81+
# Set PYTHONPATH
82+
ENV PYTHONPATH="/app:/app/aj-lang:/app/playground/deps/tsrkit-pvm"
83+
84+
EXPOSE 8000
85+
86+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

web-ide/backend/main.py

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,52 @@ async def compile_service(request: CompileRequest):
8585
env["PATH"] = f"{cargo_bin}:{env.get('PATH', '')}"
8686

8787
if request.language == "python":
88-
cmd = ["ajanta", "build", source_path, "-o", output_path]
88+
# Python workflow: transpile to C first, then compile to PVM
89+
c_output_path = source_path.replace(".py", ".c")
90+
cmd = ["ajanta", "build", source_path, "-o", c_output_path]
91+
92+
# Step 1: Transpile Python to C
93+
try:
94+
result = subprocess.run(
95+
cmd,
96+
cwd=project_root,
97+
env=env,
98+
capture_output=True,
99+
text=True,
100+
check=False
101+
)
102+
103+
if result.returncode != 0:
104+
return {"success": False, "logs": result.stdout + "\n" + result.stderr}
105+
106+
# Find the generated C file - ajanta puts it in build/ or same dir
107+
if not os.path.exists(c_output_path):
108+
# Check for C file with same name
109+
possible_c_file = os.path.join(os.path.dirname(source_path), "service.c")
110+
if os.path.exists(possible_c_file):
111+
c_output_path = possible_c_file
112+
else:
113+
# Parse output for actual C file path
114+
for line in (result.stdout + result.stderr).split('\n'):
115+
if 'Generated C code:' in line:
116+
c_output_path = line.split('Generated C code:')[1].strip()
117+
break
118+
119+
if not os.path.exists(c_output_path):
120+
return {"success": False, "logs": f"Transpilation succeeded but C file not found.\n{result.stdout}"}
121+
122+
transpile_logs = result.stdout
123+
124+
except Exception as e:
125+
return {"success": False, "logs": f"Transpilation error: {str(e)}"}
126+
127+
# Step 2: Compile C to PVM using ajanta-build-tool
128+
cmd = ["ajanta-build-tool", "build", c_output_path, "-o", output_path]
129+
89130
else:
90131
# C or C++
91-
# Ensure ajanta-build-tool is in path or use absolute path if we knew it
92-
# Assuming it's in PATH
93132
cmd = ["ajanta-build-tool", "build", source_path, "-o", output_path]
133+
transpile_logs = ""
94134

95135
# Run build
96136
try:
@@ -103,8 +143,10 @@ async def compile_service(request: CompileRequest):
103143
check=False
104144
)
105145

146+
all_logs = (transpile_logs + "\n" if request.language == "python" else "") + result.stdout + "\n" + result.stderr
147+
106148
if result.returncode != 0:
107-
return {"success": False, "logs": result.stdout + "\n" + result.stderr}
149+
return {"success": False, "logs": all_logs}
108150

109151
# Read PVM
110152
if os.path.exists(output_path):
@@ -113,11 +155,11 @@ async def compile_service(request: CompileRequest):
113155

114156
return {
115157
"success": True,
116-
"logs": result.stdout,
158+
"logs": all_logs,
117159
"pvm": pvm_bytes.hex()
118160
}
119161
else:
120-
return {"success": False, "logs": "Build succeeded but output file not found.\n" + result.stdout}
162+
return {"success": False, "logs": "Build succeeded but output file not found.\n" + all_logs}
121163

122164
except Exception as e:
123165
return {"success": False, "logs": str(e)}

0 commit comments

Comments
 (0)