2 Commits

Author SHA1 Message Date
89dd398092 ci) publish images to dedicated registry host
All checks were successful
PR Checks / lint-test-and-docker-build (pull_request) Successful in 2m15s
2026-02-21 00:09:33 -05:00
07c9361d76 ci) Updating docker container URI
Some checks failed
PR Checks / lint-test-and-docker-build (pull_request) Has been cancelled
2026-02-20 23:48:36 -05:00
3 changed files with 3 additions and 165 deletions

View File

@@ -4,7 +4,6 @@ on:
push:
branches:
- main
workflow_dispatch:
env:
REGISTRY_HOST: registry.campbellwireless.net
@@ -51,107 +50,3 @@ jobs:
tags: |
${{ env.REGISTRY_HOST }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY_HOST }}/${{ env.IMAGE_NAME }}:${{ steps.tags.outputs.sha_short }}
- name: Preflight Portainer deploy config
env:
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }}
PORTAINER_STACK_ID: ${{ secrets.PORTAINER_STACK_ID }}
PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }}
PORTAINER_INSECURE_TLS: ${{ secrets.PORTAINER_INSECURE_TLS }}
run: |
set -eu
for required in PORTAINER_URL PORTAINER_API_KEY PORTAINER_STACK_ID PORTAINER_ENDPOINT_ID; do
if [ -z "$(eval "printf '%s' \"\${$required:-}\"")" ]; then
echo "Missing required secret: $required" >&2
exit 1
fi
done
CURL_ARGS=(--fail --show-error --silent --retry 3 --retry-all-errors)
if [ "${PORTAINER_INSECURE_TLS:-false}" = "true" ]; then
CURL_ARGS+=(--insecure)
fi
API_BASE="${PORTAINER_URL%/}/api"
ENDPOINT_JSON="$(
curl "${CURL_ARGS[@]}" \
--header "X-API-Key: ${PORTAINER_API_KEY}" \
"${API_BASE}/endpoints/${PORTAINER_ENDPOINT_ID}"
)"
echo "${ENDPOINT_JSON}" | jq -e --arg id "${PORTAINER_ENDPOINT_ID}" \
'((.Id // .id) | tostring) == $id' >/dev/null
STACK_JSON="$(
curl "${CURL_ARGS[@]}" \
--header "X-API-Key: ${PORTAINER_API_KEY}" \
"${API_BASE}/stacks/${PORTAINER_STACK_ID}?endpointId=${PORTAINER_ENDPOINT_ID}"
)"
echo "${STACK_JSON}" | jq -e --arg id "${PORTAINER_STACK_ID}" \
'((.Id // .id) | tostring) == $id' >/dev/null
echo "Portainer preflight checks passed."
- name: Trigger Portainer stack redeploy
env:
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }}
PORTAINER_STACK_ID: ${{ secrets.PORTAINER_STACK_ID }}
PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }}
PORTAINER_INSECURE_TLS: ${{ secrets.PORTAINER_INSECURE_TLS }}
run: |
set -eu
for required in PORTAINER_URL PORTAINER_API_KEY PORTAINER_STACK_ID PORTAINER_ENDPOINT_ID; do
if [ -z "$(eval "printf '%s' \"\${$required:-}\"")" ]; then
echo "Missing required secret: $required" >&2
exit 1
fi
done
CURL_ARGS=(--fail --show-error --silent --retry 3 --retry-all-errors)
if [ "${PORTAINER_INSECURE_TLS:-false}" = "true" ]; then
CURL_ARGS+=(--insecure)
fi
STACK_BASE="${PORTAINER_URL%/}/api/stacks/${PORTAINER_STACK_ID}"
QUERY="endpointId=${PORTAINER_ENDPOINT_ID}"
# Git-based stacks can be redeployed directly.
if curl "${CURL_ARGS[@]}" \
--header "X-API-Key: ${PORTAINER_API_KEY}" \
--request POST \
"${STACK_BASE}/git/redeploy?${QUERY}" >/dev/null; then
echo "Portainer deploy: git stack redeploy triggered."
exit 0
fi
# Non-git stacks: fetch current stack file and redeploy with pullImage=true.
STACK_FILE_CONTENT="$(
curl "${CURL_ARGS[@]}" \
--header "X-API-Key: ${PORTAINER_API_KEY}" \
"${STACK_BASE}/file" \
| jq -r '.StackFileContent'
)"
PAYLOAD_LOWER="$(jq -cn --arg stackFileContent "${STACK_FILE_CONTENT}" \
'{stackFileContent: $stackFileContent, prune: false, pullImage: true}')"
if curl "${CURL_ARGS[@]}" \
--header "X-API-Key: ${PORTAINER_API_KEY}" \
--header "Content-Type: application/json" \
--request PUT \
--data "${PAYLOAD_LOWER}" \
"${STACK_BASE}?${QUERY}" >/dev/null; then
echo "Portainer deploy: stack updated with lower-camel payload."
exit 0
fi
PAYLOAD_UPPER="$(jq -cn --arg StackFileContent "${STACK_FILE_CONTENT}" \
'{StackFileContent: $StackFileContent, Prune: false, PullImage: true}')"
curl "${CURL_ARGS[@]}" \
--header "X-API-Key: ${PORTAINER_API_KEY}" \
--header "Content-Type: application/json" \
--request PUT \
--data "${PAYLOAD_UPPER}" \
"${STACK_BASE}?${QUERY}" >/dev/null
echo "Portainer deploy: stack updated with upper-camel payload."

View File

@@ -1,5 +0,0 @@
Hello and welcome to the Trips repository!
We are glad you are here. This project uses standard git workflows and follows the conventions already in the codebase.
If you are just getting started, begin by reading the README and browsing the main modules to understand the structure.

View File

@@ -79,7 +79,7 @@ The container stores SQLite data at `/data/trips.db` (mounted as the `trips-data
Workflows live in `.gitea/workflows`:
- `pr-checks.yml`: runs lint, tests, and Docker build on pull requests.
- `main-image.yml`: builds and pushes a Docker image on push to `main`, then calls the Portainer API to redeploy. It can also be run manually from the Actions UI.
- `main-image.yml`: builds and pushes a Docker image on push to `main`.
### Registry secrets for image publish
@@ -87,62 +87,10 @@ Configure these repository secrets in Gitea:
- `REGISTRY_USERNAME`
- `REGISTRY_PASSWORD`
- `PORTAINER_URL` (for example, `https://portainer.example.com`)
- `PORTAINER_API_KEY` (Portainer API key for a user with access to the stack)
- `PORTAINER_STACK_ID` (numeric stack ID in Portainer)
- `PORTAINER_ENDPOINT_ID` (numeric environment/endpoint ID in Portainer)
- `PORTAINER_INSECURE_TLS` (optional: set to `true` only if Portainer uses self-signed TLS)
By default, the publish workflow pushes to:
- `registry.campbellwireless.net/<owner>/<repo>:latest`
- `registry.campbellwireless.net/<owner>/<repo>:<short-sha>`
- `git.campbellwireless.net/<owner>/<repo>:latest`
- `git.campbellwireless.net/<owner>/<repo>:<short-sha>`
If your registry host differs, edit `REGISTRY_HOST` in `.gitea/workflows/main-image.yml`.
## Deploy with Portainer API
The `main-image.yml` workflow now calls the Portainer API after pushing `latest`.
In Portainer, create/update your stack to use a published image (not `build`), for example:
```yaml
services:
trips:
image: registry.campbellwireless.net/<owner>/<repo>:latest
container_name: trips
restart: unless-stopped
ports:
- '3000:3000'
volumes:
- trips-data:/data
env_file:
- .env
environment:
NODE_ENV: production
DATABASE_URL: file:/data/trips.db
PORT: '3000'
volumes:
trips-data:
```
Then in Portainer:
1. Create an API key from your user profile (`My account` -> `API keys`).
2. Open the stack details page and note the stack ID.
3. Open `Environments` and note the endpoint/environment ID where the stack runs.
4. Save these values in your Gitea repository secrets:
- `PORTAINER_URL`
- `PORTAINER_API_KEY`
- `PORTAINER_STACK_ID`
- `PORTAINER_ENDPOINT_ID`
- optional `PORTAINER_INSECURE_TLS=true`
Flow on each push to `main` (or manual run of `main-image.yml`):
1. Build image.
2. Push `:latest` and `:<short-sha>`.
3. Run Portainer preflight checks (auth + stack/endpoint IDs).
4. Call Portainer API.
5. Portainer redeploys the stack and pulls the updated image.