Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
77edee0
chore: expand CONTRIBUTING with dev and release workflows (#15)
phunkeler May 3, 2026
71ec825
ci: rename workflow to SonarCloud and restrict permissions (#16)
phunkeler May 3, 2026
297c4d1
refactor: Observable devices + tests (#19)
phunkeler May 4, 2026
7e82a2c
fix: No INFO level logging (#22)
phunkeler May 4, 2026
d95a87f
fix: log levels + categoryName + dependabot groups (#23)
phunkeler May 4, 2026
56104dd
fix: [DevOps] Expose Test coverage (#27)
phunkeler May 5, 2026
171eeeb
fix: 'ContinuousIntegrationBuild' in ci code (#28)
phunkeler May 5, 2026
877cd55
BIG refactor (API simplification)
phunkeler May 9, 2026
09a7970
test cleanup
phunkeler May 12, 2026
d7d54c4
fan-out per-subscriber channel
phunkeler May 13, 2026
ab40edd
refinement
phunkeler May 13, 2026
cf43d4f
ChannelBroadcaster + Messaging Pattern + enforce single consumer payl…
phunkeler May 20, 2026
178b0ed
Handle Reconnect attempt
phunkeler May 20, 2026
43766dd
Add Pi device farm: Appium Docker setup, UI test infrastructure, devi…
phunkeler May 24, 2026
97c1985
docs: use 'preview' pre-release naming to match Microsoft/MAUI conven…
phunkeler May 24, 2026
a6b0d4a
ci: add UI test workflow with self-hosted Pi runner and security guards
phunkeler May 24, 2026
ede899b
docs: add self-hosted runner setup and security hardening sections
phunkeler May 24, 2026
e53a835
docs: wording fix in runner section
phunkeler May 24, 2026
14f728d
ci: add device health-check step and self-healing ADB service
phunkeler May 24, 2026
9124a8e
ci: containerised runner built from official actions/runner binary
phunkeler May 24, 2026
725cad9
ci: fix Dockerfile lints and drop stored PAT in favour of gh CLI auth…
phunkeler May 24, 2026
ae453f0
ci: split workflow — APK build on ubuntu-24.04-arm, UI tests on Pi ru…
phunkeler May 24, 2026
c874a97
Build and push runner/appium images to GHCR via workflow
phunkeler May 24, 2026
044d48a
Add day-to-day operations runbook to Pi setup docs
phunkeler May 24, 2026
64a922a
Add single-device smoke test; skip two-device tests when DEVICE2_SERI…
phunkeler May 24, 2026
dbb0793
publish: create GitHub Release with auto-generated notes after NuGet …
phunkeler May 24, 2026
456bbc5
publish: open PR to main automatically after release
phunkeler May 24, 2026
569eaa5
publish: remove auto-PR step; tag always goes on main after squash merge
phunkeler May 24, 2026
d02e503
docs: document preview release process and add release.sh script
phunkeler May 24, 2026
106f121
ci: use ubuntu-latest and global.json for APK build and UI test jobs
phunkeler May 24, 2026
a775486
ci: pin all action references to full SHA, add Dependabot github-acti…
phunkeler May 24, 2026
03b3fc9
ci: harden containers with read-only fs and dropped caps; add Dependa…
phunkeler May 24, 2026
68ec639
ci: label Actions SHA bump PRs and post allow-list update reminder
phunkeler May 24, 2026
1294ddb
ci: add OS hardening to setup-pi-host.sh; fix USER expansion in syste…
phunkeler May 24, 2026
da2c1dc
fix: use Type=simple and nodaemon for adb-server systemd service
phunkeler May 24, 2026
6f625ba
fix: kill existing adb process before starting adb-server service
phunkeler May 24, 2026
5c92e7b
ci: add cloud-init user-data for reproducible Pi provisioning
phunkeler May 24, 2026
eef734d
self-hosted runner config
phunkeler May 24, 2026
108736e
fix: dotnet workload restore TFM
phunkeler May 24, 2026
f370d2c
fix: pre-install .NET in runner image; add SSH key gitignore rule
phunkeler May 24, 2026
c5d1dc4
Merge remote-tracking branch 'origin/main' into 0.3.0-preview.1
phunkeler May 24, 2026
04c44ba
fix: remove duplicate partial class files left over from merge
phunkeler May 24, 2026
d7b8b94
fix: remove duplicate type definitions left over from merge
phunkeler May 24, 2026
e09394b
fix: restore branch file structure lost during merge conflict resolution
phunkeler May 24, 2026
00d96e9
fix: options using
phunkeler May 24, 2026
f786927
fix: restore branch android implementation lost during merge
phunkeler May 24, 2026
4406144
fix: return Task.CompletedTask from advertise error catch path
phunkeler May 24, 2026
7d61db8
fix: restore NearbyChat sample files lost during merge
phunkeler May 24, 2026
c4a7a24
fix: runner image uses global.json SDK version; drop setup-dotnet fro…
phunkeler May 24, 2026
2ce6626
fix: runner image uses global.json SDK version; fix adb host routing …
phunkeler May 24, 2026
3af2413
fix: restore unit tests and runner image lost during merge
phunkeler May 24, 2026
3b9f212
fix: check devices before APK install for earlier ADB diagnostics
phunkeler May 24, 2026
84fdaca
fix: allow docker bridge access to ADB port 5037 in UFW
phunkeler May 24, 2026
0faefdb
fix: scope ADB firewall rule to docker subnet instead of docker0 inte…
phunkeler May 24, 2026
5fe0a91
fix: correct adb-server service name in diagnostic message
phunkeler May 24, 2026
802bba5
fix: use host networking for runner to allow local ADB access
phunkeler May 24, 2026
3b42d5e
fix: correct entrypoint.sh path for repo-root build context
phunkeler May 24, 2026
1b55087
fix: docker clear creds
phunkeler May 24, 2026
62def46
fix: remove read_only from runner, start Appium ephemerally via AppHost
phunkeler May 24, 2026
816ea51
feat: Aspire for uitests
phunkeler May 24, 2026
0faa212
fix: remove tmpfs mounts from ephemeral runner — writable layer is su…
phunkeler May 24, 2026
232acb7
fix: uninstall before install and capture APK install output
phunkeler May 24, 2026
9d03abb
diag: expose trace during apk install
phunkeler May 24, 2026
f444e4b
fix: use --no-streaming for APK install to work around Samsung stream…
phunkeler May 24, 2026
f1f11f6
fix: use push+pm install to avoid ADB TCP response drop on Samsung
phunkeler May 24, 2026
5bc3cc4
fix: restart runner always so ephemeral runner re-registers after eac…
phunkeler May 24, 2026
9eb86c6
fix: use Unix socket ADB to avoid TCP proxy limitations on large file…
phunkeler May 24, 2026
dc78b6a
fix: treat adb push copy-response error as non-fatal; bytes land rega…
phunkeler May 24, 2026
fad4f00
feat: install XHarness CLI in runner image; use it for APK installation
phunkeler May 24, 2026
428af91
fix: add dotnet-eng feed source for XHarness CLI tool install
phunkeler May 24, 2026
7f04b0e
feat: capture Appium and ADB logcat logs as CI artifacts
phunkeler May 24, 2026
991132b
feat: add preflight.sh to verify Pi device farm is ready
phunkeler May 24, 2026
1a2f36b
fix: explicitly add dotnet tools dir to PATH for xharness step
phunkeler May 24, 2026
1bc2400
fix: use plain adb in check-devices.sh to match Unix socket transport…
phunkeler May 24, 2026
b9d143e
fix: wait-for-device before state check to handle transient offline o…
phunkeler May 24, 2026
b2ef39d
revert: drop XHarness, use adb push+pm install for APK deployment
phunkeler May 24, 2026
e869e7d
feat: add XHarness to tool manifest; restore and use via dotnet tool run
phunkeler May 24, 2026
19d88c3
fix: add --output-directory to xharness android install
phunkeler May 24, 2026
7d1124e
fix: replace XHarness bundled x86_64 adb with system ARM64 binary
phunkeler May 24, 2026
1b9b122
fix: disable Samsung package verifier before debug APK install
phunkeler May 24, 2026
27bd888
fix: mount persistent ADB key dir so device authorization survives co…
phunkeler May 25, 2026
372fbbc
fix: disable USB autosuspend in cloud-init to prevent ADB transport t…
phunkeler May 25, 2026
77b0df2
fix: replace XHarness install with adb --no-streaming; fix stale runn…
phunkeler May 25, 2026
e6add4f
fix: correct branch pattern to match hyphenated preview branch names
phunkeler May 25, 2026
f2379b7
ci: trigger docker image rebuild
phunkeler May 25, 2026
0c94f67
ci: add renovate hint for runner version; trigger image rebuild
phunkeler May 25, 2026
9018409
test
phunkeler May 26, 2026
74d360a
fix: use dotnet publish vs. build
phunkeler May 26, 2026
a146bc4
ci: cache workloads + nugets
phunkeler May 26, 2026
ad74b70
ci: actions/cache SHA
phunkeler May 26, 2026
eb82da6
ci: dotnet restore with "-p:TargetFramework"
phunkeler May 26, 2026
977d2df
ci: dotnet public with "--no--restore"
phunkeler May 26, 2026
297c959
ci: workload cache path correction
phunkeler May 26, 2026
2b1a1be
ci: debug,keystore
phunkeler May 26, 2026
dd28aa0
ci: androidkeystore=true
phunkeler May 26, 2026
afc6aa0
ci: android signing
phunkeler May 26, 2026
ea5db31
ci: debug.keystore signing fix
phunkeler May 26, 2026
47006b7
ci: refine
phunkeler May 27, 2026
6523c9b
ci: map host USB volumes to docker container
phunkeler May 30, 2026
d28ca45
ci: upload "-Signed.apk" ONLY
phunkeler May 30, 2026
ec5b755
ci: uitests ADB path
phunkeler May 30, 2026
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
5 changes: 5 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": 1,
"isRoot": true,
"tools": {}
}
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# Code style defaults
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
csharp_prefer_braces = true:silent
csharp_prefer_braces = true:warning
csharp_preserve_single_line_blocks = true:none
csharp_preserve_single_line_statements = false:none
csharp_prefer_static_local_function = true:suggestion
Expand Down
13 changes: 13 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Summary


## Checklist

- [ ] Tested locally
- [ ] No sensitive data (serials, IPs, tokens) in committed files

<!--
If this is a Dependabot GitHub Actions SHA bump (chore(deps)):
After merging, update the matching SHA in:
Settings → Actions → General → "Allow or block specified actions and reusable workflows"
-->
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "chore(deps)"
labels:
- "actions-sha-bump"

- package-ecosystem: "docker"
directory: "/docker/runner"
schedule:
interval: "weekly"
commit-message:
prefix: "chore(deps)"

- package-ecosystem: "docker"
directory: "/docker/appium"
schedule:
interval: "weekly"
commit-message:
prefix: "chore(deps)"

- package-ecosystem: "nuget"
directory: "/"
schedule:
Expand Down
23 changes: 23 additions & 0 deletions .github/workflows/actions-sha-bump-reminder.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Actions SHA bump reminder

on:
pull_request:
types: [labeled]

permissions:
pull-requests: write

jobs:
remind:
if: github.event.label.name == 'actions-sha-bump'
runs-on: ubuntu-latest
steps:
- name: Post allow-list reminder
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--body "**Reminder:** After merging, update the matching SHA in [Settings → Actions → General → Allow list](../../settings/actions).

The new SHA is in the workflow file changed by this PR."
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@ jobs:
runs-on: macos-26-intel
steps:

- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- uses: actions/setup-dotnet@v5
- uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
with:
global-json-file: global.json

- name: Cache SonarQube Cloud packages
uses: actions/cache@v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar

- name: Cache SonarQube Cloud scanner
id: cache-sonar-scanner
uses: actions/cache@v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ${{ runner.temp }}/scanner
key: ${{ runner.os }}-sonar-scanner
Expand Down Expand Up @@ -63,13 +63,13 @@ jobs:
${{ runner.temp }}/scanner/dotnet-sonarscanner end /d:sonar.token="$SONAR_TOKEN"

- name: Upload coverage artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: coverage
path: ${{ runner.temp }}/coverage.xml

- name: Generate coverage report
uses: danielpalme/ReportGenerator-GitHub-Action@5.5.9
uses: danielpalme/ReportGenerator-GitHub-Action@c31aa4ed4f12f147061186cf2a029f307b5c3636 # 5.5.9
with:
reports: ${{ runner.temp }}/coverage.xml
targetdir: ${{ runner.temp }}/coveragereport
Expand Down
66 changes: 66 additions & 0 deletions .github/workflows/docker-images.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Docker Images

on:
push:
branches: [main, "*.*.*-preview.*"]
paths:
- 'docker/**'
workflow_dispatch:

env:
REGISTRY: ghcr.io
OWNER: phunkeler

jobs:
build-runner:
name: Build runner image
runs-on: ubuntu-24.04-arm
if: github.repository_owner == 'phunkeler'
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push runner image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
file: docker/runner/Dockerfile
platforms: linux/arm64
push: true
tags: ${{ env.REGISTRY }}/${{ env.OWNER }}/nearbyconnections-runner:latest

build-appium:
name: Build appium image
runs-on: ubuntu-24.04-arm
if: github.repository_owner == 'phunkeler'
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push appium image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: docker/appium
platforms: linux/arm64
push: true
tags: ${{ env.REGISTRY }}/${{ env.OWNER }}/nearbyconnections-appium:latest
41 changes: 41 additions & 0 deletions .github/workflows/os-maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: OS Maintenance

on:
schedule:
- cron: '0 2 * * 0' # Weekly, Sunday 02:00 UTC
workflow_dispatch:

permissions: {}

jobs:
dry-run-upgrades:
name: Unattended-upgrade dry run
runs-on: [self-hosted, linux, ARM64]
steps:
- name: Run dry run via SSH
id: dry_run
env:
PI_SSH_PRIVATE_KEY: ${{ secrets.PI_SSH_PRIVATE_KEY }}
run: |
eval $(ssh-agent -s)
echo "$PI_SSH_PRIVATE_KEY" | ssh-add -
OUTPUT=$(ssh \
-o StrictHostKeyChecking=accept-new \
-o UserKnownHostsFile=/tmp/pi_known_hosts \
sandlot@host.docker.internal \
"sudo unattended-upgrade --dry-run 2>&1" || true)
ssh-agent -k
{
echo 'output<<EOF'
echo "$OUTPUT"
echo 'EOF'
} >> "$GITHUB_OUTPUT"

- name: Post job summary
run: |
{
echo "## Unattended-Upgrade Dry Run — $(date -u '+%Y-%m-%d %H:%M UTC')"
echo '```'
echo "${{ steps.dry_run.outputs.output }}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
26 changes: 22 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,50 @@ on:

permissions:
id-token: write
contents: read
contents: write

jobs:
publish:
runs-on: macos-latest
environment: nuget
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0 # Required for MinVer to resolve the version from git tags

- uses: actions/setup-dotnet@v5
- uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5
with:
global-json-file: global.json

- name: Restore workloads
run: dotnet workload restore src/Plugin.Maui.NearbyConnections/Plugin.Maui.NearbyConnections.csproj

- name: Build
run: dotnet build src/Plugin.Maui.NearbyConnections/Plugin.Maui.NearbyConnections.csproj -c Release

- name: Build tests
run: dotnet build test/Plugin.Maui.NearbyConnections.UnitTests/Plugin.Maui.NearbyConnections.UnitTests.csproj -c Release

- name: Test
run: dotnet exec test/Plugin.Maui.NearbyConnections.UnitTests/bin/Release/net10.0/Plugin.Maui.NearbyConnections.UnitTests.dll

- name: Pack
run: dotnet pack src/Plugin.Maui.NearbyConnections/Plugin.Maui.NearbyConnections.csproj -c Release --output nupkgs /p:ContinuousIntegrationBuild=true

- name: Login to NuGet.org (OIDC)
uses: NuGet/login@v1.2.0
uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0
id: login
with:
user: phunkeler

- name: Push to NuGet.org
run: dotnet nuget push nupkgs/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate

- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ github.ref_name }}" \
--generate-notes \
--prerelease=${{ contains(github.ref_name, 'preview') }} \
nupkgs/*.nupkg
41 changes: 41 additions & 0 deletions .github/workflows/reapply-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Reapply host config

on:
workflow_dispatch:

permissions: {}

jobs:
reapply:
name: Reapply Pi host configuration
runs-on: [self-hosted, linux, ARM64]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Reapply configuration via SSH
id: reapply
env:
PI_ADMIN_SSH_KEY: ${{ secrets.PI_ADMIN_SSH_KEY }}
run: |
eval $(ssh-agent -s)
echo "$PI_ADMIN_SSH_KEY" | ssh-add -
OUTPUT=$(ssh \
-o StrictHostKeyChecking=accept-new \
-o UserKnownHostsFile=/tmp/pi_known_hosts \
sandlot@host.docker.internal \
< scripts/reapply-host-config.sh 2>&1 || true)
ssh-agent -k
{
echo 'output<<EOF'
echo "$OUTPUT"
echo 'EOF'
} >> "$GITHUB_OUTPUT"

- name: Post job summary
run: |
{
echo "## Host config reapplied — $(date -u '+%Y-%m-%d %H:%M UTC')"
echo '```'
echo "${{ steps.reapply.outputs.output }}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
2 changes: 1 addition & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
- uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4
with:
config-file: .release-please-config.json
manifest-file: .release-please-manifest.json
Loading
Loading