{currentName?`Running ${duration(current.elapsed_seconds)}`:"Waiting for an active import"}
{currentName||"No active copy."}
{currentName&&<>diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 00cd1c0..1f4f306 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -31,13 +31,22 @@ jobs: python -m pytest -q npm --prefix frontend test -- --run npm --prefix frontend run build + python -m pip wheel --no-deps --wheel-dir dist . sh -n deploy/systemd-install.sh sh -n deploy/repo-upgrade.sh + - uses: actions/upload-artifact@v4 + with: + name: importarr-wheel + path: dist/*.whl deploy: needs: test runs-on: ubuntu-latest steps: + - uses: actions/download-artifact@v4 + with: + name: importarr-wheel + path: dist - name: Configure deployment SSH shell: bash env: @@ -54,10 +63,16 @@ jobs: DEPLOY_HOST: ${{ secrets.IMPORTARR_DEPLOY_HOST }} DEPLOY_PORT: ${{ secrets.IMPORTARR_DEPLOY_PORT }} DEPLOY_USER: ${{ secrets.IMPORTARR_DEPLOY_USER }} - run: >- - ssh -p "$DEPLOY_PORT" -o BatchMode=yes "$DEPLOY_USER@$DEPLOY_HOST" - "sudo -n /bin/sh -c 'set -eu; cd /opt/importarr/repo; + DEPLOY_SHA: ${{ github.sha }} + run: | + WHEEL=$(find dist -maxdepth 1 -name 'importarr-*.whl' -print -quit) + test -n "$WHEEL" + scp -P "$DEPLOY_PORT" -o BatchMode=yes "$WHEEL" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/importarr-deploy.whl" + ssh -p "$DEPLOY_PORT" -o BatchMode=yes "$DEPLOY_USER@$DEPLOY_HOST" \ + "deploy_status=0; sudo -n /bin/sh -c 'set -eu; cd /opt/importarr/repo; test -z \"\$(git status --porcelain)\"; git fetch --prune origin main; - git checkout -B main origin/main; - exec /bin/sh deploy/repo-upgrade.sh'" + git checkout --detach $DEPLOY_SHA; + /bin/sh deploy/repo-upgrade.sh /tmp/importarr-deploy.whl $DEPLOY_SHA' || deploy_status=\$?; + rm -f /tmp/importarr-deploy.whl; + exit \$deploy_status" diff --git a/deploy/repo-upgrade.sh b/deploy/repo-upgrade.sh index e7ece6f..e68d790 100644 --- a/deploy/repo-upgrade.sh +++ b/deploy/repo-upgrade.sh @@ -16,10 +16,16 @@ PREFIX=${IMPORTARR_PREFIX:-/opt/importarr} REPO_DIR=${IMPORTARR_REPO_DIR:-$PREFIX/repo} SERVICE=${IMPORTARR_SERVICE:-importarr.service} VENV=${IMPORTARR_VENV:-$PREFIX/venv} -if [ "$#" -ne 0 ]; then - echo "Usage: $0" >&2 +if [ "$#" -gt 2 ]; then + echo "Usage: $0 [wheel [revision]]" >&2 exit 2 fi +WHEEL=${1:-} +REVISION=${2:-} +if [ -n "$WHEEL" ] && [ ! -f "$WHEEL" ]; then + echo "Built wheel not found: $WHEEL" >&2 + exit 1 +fi LOCK_FILE=${IMPORTARR_UPGRADE_LOCK_FILE:-$PREFIX/repo-upgrade.lock} exec 9>"$LOCK_FILE" @@ -40,10 +46,14 @@ if [ -n "$(git status --porcelain)" ]; then exit 1 fi -git fetch --prune origin main -git checkout -B main origin/main -test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" -"$VENV/bin/pip" install --upgrade --force-reinstall --no-cache-dir "$REPO_DIR" +if [ -n "$REVISION" ]; then + test "$(git rev-parse HEAD)" = "$(git rev-parse "$REVISION^{commit}")" +else + git fetch --prune origin main + git checkout -B main origin/main + test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" +fi +"$VENV/bin/pip" install --upgrade --force-reinstall --no-cache-dir "${WHEEL:-$REPO_DIR}" if [ -f "$ENV_FILE" ]; then sed -i '/^[[:space:]]*IMPORTARR_UPDATE_COMMAND=/d' "$ENV_FILE" fi diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 81ad20c..1b1bd76 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -23,6 +23,7 @@ export const pollDelay = failures => failures ? Math.min(5000,1000*2**(failures- function Modal({ trigger, title, children }) { return ; } function Field({ label, ...props }) { return ; } +export function BuildSummary({ build }) { return
{build?`Build ${build.git_sha} · ${build.build_date}`:"Build information unavailable"}
; } export function SettingsDialog({ status, refresh }) { const [result,setResult]=useState({}); @@ -45,7 +46,7 @@ export function App(){ const control=action=>{if(action==="cancel-current"&&!confirm("Cancel the current import job?"))return;post(`/api/control/${action}`)}; const current=status?.current, currentName=typeof current==="object"?(current.file||current.name):current; return{status?.control?.queue_mode||"Connecting"}
{status?.control?.queue_mode||"Connecting"}
{currentName?`Running ${duration(current.elapsed_seconds)}`:"Waiting for an active import"}
{currentName||"No active copy."}
{currentName&&<>