ci: switch mai-bot release to single-host build runner
This commit is contained in:
@@ -4,155 +4,37 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-upload:
|
||||
runs-on: local-build
|
||||
package-and-deploy:
|
||||
runs-on: build-host
|
||||
steps:
|
||||
- name: Prepare local worktree
|
||||
env:
|
||||
MAIBOT_REPO_URL: https://git.lecspace.com/${{ gitea.repository }}.git
|
||||
MAIBOT_GIT_REPO_URL: ${{ secrets.MAIBOT_GIT_REPO_URL }}
|
||||
MAIBOT_REPO_URL: http://127.0.0.1:3000/${{ gitea.repository }}.git
|
||||
MAIBOT_REPO_SHA: ${{ gitea.sha }}
|
||||
MAIBOT_GITEA_USER: ${{ secrets.MAIBOT_GITEA_USER }}
|
||||
MAIBOT_GITEA_TOKEN: ${{ secrets.MAIBOT_GITEA_TOKEN }}
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
function Add-GitHubEnv {
|
||||
param([string]$Line)
|
||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
||||
[System.IO.File]::AppendAllText($env:GITHUB_ENV, $Line + [Environment]::NewLine, $utf8NoBom)
|
||||
}
|
||||
|
||||
$worktreeRoot = Join-Path ([System.IO.Path]::GetTempPath()) "maibot-actions"
|
||||
$worktree = Join-Path $worktreeRoot $env:MAIBOT_REPO_SHA
|
||||
$repoUrl = if ([string]::IsNullOrWhiteSpace($env:MAIBOT_GIT_REPO_URL)) { $env:MAIBOT_REPO_URL } else { $env:MAIBOT_GIT_REPO_URL }
|
||||
|
||||
if (Test-Path $worktree) {
|
||||
Remove-Item -LiteralPath $worktree -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $worktreeRoot | Out-Null
|
||||
|
||||
$gitArgs = @()
|
||||
if (-not [string]::IsNullOrWhiteSpace($env:MAIBOT_GITEA_TOKEN)) {
|
||||
$giteaUser = $env:MAIBOT_GITEA_USER
|
||||
if ([string]::IsNullOrWhiteSpace($giteaUser)) { $giteaUser = "Losita" }
|
||||
$basicToken = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $giteaUser, $env:MAIBOT_GITEA_TOKEN)))
|
||||
$gitArgs += @("-c", ("http.extraHeader=Authorization: Basic {0}" -f $basicToken))
|
||||
}
|
||||
|
||||
& git @gitArgs clone --no-checkout $repoUrl $worktree
|
||||
if ($LASTEXITCODE -ne 0) { throw "source clone failed." }
|
||||
|
||||
& git -C $worktree checkout --force $env:MAIBOT_REPO_SHA
|
||||
if ($LASTEXITCODE -ne 0) { throw "source checkout failed." }
|
||||
|
||||
& git -C $worktree clean -dffx
|
||||
if ($LASTEXITCODE -ne 0) { throw "source cleanup failed." }
|
||||
|
||||
$appTag = (& git -C $worktree rev-parse --short=12 HEAD).Trim()
|
||||
Add-GitHubEnv "APP_TAG=$appTag"
|
||||
Add-GitHubEnv "MAIBOT_WORKTREE=$worktree"
|
||||
|
||||
- name: Build release archive
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
function Add-GitHubEnv {
|
||||
param([string]$Line)
|
||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
||||
[System.IO.File]::AppendAllText($env:GITHUB_ENV, $Line + [Environment]::NewLine, $utf8NoBom)
|
||||
}
|
||||
|
||||
Set-Location $env:MAIBOT_WORKTREE
|
||||
$archiveDir = Join-Path ([System.IO.Path]::GetTempPath()) "maibot-release"
|
||||
New-Item -ItemType Directory -Force -Path $archiveDir | Out-Null
|
||||
$archivePath = Join-Path $archiveDir ("mai-bot-{0}.tgz" -f $env:APP_TAG)
|
||||
if (Test-Path $archivePath) {
|
||||
Remove-Item -LiteralPath $archivePath -Force
|
||||
}
|
||||
|
||||
& git archive --format=tar.gz --output=$archivePath HEAD
|
||||
if ($LASTEXITCODE -ne 0) { throw "release archive failed." }
|
||||
|
||||
Add-GitHubEnv "RELEASE_ARCHIVE=$archivePath"
|
||||
|
||||
- name: Upload release to server
|
||||
env:
|
||||
MAIBOT_RELEASE_HOST: ${{ secrets.MAIBOT_RELEASE_HOST }}
|
||||
MAIBOT_RELEASE_USER: ${{ secrets.MAIBOT_RELEASE_USER }}
|
||||
MAIBOT_RELEASE_PORT: ${{ secrets.MAIBOT_RELEASE_PORT }}
|
||||
MAIBOT_RELEASE_ROOT: ${{ secrets.MAIBOT_RELEASE_ROOT }}
|
||||
MAIBOT_SSH_KEY: ${{ secrets.MAIBOT_SSH_KEY }}
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$hostName = $env:MAIBOT_RELEASE_HOST
|
||||
if ([string]::IsNullOrWhiteSpace($hostName)) { $hostName = "192.140.166.210" }
|
||||
$userName = $env:MAIBOT_RELEASE_USER
|
||||
if ([string]::IsNullOrWhiteSpace($userName)) { $userName = "root" }
|
||||
$port = $env:MAIBOT_RELEASE_PORT
|
||||
if ([string]::IsNullOrWhiteSpace($port)) { $port = "22" }
|
||||
$releaseRoot = $env:MAIBOT_RELEASE_ROOT
|
||||
if ([string]::IsNullOrWhiteSpace($releaseRoot)) { $releaseRoot = "/srv/maibot/releases" }
|
||||
if ($releaseRoot -notmatch '^/srv/maibot/releases(/.*)?$') { throw "release root must stay under /srv/maibot/releases." }
|
||||
|
||||
$remote = "{0}@{1}" -f $userName, $hostName
|
||||
$remoteArchive = ("{0}/{1}.tgz" -f $releaseRoot.TrimEnd('/'), $env:APP_TAG)
|
||||
$sshArgs = @("-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=30", "-p", $port)
|
||||
$scpArgs = @("-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=30", "-P", $port)
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($env:MAIBOT_SSH_KEY)) {
|
||||
$keyPath = Join-Path ([System.IO.Path]::GetTempPath()) ("maibot-release-{0}.key" -f $env:APP_TAG)
|
||||
$env:MAIBOT_SSH_KEY.Replace("`r`n", "`n") | Out-File -FilePath $keyPath -Encoding ascii -NoNewline
|
||||
if ([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)) {
|
||||
& icacls $keyPath /inheritance:r /grant:r "$($env:USERNAME):(R)" | Out-Null
|
||||
} else {
|
||||
& chmod 600 $keyPath
|
||||
}
|
||||
$sshArgs += @("-i", $keyPath)
|
||||
$scpArgs += @("-i", $keyPath)
|
||||
}
|
||||
|
||||
& ssh @sshArgs $remote "mkdir -p '$releaseRoot'"
|
||||
if ($LASTEXITCODE -ne 0) { throw "remote release root prepare failed." }
|
||||
|
||||
& scp @scpArgs $env:RELEASE_ARCHIVE ("{0}:{1}" -f $remote, $remoteArchive)
|
||||
if ($LASTEXITCODE -ne 0) { throw "release upload failed." }
|
||||
|
||||
- name: Cleanup worktree
|
||||
if: ${{ always() }}
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
$worktreeRoot = Join-Path ([System.IO.Path]::GetTempPath()) "maibot-actions"
|
||||
$expectedPrefix = $worktreeRoot.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) + [System.IO.Path]::DirectorySeparatorChar
|
||||
if (-not [string]::IsNullOrWhiteSpace($env:MAIBOT_WORKTREE) -and $env:MAIBOT_WORKTREE.StartsWith($expectedPrefix, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
Remove-Item -LiteralPath $env:MAIBOT_WORKTREE -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
deploy:
|
||||
runs-on: build-host
|
||||
needs: build-upload
|
||||
steps:
|
||||
- name: Deploy release
|
||||
env:
|
||||
MAIBOT_REPO_SHA: ${{ gitea.sha }}
|
||||
MAIBOT_RELEASE_ROOT: ${{ secrets.MAIBOT_RELEASE_ROOT }}
|
||||
MAIBOT_RUNTIME_ROOT: ${{ secrets.MAIBOT_RUNTIME_ROOT }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
app_tag="${MAIBOT_REPO_SHA:0:12}"
|
||||
release_root="${MAIBOT_RELEASE_ROOT:-/srv/maibot/releases}"
|
||||
runtime_root="${MAIBOT_RUNTIME_ROOT:-/root/maibot-offline}"
|
||||
worktree_root=/tmp/maibot-actions
|
||||
worktree="${worktree_root}/${MAIBOT_REPO_SHA}"
|
||||
|
||||
rm -rf "$worktree"
|
||||
mkdir -p "$worktree_root"
|
||||
|
||||
git clone --no-checkout "$MAIBOT_REPO_URL" "$worktree"
|
||||
git -C "$worktree" checkout --force "$MAIBOT_REPO_SHA"
|
||||
git -C "$worktree" clean -dffx
|
||||
|
||||
app_tag="$(git -C "$worktree" rev-parse --short=12 HEAD)"
|
||||
printf 'APP_TAG=%s\n' "$app_tag" >> "$GITHUB_ENV"
|
||||
printf 'MAIBOT_WORKTREE=%s\n' "$worktree" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Stage release directory
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_root="${MAIBOT_RELEASE_ROOT:-/srv/maibot/releases}"
|
||||
case "$release_root" in
|
||||
/srv/maibot/releases|/srv/maibot/releases/*) ;;
|
||||
*)
|
||||
@@ -161,21 +43,31 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$runtime_root" in
|
||||
/root/maibot-offline|/root/maibot-offline/*) ;;
|
||||
*)
|
||||
echo "runtime root must stay under /root/maibot-offline" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
archive="${release_root}/${app_tag}.tgz"
|
||||
release_dir="${release_root}/${app_tag}"
|
||||
|
||||
test -f "$archive"
|
||||
release_dir="${release_root}/${APP_TAG}"
|
||||
rm -rf "$release_dir"
|
||||
mkdir -p "$release_dir"
|
||||
tar -xzf "$archive" -C "$release_dir"
|
||||
chmod +x "$release_dir/deploy/server-maibot/activate-release.sh"
|
||||
MAIBOT_RUNTIME_ROOT="$runtime_root" "$release_dir/deploy/server-maibot/activate-release.sh" "$release_dir"
|
||||
rm -f "$archive"
|
||||
git -C "$MAIBOT_WORKTREE" archive HEAD | tar -x -C "$release_dir"
|
||||
|
||||
printf 'RELEASE_DIR=%s\n' "$release_dir" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Deploy release
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
runtime_root="${MAIBOT_RUNTIME_ROOT:-/root/maibot-offline}"
|
||||
chmod +x "$RELEASE_DIR/deploy/server-maibot/activate-release.sh"
|
||||
MAIBOT_RUNTIME_ROOT="$runtime_root" "$RELEASE_DIR/deploy/server-maibot/activate-release.sh" "$RELEASE_DIR"
|
||||
|
||||
- name: Cleanup worktree
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
worktree_root=/tmp/maibot-actions/
|
||||
case "${MAIBOT_WORKTREE:-}" in
|
||||
${worktree_root}*)
|
||||
rm -rf "$MAIBOT_WORKTREE"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -19,13 +19,14 @@ Persistent files that stay on the server and do not go into Git:
|
||||
Gitea workflow:
|
||||
- .gitea/workflows/release-offline.yml
|
||||
|
||||
Suggested Gitea secrets:
|
||||
- MAIBOT_RELEASE_HOST
|
||||
- MAIBOT_RELEASE_USER
|
||||
- MAIBOT_RELEASE_PORT
|
||||
- MAIBOT_RELEASE_ROOT
|
||||
- MAIBOT_RUNTIME_ROOT
|
||||
- MAIBOT_SSH_KEY
|
||||
- MAIBOT_GIT_REPO_URL (optional)
|
||||
- MAIBOT_GITEA_USER (optional)
|
||||
- MAIBOT_GITEA_TOKEN (optional)
|
||||
Current pipeline mode:
|
||||
- single-host release on the repo-level `build-host` runner
|
||||
- clones from local Gitea HTTP on `127.0.0.1:3000`
|
||||
- stages source into `/srv/maibot/releases/<commit>`
|
||||
- activates it into `/root/maibot-offline`
|
||||
|
||||
Optional environment overrides for the workflow runtime:
|
||||
- `MAIBOT_RELEASE_ROOT`
|
||||
- `MAIBOT_RUNTIME_ROOT`
|
||||
|
||||
No repository secrets are required for the default same-host pipeline.
|
||||
|
||||
Reference in New Issue
Block a user