From c80e323b35dd2b0110c0b419a0e3587ca07a0568 Mon Sep 17 00:00:00 2001 From: Wilko Date: Mon, 19 Oct 2026 10:47:11 +0200 Subject: [PATCH 1/2] Publish a Docker test image :pr- for each pull request Pull requests from branches of this repository get a multi-platform image tagged pr-, rebuilt on every push (a newer push cancels an older build). Forks are skipped since they have no secrets. Closing the pull request deletes the tag via the Docker Hub API. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/pr-image.yml | 79 ++++++++++++++++++++++++++++++++++ CHANGELOG.md | 1 + README.md | 4 ++ 3 files changed, 84 insertions(+) create mode 100644 .github/workflows/pr-image.yml diff --git a/.github/workflows/pr-image.yml b/.github/workflows/pr-image.yml new file mode 100644 index 0000000..6fdbadc --- /dev/null +++ b/.github/workflows/pr-image.yml @@ -0,0 +1,79 @@ +name: PR image + +# Publishes :pr- for every pull request from a branch of this repository, so a change +# can be tested on a real car with `docker pull` before it is merged. Pull requests from forks +# get no secrets and are skipped. :latest, :dev and version tags are never touched. +on: + pull_request: + types: [opened, synchronize, reopened, closed] + +# A newer push to the same pull request replaces a build still running. +concurrency: + group: docker-pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + docker: + name: Publish Docker :pr-${{ github.event.pull_request.number }} + if: github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + + steps: + # The head commit of the branch, not the merge commit with main, so the image is exactly + # what was pushed. + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Login + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} + + - name: Setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Meta + id: meta + uses: docker/metadata-action@v5 + with: + images: wimaha/tesla-ble-http-proxy + tags: | + type=raw,value=pr-${{ github.event.pull_request.number }} + + - name: Publish + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7 + push: true + tags: ${{ steps.meta.outputs.tags }} + + cleanup: + name: Delete Docker :pr-${{ github.event.pull_request.number }} + if: github.event.action == 'closed' && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + + steps: + # Needs a Docker Hub access token with "Read, Write, Delete" scope in DOCKER_PASS. If this + # step fails, delete the tag by hand on Docker Hub. + - name: Delete tag + env: + DOCKER_USER: ${{ secrets.DOCKER_USER }} + DOCKER_PASS: ${{ secrets.DOCKER_PASS }} + TAG: pr-${{ github.event.pull_request.number }} + run: | + token=$(jq -n --arg u "$DOCKER_USER" --arg p "$DOCKER_PASS" '{username: $u, password: $p}' | + curl -sf -H 'Content-Type: application/json' -d @- https://hub.docker.com/v2/users/login | + jq -r .token) + status=$(curl -s -o /dev/null -w '%{http_code}' -X DELETE -H "Authorization: Bearer $token" \ + "https://hub.docker.com/v2/repositories/wimaha/tesla-ble-http-proxy/tags/$TAG/") + case "$status" in + 204) echo "Deleted :$TAG" ;; + 404) echo ":$TAG does not exist, nothing to delete" ;; + *) echo "Deleting :$TAG failed with HTTP $status"; exit 1 ;; + esac diff --git a/CHANGELOG.md b/CHANGELOG.md index 423f40e..3393187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes are listed here. `Unreleased` is what `main` and the Docker - `trustedOrigins` environment variable for reverse proxies over plain HTTP that rewrite the `Host` header, and for web pages on other origins that call the API. See [environment variables](docs/environment_variables.md#trustedorigins). ([#170](https://github.com/wimaha/TeslaBleHttpProxy/pull/170)) - Docker image `:dev`, built from `main` on every push. ([#171](https://github.com/wimaha/TeslaBleHttpProxy/pull/171)) +- Docker image `:pr-` for every pull request from a branch of this repository, to test a change on a car before it is merged. See [Test images for pull requests](README.md#test-images-for-pull-requests). - `releaseAdapterWhenIdle` environment variable: hands the Bluetooth adapter back to the system between connections, so other Bluetooth services on the same host can use it. Off by default. Fixes [#158](https://github.com/wimaha/TeslaBleHttpProxy/issues/158), based on [#161](https://github.com/wimaha/TeslaBleHttpProxy/pull/161) by @AloisKlingler. - `connectionTimeout` environment variable: how long a connection stays open after a command (default 29 seconds as before). Based on [#161](https://github.com/wimaha/TeslaBleHttpProxy/pull/161) by @AloisKlingler. - README examples for `set_charge_limit` and `set_sentry_mode`. ([#169](https://github.com/wimaha/TeslaBleHttpProxy/pull/169)) diff --git a/README.md b/README.md index b43b164..7a7153b 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,10 @@ Please remember to create an empty folder called `key` where the keys can be sto Note that you can optionally set environment variables to override the default behavior. See [environment variables](docs/environment_variables.md) for more information. +#### Test images for pull requests + +Every pull request from a branch of this repository gets its own Docker image `wimaha/tesla-ble-http-proxy:pr-` (for all platforms of the release image), rebuilt on every push to the pull request. To test a change on your car before it is merged, set `image: wimaha/tesla-ble-http-proxy:pr-` in your `docker-compose.yml` and run `docker compose pull && docker compose up -d`. Pull requests from forks get no image. When the pull request is closed, the tag is deleted again. + ## Generate key for vehicle *(Here, the simple, automatic method is described. Besides the automatic method, you can also generate the keys [manually](docs/manually_gen_key.md).)* From b979084f6a2a2d85492481b7361fbe14b5d24d8c Mon Sep 17 00:00:00 2001 From: Wilko Date: Mon, 19 Oct 2026 10:53:07 +0200 Subject: [PATCH 2/2] Report a failed Docker Hub login in the PR image cleanup Mask the token, and give the cleanup job a fixed name so the skipped check is not shown with an unexpanded expression. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/pr-image.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-image.yml b/.github/workflows/pr-image.yml index 6fdbadc..8d08dfb 100644 --- a/.github/workflows/pr-image.yml +++ b/.github/workflows/pr-image.yml @@ -54,7 +54,8 @@ jobs: tags: ${{ steps.meta.outputs.tags }} cleanup: - name: Delete Docker :pr-${{ github.event.pull_request.number }} + # A fixed name: GitHub shows the expression unexpanded while the job is skipped. + name: Delete Docker PR image if: github.event.action == 'closed' && github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest @@ -68,8 +69,13 @@ jobs: TAG: pr-${{ github.event.pull_request.number }} run: | token=$(jq -n --arg u "$DOCKER_USER" --arg p "$DOCKER_PASS" '{username: $u, password: $p}' | - curl -sf -H 'Content-Type: application/json' -d @- https://hub.docker.com/v2/users/login | - jq -r .token) + curl -s -H 'Content-Type: application/json' -d @- https://hub.docker.com/v2/users/login | + jq -r '.token // empty') || true + if [ -z "$token" ]; then + echo "Docker Hub login failed, delete :$TAG by hand" + exit 1 + fi + echo "::add-mask::$token" status=$(curl -s -o /dev/null -w '%{http_code}' -X DELETE -H "Authorization: Bearer $token" \ "https://hub.docker.com/v2/repositories/wimaha/tesla-ble-http-proxy/tags/$TAG/") case "$status" in