Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
78e3628
Initial plan
Copilot Dec 20, 2025
c8bd78d
Add Docker support for browser mode with build workflow
Copilot Dec 20, 2025
319bc4c
Fix cron comment and improve health check error handling
Copilot Dec 20, 2025
2b5cd99
Merge branch 'master' into copilot/create-docker-build-browser-solution
thomasnordquist Dec 20, 2025
67e345b
Merge branch 'master' into copilot/create-docker-build-browser-solution
thomasnordquist Dec 21, 2025
a7742fc
Rename image to mqtt-explorer, add ARM support (arm64/v7), upgrade to…
Copilot Dec 21, 2025
625d5ed
Fix image tag naming consistency in tests and docs
Copilot Dec 21, 2025
f822cdc
Optimize Docker image: 3-stage build with minimal runtime deps and la…
Copilot Dec 21, 2025
3d28977
Fix webpack config: enable minification and update @material-ui to @mui
Copilot Dec 21, 2025
785cc42
Simplify Dockerfile: use yarn --production instead of inline script
Copilot Dec 21, 2025
b2a40c8
Add browser test suite execution against Docker image
Copilot Dec 21, 2025
13beb04
Fix port conflict and add yarn cache for browser tests
Copilot Dec 21, 2025
4695488
Add image size reporting and lightweight frontend tests without test …
Copilot Dec 21, 2025
10ab0ca
Update .github/workflows/docker-browser.yml
thomasnordquist Dec 21, 2025
aeaf2a7
Fix workflow paths, attestation digest, remove events from dockerigno…
Copilot Dec 21, 2025
8fbbd7d
Remove unused Mosquitto service from Docker workflow
Copilot Dec 21, 2025
9439885
Restore Mosquitto service, rename ui-tests to electron-tests, add bro…
Copilot Dec 21, 2025
e7e3913
Make MQTT broker configurable via environment variables for tests
Copilot Dec 21, 2025
d91f948
Merge branch 'master' into copilot/create-docker-build-browser-solution
thomasnordquist Dec 22, 2025
d190b67
Merge branch 'master' into copilot/create-docker-build-browser-solution
thomasnordquist Dec 22, 2025
8ae915d
Add one-click deployment options with Play with Docker and cloud plat…
Copilot Dec 22, 2025
8944539
Add MQTT_EXPLORER_SKIP_AUTH environment variable for proxy authentica…
Copilot Dec 22, 2025
8beb173
Use Socket.IO auth-status event instead of HTTP endpoint, hide logout…
Copilot Dec 22, 2025
fa9d04a
Merge branch 'master' into copilot/create-docker-build-browser-solution
thomasnordquist Dec 22, 2025
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
64 changes: 64 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Git
.git
.gitignore
.github

# Dependencies
node_modules
app/node_modules
backend/node_modules

# Build artifacts
build
dist
app/dist

# Testing
coverage
.nyc_output
test-screenshot-*.png
ui-test.mp4
ui-test.gif

# Development
.vscode
.devcontainer
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# OS
.DS_Store
Thumbs.db

# IDE
*.swp
*.swo
*~
.idea

# Documentation
*.md
!Readme.md
LICENSE.md

# CI/CD files
.releaserc
appveyor.yml

# Misc
res
scripts
docker
icon.xcf
greenkeeper.json
prettier.config.js
.prettierignore
.eslintrc.json
.cspell.json
tslint.json
mcp.json

# Data directory (will be created in container)
data
219 changes: 219 additions & 0 deletions .github/workflows/docker-browser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
name: Docker Browser Build

on:
push:
branches:
- master
- release
- beta
paths:
- 'Dockerfile.browser'
- 'src/server.ts'
- 'src/AuthManager.ts'
- 'app/**'
- 'backend/**'
- 'package.json'
- 'yarn.lock'
- '.github/workflows/docker-browser.yml'

Copilot AI Dec 21, 2025

Copy link

Choose a reason for hiding this comment

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

The workflow paths do not include tsconfig.json and events/**, but both are copied in the Dockerfile and can affect the build output. Changes to TypeScript configuration or event definitions should trigger a Docker rebuild. Add these paths to ensure the Docker image is rebuilt when these critical files change.

Suggested change
- '.github/workflows/docker-browser.yml'
- '.github/workflows/docker-browser.yml'
- 'tsconfig.json'
- 'events/**'

Copilot uses AI. Check for mistakes.
- 'tsconfig.json'
- 'events/**'
schedule:
# Run every two weeks (1st and 15th of each month) at 2:00 AM UTC
- cron: '0 2 1,15 * *'
workflow_dispatch:

jobs:
build-and-test:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
Comment thread
thomasnordquist marked this conversation as resolved.
id-token: write

services:
# MQTT broker for testing
mosquitto:
image: eclipse-mosquitto:2
ports:
- 1883:1883
options: >-
--health-cmd "mosquitto_sub -t '$SYS/#' -C 1"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

Check warning on line 50 in .github/workflows/docker-browser.yml

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.github/workflows/docker-browser.yml#L50

An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3

Check warning on line 53 in .github/workflows/docker-browser.yml

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.github/workflows/docker-browser.yml#L53

An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5

Check warning on line 61 in .github/workflows/docker-browser.yml

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.github/workflows/docker-browser.yml#L61

An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}

- name: Build Docker image
uses: docker/build-push-action@v5

Check warning on line 70 in .github/workflows/docker-browser.yml

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

.github/workflows/docker-browser.yml#L70

An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.
with:
context: .
file: ./Dockerfile.browser
platforms: linux/amd64
push: false
load: true
tags: mqtt-explorer:test
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Test Docker image - Basic startup
run: |
# Start container with test credentials
docker run -d \
--name mqtt-explorer-test \
-p 3000:3000 \
-e MQTT_EXPLORER_USERNAME=test \
-e MQTT_EXPLORER_PASSWORD=test123 \
-e PORT=3000 \
mqtt-explorer:test

# Wait for server to be ready (max 60 seconds)
echo "Waiting for server to start..."
for i in {1..60}; do
if curl -f http://localhost:3000 > /dev/null 2>&1; then
echo "Server started successfully after $i seconds"
break
fi
if [ $i -eq 60 ]; then
echo "Server failed to start within 60 seconds"
docker logs mqtt-explorer-test
exit 1
fi
sleep 1
done

- name: Test Docker image - Health check
run: |
# Wait for health check to pass
echo "Waiting for health check to pass..."
for i in {1..30}; do
health=$(docker inspect --format='{{.State.Health.Status}}' mqtt-explorer-test)
if [ "$health" = "healthy" ]; then
echo "Container is healthy"
break
fi
if [ $i -eq 30 ]; then
echo "Health check failed"
docker logs mqtt-explorer-test
exit 1
fi
sleep 2
done

- name: Test Docker image - Verify response
run: |
# Test that the server responds with HTML
response=$(curl -s http://localhost:3000)
if echo "$response" | grep -q "MQTT Explorer"; then
echo "Server is serving the application correctly"
else
echo "Server response does not contain expected content"
echo "Response: $response"
exit 1
fi

- name: Test Docker image - Verify data persistence
run: |
# Check that data directory was created
docker exec mqtt-explorer-test sh -c '[ -d /app/data ] && echo "Data directory exists"'

- name: Clean up test container
if: always()
run: |
docker stop mqtt-explorer-test || true
docker rm mqtt-explorer-test || true

- name: Check Docker image size
run: |
echo "### Docker Image Size" >> $GITHUB_STEP_SUMMARY
docker images mqtt-explorer:test --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" >> $GITHUB_STEP_SUMMARY

# Get size in bytes for detailed reporting
SIZE_BYTES=$(docker inspect mqtt-explorer:test --format='{{.Size}}')
SIZE_MB=$((SIZE_BYTES / 1024 / 1024))
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Image size**: ${SIZE_MB} MB (${SIZE_BYTES} bytes)" >> $GITHUB_STEP_SUMMARY
echo "Image size: ${SIZE_MB} MB"

- name: Setup Node.js for browser tests
uses: actions/setup-node@v4
with:
node-version: '24'
cache: 'yarn'

- name: Install dependencies for browser tests
run: yarn install --frozen-lockfile

- name: Start Docker container for browser tests
run: |
docker run -d \
--name mqtt-explorer-browser-test \
--network host \
-e MQTT_EXPLORER_USERNAME=test \
-e MQTT_EXPLORER_PASSWORD=test123 \
-e PORT=3000 \
mqtt-explorer:test

# Wait for server to be ready
echo "Waiting for Docker container to be ready..."
timeout 60 bash -c 'until curl -f http://localhost:3000; do sleep 1; done'
echo "Docker container is ready"

- name: Run browser test suite
run: |
yarn test:browser
env:
MQTT_EXPLORER_USERNAME: test
MQTT_EXPLORER_PASSWORD: test123
BROWSER_MODE_URL: http://localhost:3000
MQTT_BROKER_HOST: localhost
MQTT_BROKER_PORT: 1883

- name: Clean up browser test container
if: always()
run: |
docker logs mqtt-explorer-browser-test || true
docker stop mqtt-explorer-browser-test || true
docker rm mqtt-explorer-browser-test || true

- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.browser
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-name: ghcr.io/${{ github.repository }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
6 changes: 3 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Test
run: yarn test

ui-tests:
electron-tests:
runs-on: ubuntu-latest
container:
image: ghcr.io/thomasnordquist/mqtt-explorer-ui-tests:latest
Expand All @@ -36,14 +36,14 @@ jobs:
run: yarn install --frozen-lockfile
- name: Build
run: yarn build
- name: Run UI Tests
- name: Run Electron UI Tests
timeout-minutes: 10
run: ./scripts/runUiTests.sh
- name: Upload Test Screenshots
if: always()
uses: actions/upload-artifact@v4
with:
name: ui-test-screenshots
name: electron-test-screenshots
path: |
test-screenshot-*.png
retention-days: 30
Expand Down
Loading
Loading