feat(npc): restore missing dialogue keywords for the remaining Thais NPCs (part 3/3) #2266
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Deploy to Neep Host | |
| on: | |
| workflow_dispatch: | |
| issue_comment: | |
| types: [created] | |
| concurrency: | |
| group: deploy-neep | |
| cancel-in-progress: false | |
| jobs: | |
| deploy: | |
| if: | | |
| ( | |
| github.event_name == 'workflow_dispatch' | |
| ) || | |
| ( | |
| github.event_name == 'issue_comment' && | |
| github.event.issue.pull_request && | |
| contains(github.event.comment.body, '/deploy') && | |
| ( | |
| github.event.comment.author_association == 'OWNER' || | |
| github.event.comment.author_association == 'MEMBER' || | |
| github.event.comment.author_association == 'COLLABORATOR' | |
| ) | |
| ) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| steps: | |
| # --------------------------------------------------------- | |
| # Authenticate gh | |
| # --------------------------------------------------------- | |
| - name: Authenticate gh | |
| run: echo "${{ github.token }}" | gh auth login --with-token | |
| # --------------------------------------------------------- | |
| # React to command: 👀 | |
| # --------------------------------------------------------- | |
| - name: React to comment (👀) | |
| if: github.event_name == 'issue_comment' | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 | |
| with: | |
| token: ${{ github.token }} | |
| comment-id: ${{ github.event.comment.id }} | |
| reactions: eyes | |
| # --------------------------------------------------------- | |
| # Detect PR when running manually | |
| # --------------------------------------------------------- | |
| - name: Detect open PR for branch | |
| id: detect_pr | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| BRANCH="${{ github.ref_name }}" | |
| PR_NUMBER="$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number' || true)" | |
| { | |
| if [ -n "$PR_NUMBER" ]; then | |
| echo "pr_number=$PR_NUMBER" | |
| echo "has_pr=true" | |
| else | |
| echo "has_pr=false" | |
| fi | |
| } >> "$GITHUB_OUTPUT" | |
| # --------------------------------------------------------- | |
| # Extract PR branch from comment | |
| # --------------------------------------------------------- | |
| - uses: xt0rted/pull-request-comment-branch@e8b8daa837e8ea7331c0003c9c316a64c6d8b0b1 | |
| if: github.event_name == 'issue_comment' | |
| id: comment-branch | |
| # --------------------------------------------------------- | |
| # Setup configs (branch, actor, PR number) | |
| # --------------------------------------------------------- | |
| - name: Setup configurations | |
| id: setup | |
| env: | |
| COMMENT_BODY: ${{ github.event.comment.body }} | |
| run: | | |
| if [ "${{ github.event_name }}" = "issue_comment" ]; then | |
| { | |
| echo "name=${{ steps.comment-branch.outputs.head_ref }}" | |
| echo "actor=${{ github.event.comment.user.login }}" | |
| echo "pr_number=${{ github.event.issue.number }}" | |
| echo "has_pr=true" | |
| if printf '%s\n' "$COMMENT_BODY" | grep -Fqi -- '/deploy clean'; then | |
| echo "is_clean=true" | |
| else | |
| echo "is_clean=false" | |
| fi | |
| } >> "$GITHUB_OUTPUT" | |
| else | |
| { | |
| echo "name=${{ github.ref_name }}" | |
| echo "actor=${{ github.actor }}" | |
| echo "pr_number=${{ steps.detect_pr.outputs.pr_number }}" | |
| echo "has_pr=${{ steps.detect_pr.outputs.has_pr }}" | |
| echo "is_clean=false" | |
| } >> "$GITHUB_OUTPUT" | |
| fi | |
| # --------------------------------------------------------- | |
| # Remote: checkout, build, deploy | |
| # --------------------------------------------------------- | |
| - name: Remote build and deploy | |
| id: remote | |
| uses: appleboy/ssh-action@91f3272fc5907f4699dcf59761eb622a07342f5a | |
| with: | |
| host: ${{ secrets.NEEP_HOST }} | |
| username: root | |
| password: ${{ secrets.NEEP_PASS }} | |
| timeout: 300s | |
| command_timeout: 30m | |
| script: | | |
| set -euo pipefail | |
| : > /tmp/canary-deploy.log | |
| exec > >(tee /tmp/canary-deploy.log) 2>&1 | |
| CANARY_DIR=/opt/canary | |
| VCPKG_DIR="$HOME/vcpkg" | |
| BUILD_PRESET=linux-release | |
| BUILD_DIR="$CANARY_DIR/build/$BUILD_PRESET" | |
| BRANCH="${{ steps.setup.outputs.name }}" | |
| IS_CLEAN="${{ steps.setup.outputs.is_clean }}" | |
| HAS_PR="${{ steps.setup.outputs.has_pr }}" | |
| PR_NUMBER="${{ steps.setup.outputs.pr_number }}" | |
| export VCPKG_ROOT="$VCPKG_DIR" | |
| export PATH="$VCPKG_DIR:$PATH" | |
| echo "=== [1/7] Checking out branch: $BRANCH ===" | |
| cd "$CANARY_DIR" | |
| git fetch origin | |
| if [ "$HAS_PR" = "true" ] && [ -n "$PR_NUMBER" ]; then | |
| # PR head may live in a fork; use the GitHub PR ref so this works | |
| # for both same-repo and fork PRs. | |
| git fetch origin "+refs/pull/${PR_NUMBER}/head:refs/remotes/pr/${PR_NUMBER}" | |
| git checkout -B "$BRANCH" "refs/remotes/pr/${PR_NUMBER}" | |
| git reset --hard "refs/remotes/pr/${PR_NUMBER}" | |
| else | |
| git checkout "$BRANCH" 2>/dev/null || git checkout -b "$BRANCH" | |
| git reset --hard "origin/$BRANCH" | |
| fi | |
| git clean -fdx --exclude=build --exclude=config.lua | |
| echo "=== [2/7] Updating vcpkg ===" | |
| if [ ! -d "$VCPKG_DIR/.git" ]; then | |
| echo "ERROR: $VCPKG_DIR is not a git clone of vcpkg" | |
| exit 1 | |
| fi | |
| git -C "$VCPKG_DIR" fetch --tags origin | |
| git -C "$VCPKG_DIR" reset --hard origin/master | |
| "$VCPKG_DIR/bootstrap-vcpkg.sh" -disableMetrics | |
| echo "=== [3/7] Preparing build ===" | |
| if [ "$IS_CLEAN" = "true" ]; then | |
| echo "'/deploy clean' command detected. Removing $BUILD_DIR..." | |
| rm -rf "$BUILD_DIR" | |
| else | |
| echo "Reusing $BUILD_DIR if it exists..." | |
| fi | |
| echo "=== [4/7] Configuring CMake ===" | |
| cmake --preset "$BUILD_PRESET" -DTOGGLE_BIN_FOLDER=ON | |
| echo "=== [5/7] Compiling ===" | |
| cmake --build --preset "$BUILD_PRESET" | |
| echo "=== [6/7] Deploying binary ===" | |
| stopped_canary=false | |
| restore_canary() { | |
| if [ "$stopped_canary" = "true" ]; then | |
| systemctl start canary || true | |
| fi | |
| } | |
| trap restore_canary EXIT | |
| if systemctl is-active --quiet canary; then | |
| systemctl stop canary | |
| stopped_canary=true | |
| fi | |
| sleep 3 | |
| if systemctl is-active --quiet canary; then | |
| echo "ERROR: canary service is still running after stop!" | |
| exit 1 | |
| fi | |
| install -m 0755 "$BUILD_DIR/bin/canary" "$CANARY_DIR/canary" | |
| ESCAPED_BRANCH="$(printf '%s\n' "$BRANCH" | sed 's/[\/&]/\\&/g')" | |
| sed -i "s/^serverMotd = \".*\"/serverMotd = \"Welcome to the Canary Test Server! Currently running branch: $ESCAPED_BRANCH\"/" "$CANARY_DIR/config.lua" | |
| echo "=== [7/7] Updating configs and starting service ===" | |
| echo "Updating $CANARY_DIR/data/stages.lua" | |
| cat << 'EOF' > "$CANARY_DIR/data/stages.lua" | |
| -- Minlevel and multiplier are MANDATORY | |
| -- Maxlevel is OPTIONAL, but is considered infinite by default | |
| -- Create a stage with minlevel 1 and no maxlevel to disable stages | |
| experienceStages = { | |
| { | |
| minlevel = 1, | |
| maxlevel = 8, | |
| multiplier = 50 | |
| }, | |
| { | |
| minlevel = 8, | |
| maxlevel = 100, | |
| multiplier = 300 | |
| }, | |
| { | |
| minlevel = 101, | |
| maxlevel = 200, | |
| multiplier = 250 | |
| }, | |
| { | |
| minlevel = 201, | |
| maxlevel = 300, | |
| multiplier = 200 | |
| }, | |
| { | |
| minlevel = 301, | |
| maxlevel = 400, | |
| multiplier = 150 | |
| }, | |
| { | |
| minlevel = 401, | |
| maxlevel = 500, | |
| multiplier = 100 | |
| }, | |
| { | |
| minlevel = 501, | |
| maxlevel = 600, | |
| multiplier = 80 | |
| }, | |
| { | |
| minlevel = 601, | |
| maxlevel = 700, | |
| multiplier = 60 | |
| }, | |
| { | |
| minlevel = 701, | |
| maxlevel = 800, | |
| multiplier = 40 | |
| }, | |
| { | |
| minlevel = 801, | |
| maxlevel = 900, | |
| multiplier = 20 | |
| }, | |
| { | |
| minlevel = 901, | |
| maxlevel = 1000, | |
| multiplier = 15 | |
| }, | |
| { | |
| minlevel = 1001, | |
| multiplier = 10 | |
| }, | |
| } | |
| skillsStages = { | |
| { | |
| minlevel = 10, | |
| maxlevel = 50, | |
| multiplier = 50 | |
| }, | |
| { | |
| minlevel = 51, | |
| maxlevel = 80, | |
| multiplier = 40 | |
| }, | |
| { | |
| minlevel = 81, | |
| maxlevel = 100, | |
| multiplier = 20 | |
| }, | |
| { | |
| minlevel = 101, | |
| maxlevel = 110, | |
| multiplier = 15 | |
| }, | |
| { | |
| minlevel = 111, | |
| multiplier = 10 | |
| }, | |
| } | |
| magicLevelStages = { | |
| { | |
| minlevel = 0, | |
| maxlevel = 60, | |
| multiplier = 30 | |
| }, | |
| { | |
| minlevel = 61, | |
| maxlevel = 80, | |
| multiplier = 25 | |
| }, | |
| { | |
| minlevel = 81, | |
| maxlevel = 100, | |
| multiplier = 20 | |
| }, | |
| { | |
| minlevel = 101, | |
| maxlevel = 110, | |
| multiplier = 15 | |
| }, | |
| { | |
| minlevel = 111, | |
| maxlevel = 120, | |
| multiplier = 10 | |
| }, | |
| { | |
| minlevel = 121, | |
| multiplier = 2 | |
| }, | |
| } | |
| EOF | |
| echo "Updating $CANARY_DIR/data/XML/vocations.xml" | |
| cat << 'EOF' > "$CANARY_DIR/data/XML/vocations.xml" | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <vocations> | |
| <vocation id="0" clientid="0" baseid="0" name="None" description="none" magicshield="0" gaincap="10" gainhp="5" gainmana="5" gainhpticks="4000" gainhpamount="5" gainmanaticks="4000" gainmanaamount="5" manamultiplier="4.0" attackspeed="2000" basespeed="110" soulmax="100" gainsoulticks="120000" fromvoc="0"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.3" primaryShield="2.05" secondaryShield="1.25" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.5" /> | |
| <skill id="1" multiplier="2.0" /> | |
| <skill id="2" multiplier="2.0" /> | |
| <skill id="3" multiplier="2.0" /> | |
| <skill id="4" multiplier="2.0" /> | |
| <skill id="5" multiplier="1.5" /> | |
| <skill id="6" multiplier="1.1" /> | |
| </vocation> | |
| <vocation id="1" clientid="3" baseid="1" name="Sorcerer" description="a sorcerer" magicshield="1" gaincap="10" gainhp="5" gainmana="30" gainhpticks="4000" gainhpamount="5" gainmanaticks="4000" gainmanaamount="10" manamultiplier="1.1" attackspeed="2000" basespeed="110" soulmax="100" gainsoulticks="120000" fromvoc="1" avatarlooktype="1595"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.26" primaryShield="2.0" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.5" /> | |
| <skill id="1" multiplier="2.0" /> | |
| <skill id="2" multiplier="2.0" /> | |
| <skill id="3" multiplier="2.0" /> | |
| <skill id="4" multiplier="2.0" /> | |
| <skill id="5" multiplier="1.5" /> | |
| <skill id="6" multiplier="1.1" /> | |
| </vocation> | |
| <vocation id="2" clientid="4" baseid="2" name="Druid" description="a druid" magicshield="1" gaincap="10" gainhp="5" gainmana="30" gainhpticks="4000" gainhpamount="5" gainmanaticks="4000" gainmanaamount="10" manamultiplier="1.1" attackspeed="2000" basespeed="110" soulmax="100" gainsoulticks="120000" fromvoc="2" avatarlooktype="1596"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.26" primaryShield="2.0" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.5" /> | |
| <skill id="1" multiplier="1.8" /> | |
| <skill id="2" multiplier="1.8" /> | |
| <skill id="3" multiplier="1.8" /> | |
| <skill id="4" multiplier="1.8" /> | |
| <skill id="5" multiplier="1.5" /> | |
| <skill id="6" multiplier="1.1" /> | |
| </vocation> | |
| <vocation id="3" clientid="2" baseid="3" name="Paladin" description="a paladin" magicshield="0" gaincap="20" gainhp="10" gainmana="15" gainhpticks="4000" gainhpamount="8" gainmanaticks="4000" gainmanaamount="8" manamultiplier="1.4" attackspeed="2000" basespeed="110" soulmax="100" gainsoulticks="120000" fromvoc="3" avatarlooktype="1594"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.28" primaryShield="2.08" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.2" /> | |
| <skill id="1" multiplier="1.2" /> | |
| <skill id="2" multiplier="1.2" /> | |
| <skill id="3" multiplier="1.2" /> | |
| <skill id="4" multiplier="1.1" /> | |
| <skill id="5" multiplier="1.1" /> | |
| <skill id="6" multiplier="1.1" /> | |
| </vocation> | |
| <vocation id="4" clientid="1" baseid="4" name="Knight" description="a knight" magicshield="0" gaincap="25" gainhp="15" gainmana="5" gainhpticks="4000" gainhpamount="10" gainmanaticks="4000" gainmanaamount="5" manamultiplier="3.0" attackspeed="2000" basespeed="110" soulmax="100" gainsoulticks="120000" fromvoc="4" avatarlooktype="1593"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.3" primaryShield="2.05" secondaryShield="1.25" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.1" /> | |
| <skill id="1" multiplier="1.1" /> | |
| <skill id="2" multiplier="1.1" /> | |
| <skill id="3" multiplier="1.1" /> | |
| <skill id="4" multiplier="1.4" /> | |
| <skill id="5" multiplier="1.1" /> | |
| <skill id="6" multiplier="1.1" /> | |
| </vocation> | |
| <vocation id="5" clientid="13" baseid="1" name="Master Sorcerer" description="a master sorcerer" magicshield="1" gaincap="10" gainhp="5" gainmana="30" gainhpticks="3000" gainhpamount="15" gainmanaticks="2000" gainmanaamount="25" manamultiplier="1.1" attackspeed="2000" basespeed="110" soulmax="200" gainsoulticks="15000" fromvoc="1" avatarlooktype="1595"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.26" primaryShield="2.0" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.5" /> | |
| <skill id="1" multiplier="2.0" /> | |
| <skill id="2" multiplier="2.0" /> | |
| <skill id="3" multiplier="2.0" /> | |
| <skill id="4" multiplier="2.0" /> | |
| <skill id="5" multiplier="1.5" /> | |
| <skill id="6" multiplier="1.1" /> | |
| <gem quality="0" name="lesser sage gem" /> | |
| <gem quality="1" name="sage gem" /> | |
| <gem quality="2" name="greater sage gem" /> | |
| </vocation> | |
| <vocation id="6" clientid="14" baseid="2" name="Elder Druid" description="an elder druid" magicshield="1" gaincap="10" gainhp="5" gainmana="30" gainhpticks="3000" gainhpamount="15" gainmanaticks="2000" gainmanaamount="25" manamultiplier="1.1" attackspeed="2000" basespeed="110" soulmax="200" gainsoulticks="15000" fromvoc="2" avatarlooktype="1596"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.26" primaryShield="2.0" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.5" /> | |
| <skill id="1" multiplier="1.8" /> | |
| <skill id="2" multiplier="1.8" /> | |
| <skill id="3" multiplier="1.8" /> | |
| <skill id="4" multiplier="1.8" /> | |
| <skill id="5" multiplier="1.5" /> | |
| <skill id="6" multiplier="1.1" /> | |
| <gem quality="0" name="lesser mystic gem" /> | |
| <gem quality="1" name="mystic gem" /> | |
| <gem quality="2" name="greater mystic gem" /> | |
| </vocation> | |
| <vocation id="7" clientid="12" baseid="3" name="Royal Paladin" description="a royal paladin" magicshield="0" gaincap="20" gainhp="10" gainmana="15" gainhpticks="2000" gainhpamount="20" gainmanaticks="3000" gainmanaamount="15" manamultiplier="1.4" attackspeed="2000" basespeed="110" soulmax="200" gainsoulticks="15000" fromvoc="3" avatarlooktype="1594"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.28" primaryShield="2.08" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.2" /> | |
| <skill id="1" multiplier="1.2" /> | |
| <skill id="2" multiplier="1.2" /> | |
| <skill id="3" multiplier="1.2" /> | |
| <skill id="4" multiplier="1.1" /> | |
| <skill id="5" multiplier="1.1" /> | |
| <skill id="6" multiplier="1.1" /> | |
| <gem quality="0" name="lesser marksman gem" /> | |
| <gem quality="1" name="marksman gem" /> | |
| <gem quality="2" name="greater marksman gem" /> | |
| </vocation> | |
| <vocation id="8" clientid="11" baseid="4" name="Elite Knight" description="an elite knight" magicshield="0" gaincap="25" gainhp="15" gainmana="5" gainhpticks="2000" gainhpamount="25" gainmanaticks="3000" gainmanaamount="10" manamultiplier="3.0" attackspeed="2000" basespeed="110" soulmax="200" gainsoulticks="15000" fromvoc="4" avatarlooktype="1593"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.3" primaryShield="2.05" secondaryShield="1.25" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.4" /> | |
| <skill id="1" multiplier="1.1" /> | |
| <skill id="2" multiplier="1.1" /> | |
| <skill id="3" multiplier="1.1" /> | |
| <skill id="4" multiplier="1.1" /> | |
| <skill id="5" multiplier="1.1" /> | |
| <skill id="6" multiplier="1.1" /> | |
| <gem quality="0" name="lesser guardian gem" /> | |
| <gem quality="1" name="guardian gem" /> | |
| <gem quality="2" name="greater guardian gem" /> | |
| </vocation> | |
| <vocation id="9" clientid="5" baseid="9" name="Monk" description="a monk" magicshield="0" gaincap="25" gainhp="10" gainmana="10" gainhpticks="4000" gainhpamount="8" gainmanaticks="4000" gainmanaamount="8" manamultiplier="1.3" attackspeed="2000" basespeed="110" soulmax="100" gainsoulticks="120000" fromvoc="9" avatarlooktype="1831"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.28" primaryShield="2.08" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.1" /> <!-- fist --> | |
| <skill id="1" multiplier="1.5" /> | |
| <skill id="2" multiplier="1.5" /> | |
| <skill id="3" multiplier="1.5" /> | |
| <skill id="4" multiplier="2.0" /> | |
| <skill id="5" multiplier="1.2" /> | |
| <skill id="6" multiplier="1.1" /> | |
| </vocation> | |
| <vocation id="10" clientid="15" baseid="9" name="Exalted Monk" description="an exalted monk" magicshield="0" gaincap="25" gainhp="10" gainmana="10" gainhpticks="2000" gainhpamount="15" gainmanaticks="3000" gainmanaamount="20" manamultiplier="1.3" attackspeed="2000" basespeed="110" soulmax="200" gainsoulticks="15000" fromvoc="9" avatarlooktype="1831"> | |
| <formula meleeDamage="1.0" distDamage="1.0" defense="1.0" armor="1.0" /> | |
| <mitigation multiplier="1.28" primaryShield="2.08" secondaryShield="1.2" /> | |
| <pvp damageReceivedMultiplier="1.0" damageDealtMultiplier ="1.0"/> | |
| <skill id="0" multiplier="1.1" /> <!-- fist --> | |
| <skill id="1" multiplier="1.5" /> | |
| <skill id="2" multiplier="1.5" /> | |
| <skill id="3" multiplier="1.5" /> | |
| <skill id="4" multiplier="2.0" /> | |
| <skill id="5" multiplier="1.2" /> | |
| <skill id="6" multiplier="1.1" /> | |
| <gem quality="0" name="lesser spiritualist gem" /> | |
| <gem quality="1" name="spiritualist gem" /> | |
| <gem quality="2" name="greater spiritualist gem" /> | |
| </vocation> | |
| </vocations> | |
| EOF | |
| systemctl start canary | |
| sleep 3 | |
| if ! systemctl is-active --quiet canary; then | |
| echo "ERROR: canary service is not running after start!" | |
| systemctl status canary --no-pager || true | |
| exit 1 | |
| fi | |
| trap - EXIT | |
| echo "DEPLOY_SUCCESS=true" | |
| # --------------------------------------------------------- | |
| # On failure, fetch the tail of the remote deploy log over a | |
| # second SSH session. This keeps the captured output small | |
| # (well under ARG_MAX and under GitHub's ~65k comment limit) | |
| # without piping the full multi-MB build log through env vars. | |
| # --------------------------------------------------------- | |
| - name: Fetch remote deploy log tail | |
| if: always() && steps.remote.outcome != 'success' && steps.setup.outputs.has_pr == 'true' | |
| id: fetch_log | |
| uses: appleboy/ssh-action@91f3272fc5907f4699dcf59761eb622a07342f5a | |
| with: | |
| host: ${{ secrets.NEEP_HOST }} | |
| username: root | |
| password: ${{ secrets.NEEP_PASS }} | |
| timeout: 60s | |
| command_timeout: 60s | |
| capture_stdout: true | |
| script: tail -c 50000 /tmp/canary-deploy.log 2>/dev/null || echo "(no deploy log on remote)" | |
| # --------------------------------------------------------- | |
| # Success or failure comment | |
| # --------------------------------------------------------- | |
| - name: Post deploy result | |
| if: always() && steps.remote.outcome == 'success' && steps.setup.outputs.has_pr == 'true' | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 | |
| with: | |
| issue-number: ${{ steps.setup.outputs.pr_number }} | |
| body: | | |
| ✅ **Deploy successful!** | |
| **Branch:** `${{ steps.setup.outputs.name }}` | |
| **Build:** Compiled on remote server | |
| *(Triggered by @${{ steps.setup.outputs.actor }})* | |
| - name: Post failure feedback | |
| if: always() && steps.remote.outcome != 'success' && steps.setup.outputs.has_pr == 'true' | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 | |
| with: | |
| issue-number: ${{ steps.setup.outputs.pr_number }} | |
| body: | | |
| ❌ **Deploy failed!** | |
| **Branch:** `${{ steps.setup.outputs.name }}` | |
| **Last build output (tail, max 50KB):** | |
| <details><summary>Click to expand</summary> | |
| ```` | |
| ${{ steps.fetch_log.outputs.stdout }} | |
| ```` | |
| </details> | |
| *(Triggered by @${{ steps.setup.outputs.actor }})* | |
| # --------------------------------------------------------- | |
| # React with emojis | |
| # --------------------------------------------------------- | |
| - name: React success | |
| if: always() && github.event_name == 'issue_comment' && steps.remote.outcome == 'success' | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 | |
| with: | |
| comment-id: ${{ github.event.comment.id }} | |
| reactions: hooray | |
| - name: React failure | |
| if: always() && github.event_name == 'issue_comment' && steps.remote.outcome != 'success' | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 | |
| with: | |
| comment-id: ${{ github.event.comment.id }} | |
| reactions: "-1" |