Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
run: |
sudo apt-get install --no-install-recommends --assume-yes shellcheck parallel
python -m pip install --upgrade pip
pip install poetry
pip install poetry==2.4.1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we skip the python part since we don't have problems with and we are closer to a stable release ? I would limit the scope of this PR to just deal with the frontend.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can, but if we need to apply a backport in the future, there's no guarantee we won't introduce a bug.

I made sure we are pinning to the same dependency versions that are being used in the build today.

I'm far more comfortable pinning what we can before release.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update: reran the dependency diff, got one drift, fixed now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scope of this PR is quite big for a stable release.
It mixes lock of frontend and big changes in backend project management.

  • Move projects to uv
  • Move projects from setup.py to pyproject.
  • Move projects to venv
  • Remove yarn.lock ?? For what reason, even in master we have yarn.

Python projects are already dependency lock, if there is a place that we are not, we can just add such version.

@joaoantoniocardoso joaoantoniocardoso Aug 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-split of those concerns into separate PRs is intentional. I want to address all before the stable release.

The diff can look scary, but almost all of it is just the lock files themselves, so it's not difficult to review carefully.

Python projects are already dependency lock, if there is a place that we are not, we can just add such version.

This is exactly what we are doing here: the Python dependencies are not pinned in practice (we "lock" packaging==20.4, but the image is shipping 26.2), and we have broken dependencies already, and nothing guarantees we won't have more while I'm writing this message:

image

(Yes, we don't use flask directly, it's brought transitively via connexion, but the point is: it is there and silently broken today. Which will be the next one?)

The practical effect on the built image is tight and we must work to make it under control, so we should spend effort in improving this rather than ignoring the problem.

You can run agents to inspect the differences before/after; we can adjust any detail if needed, but the dependency-locking before the release is a must alongside the anti-corruption measure.

Docker dive:

dive-1.4-dev.json

dive-branch.json

pip freezes:

pip-1.4-dev.txt
pip-branch.txt

thanks


- name: Run tests
run: |
Expand All @@ -54,10 +54,10 @@ jobs:

- uses: oven-sh/setup-bun@v1
with:
bun-version: 1.0.3
bun-version: 1.3.14

- name: Bun install
run: bun install --cwd ./core/frontend
run: bun install --frozen-lockfile --cwd ./core/frontend

- name: Bun lint
run: bun --cwd ./core/frontend lint
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ node_modules
env/
Pipfile
Pipfile.lock
poetry.lock
registry/

# Docker compose binds
Expand Down
11 changes: 8 additions & 3 deletions .hooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ echo "installing mavlink-router"
echo "installing mavp2p"
./core/tools/mavp2p/bootstrap.sh
echo "installing ardupilot_tools"
NOSUDO=1 ./core/tools/ardupilot_tools/bootstrap.sh
NOSUDO=1 ./core/tools/ardupilot_tools/bootstrap.sh && ./core/tools/ardupilot_tools/setup-python-libs.sh

isort_extra_args="--check-only --diff"
black_extra_args="--check --diff"
Expand Down Expand Up @@ -99,9 +99,14 @@ echo "Running shellcheck..."
#SC2086: Allow word splitting
git ls-files '*.sh' | xargs -L 1 shellcheck --exclude=SC2005,SC2015,SC2046,SC2048,SC2086

# Roots of every python project, which isort and mypy check one by one. A project
# declares itself with either a setup.py or a pyproject.toml.
python_packages=$(git ls-files '*/setup.py' 'core/libs/*/pyproject.toml' 'core/services/*/pyproject.toml' \
| xargs -n 1 dirname | sort -u)

echo "Running isort.."
# Run isort for each python project
dirname $(git ls-files "$repository_path/*/setup.py") | xargs -I {} isort --src-path="{}" ${isort_extra_args} "{}"
echo "$python_packages" | xargs -I {} isort --src-path="{}" ${isort_extra_args} "{}"

# This will only get the python files track by git, not including submodules
python_files=$(git ls-files '*.py')
Expand All @@ -120,7 +125,7 @@ echo "Running pylint.."
pylint $python_files

echo "Running mypy.."
git ls-files '*setup.py' | parallel 'mypy $(dirname {}) --cache-dir "$(dirname {})/__mypycache__"'
echo "$python_packages" | parallel 'mypy {} --cache-dir "{}/__mypycache__"'

echo "Running pytest.."
pytest -n 10 --durations=0 --cov="$repository_path" --cov-report html
Expand Down
1 change: 1 addition & 0 deletions core/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11
48 changes: 40 additions & 8 deletions core/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
ARG BASE_IMAGE=bluerobotics/blueos-base:0.2.6

# Build frontend
FROM --platform=$BUILDPLATFORM oven/bun:1.0.3-slim AS frontend-builder
FROM --platform=$BUILDPLATFORM oven/bun:1.3.14-slim AS frontend-builder

ARG VITE_APP_GIT_DESCRIBE
ENV VITE_APP_GIT_DESCRIBE=${VITE_APP_GIT_DESCRIBE:-none/none-0-g00000000}
Expand All @@ -21,7 +21,7 @@ COPY frontend /home/pi/frontend
RUN <<-EOF
set -e

bun install --cwd /home/pi/frontend
bun install --frozen-lockfile --cwd /home/pi/frontend
NODE_OPTIONS=--max-old-space-size=8192 bun run --cwd /home/pi/frontend build

EOF
Expand All @@ -34,6 +34,39 @@ COPY tools /home/pi/tools
RUN apt update && apt install -y --no-install-recommends binutils
RUN /home/pi/tools/install-static-binaries.sh

# Generation of python virtual environment for our libraries and services
FROM base AS install-services-and-libs

RUN apt update && apt install -y --no-install-recommends g++

# Wifi service / Bind path for wpa
RUN mkdir -p /var/run/wpa_supplicant/

# Install UV, version pinned so the resolver that reads uv.lock never changes on its own
ADD https://astral.sh/uv/0.12.0/install.sh /uv-installer.sh
RUN sh /uv-installer.sh && rm /uv-installer.sh
ENV PATH="/root/.local/bin/:$PATH"

# Project files
COPY ./uv.lock /home/pi/uv.lock
COPY ./pyproject.toml /home/pi/pyproject.toml
COPY ./.python-version /home/pi/.python-version

COPY ./libs /home/pi/libs
COPY ./services /home/pi/services

COPY ./tools /home/pi/tools

# Virtual environment creation and packages installation
WORKDIR /home/pi
# --locked fails the build when uv.lock is out of sync with the pyprojects, so dependency
# changes have to be relocked and committed instead of silently resolved at build time
RUN uv venv && uv sync --locked

# Post install scripts
ENV VIRTUAL_ENV=/home/pi/.venv
RUN /home/pi/tools/install-python-libs.sh

# BlueOS base image
FROM base

Expand Down Expand Up @@ -70,17 +103,15 @@ ENV TARGETVARIANT=${TARGETVARIANT}
COPY tools /home/pi/tools
RUN /home/pi/tools/install-system-tools.sh

# Install custom libraries
# Copy libs and services code
COPY libs /home/pi/libs
RUN /home/pi/libs/install-libs.sh
COPY services /home/pi/services

# Set tmux configuration file
COPY configuration/tmux.conf /etc/tmux.conf
COPY configuration/motd /etc/motd

# Install services
COPY services /home/pi/services
RUN /home/pi/services/install-services.sh
# Copy configuration files
COPY start-blueos-core /usr/bin/start-blueos-core
COPY run-service.sh /usr/bin/run-service

Expand All @@ -99,6 +130,7 @@ COPY --from=download-binaries \

# Copy frontend built on frontend-builder to this stage
COPY --from=frontend-builder /home/pi/frontend/dist /home/pi/frontend
COPY --from=install-services-and-libs /home/pi/.venv /usr/blueos/venv

RUN <<-EOF
set -e
Expand All @@ -113,7 +145,7 @@ set -e
RCFILE_PATH="/etc/blueosrc"
echo "export GIT_DESCRIBE_TAGS=$GIT_DESCRIBE_TAGS" >> $RCFILE_PATH
echo "export HISTFILE=/etc/blueos/.bash_history" >> $RCFILE_PATH
echo "export PATH=$(python -m site --user-base)/bin:/usr/blueos/bin:$PATH" >> $RCFILE_PATH
echo "export PATH=/usr/blueos/venv/bin:/usr/blueos/bin:$PATH" >> $RCFILE_PATH
echo "export RUST_BACKTRACE=1" >> $RCFILE_PATH

# Setup shortcuts
Expand Down
1 change: 0 additions & 1 deletion core/frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ dist/
yarn.lock
dev-dist/
components.d.ts
bun.lockb
Binary file modified core/frontend/bun.lockb
Binary file not shown.
45 changes: 45 additions & 0 deletions core/frontend/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,51 @@ export default defineConfig(({ command, mode }) => {
deleteOriginFile: true,
filter: /\.(js|css|json|svg|txt|xml|wasm|glb)$/i,
}),
// Parse every shipped script, so a corrupt chunk fails the build instead of only breaking
// the route that imports it at runtime, like 1.4.4-beta.14 shipped a source map as a chunk.
// Runs after compression to check the exact bytes nginx serves.
{
name: 'validate-emitted-javascript',
apply: 'build',
enforce: 'post',
// closeBundle is a parallel hook, sequential makes it wait for the compression above
closeBundle: {
sequential: true,
handler() {
const fs = require('fs')
const { gunzipSync } = require('zlib')
const { transformSync } = require('esbuild')
const distPath = path.resolve(__dirname, 'dist')

const collectScripts = (dir) => fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const fullPath = path.join(dir, entry.name)
if (entry.isDirectory()) return collectScripts(fullPath)
return /\.js(\.gz)?$/.test(entry.name) ? [fullPath] : []
})

const scripts = collectScripts(distPath)
if (scripts.length === 0) {
throw new Error('No javascript emitted to dist/, the build produced nothing to validate')
}

const failures = scripts.flatMap((script) => {
try {
const bytes = fs.readFileSync(script)
transformSync((script.endsWith('.gz') ? gunzipSync(bytes) : bytes).toString('utf8'), { loader: 'js' })
return []
} catch (error) {
return [`${path.relative(distPath, script)}: ${error.errors?.[0]?.text ?? error.message}`]
}
})

if (failures.length > 0) {
throw new Error(`Corrupt javascript in dist/:\n ${failures.join('\n ')}`)
}

console.log(`validated ${scripts.length} emitted javascript files`)
}
}
},
// Fix Draco imports in dev server
{
name: 'draco-dev-fix',
Expand Down
Loading
Loading