Compare commits
24 Commits
dd9799d8b3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7102f0f553 | ||
|
|
da2466462e | ||
|
|
77f3326868 | ||
|
|
2dbe8c8a74 | ||
|
|
c163d00f51 | ||
|
|
5e92ea62ef | ||
|
|
f80c2a2518 | ||
|
|
6de184968d | ||
|
|
be710b920e | ||
|
|
d59e55a54e | ||
|
|
53f84e2647 | ||
|
|
86c0180c3f | ||
|
|
f8e9c95403 | ||
|
|
793846e7f5 | ||
|
|
29d2dbbb57 | ||
|
|
0acac8799d | ||
|
|
39a850b064 | ||
|
|
90e805a360 | ||
|
|
f700a3454e | ||
|
|
0d1278b9ac | ||
|
|
639ac23efa | ||
|
|
297299c3f8 | ||
|
|
2f2ae074f5 | ||
|
|
2c96d29c6f |
32
.claude/settings.local.json
Normal file
32
.claude/settings.local.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(curl -m 10 -s -o /dev/null -w \"%{http_code}\" -H \"Connection: Upgrade\" -H \"Upgrade: websocket\" https://windmill.keinafarm.net/ws/)",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" -t claude@keinafarm.net \"cat /home/windmill/windmill/docker-compose.yml\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"docker exec windmill_server cat /workspace/docker-compose.yml\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"docker compose --project-directory /home/windmill/windmill version 2>&1\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"docker compose --project-directory /home/windmill/windmill ps 2>&1\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"docker exec windmill_server cat /workspace/.env\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"docker network inspect traefik-net --format ''{{json .Name}}'' && docker network connect traefik-net windmill-windmill_extra-1 && echo ''Connected successfully''\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"docker exec windmill_server cat /workspace/docker-compose.yml > /tmp/windmill-compose.yml && cat /tmp/windmill-compose.yml | wc -l\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"grep -A 20 ''windmill_extra:'' /tmp/windmill-compose-fixed.yml | grep -E ''\\(traefik-net|windmill-lsp.service|windmill-debug.service\\)''\")",
|
||||||
|
"Bash(ssh -i \"/c/Users/akira/.ssh/ssh-key-20241206.pem\" akira@keinafarm.net \"grep -n ''windmill-lsp\\\\|windmill-debug\\\\|traefik-net'' /tmp/windmill-compose-fixed.yml\")",
|
||||||
|
"Bash(ssh -i:*)",
|
||||||
|
"WebFetch(domain:github.com)",
|
||||||
|
"Bash(python -c \"from mcp.server.fastmcp import FastMCP; print\\(''mcp OK''\\)\")",
|
||||||
|
"Bash(pip install mcp httpx)",
|
||||||
|
"Bash(WINDMILL_TOKEN=qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh python -c \":*)",
|
||||||
|
"Read(//c/Users/akira/.claude/**)",
|
||||||
|
"Bash(git add .gitignore mcp/)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"mcp__windmill__windmill_list_flows"
|
||||||
|
],
|
||||||
|
"additionalDirectories": [
|
||||||
|
"C:\\Users\\akira\\Develop\\windmill",
|
||||||
|
"C:\\Users\\akira\\.claude\\projects\\c--Users-akira-Develop-windmill\\memory\\"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enabledMcpjsonServers": [
|
||||||
|
"windmill"
|
||||||
|
]
|
||||||
|
}
|
||||||
9
.env
9
.env
@@ -1,9 +1,14 @@
|
|||||||
DATABASE_URL=postgres://postgres:changeme@db/windmill?sslmode=disable
|
DATABASE_PASSWORD=DbForWindMillPassword
|
||||||
|
WM_VERSION=1.638.0
|
||||||
|
|
||||||
|
DATABASE_URL=postgres://postgres:${DATABASE_PASSWORD}@db/windmill?sslmode=disable
|
||||||
|
|
||||||
# For Enterprise Edition, use:
|
# For Enterprise Edition, use:
|
||||||
# WM_IMAGE=ghcr.io/windmill-labs/windmill-ee:main
|
# WM_IMAGE=ghcr.io/windmill-labs/windmill-ee:main
|
||||||
WM_IMAGE=ghcr.io/windmill-labs/windmill:main
|
WM_IMAGE=ghcr.io/windmill-labs/windmill:${WM_VERSION}
|
||||||
|
|
||||||
|
GOOGLE_OAUTH_CLIENT_ID=976427934311-6oj0l38ptn6ui2hoj37qbs137lcnu6kg.apps.googleusercontent.com
|
||||||
|
GOOGLE_OAUTH_CLIENT_SECRET=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
|
||||||
|
|
||||||
# To use another port than :80, setup the Caddyfile and the caddy section of the docker-compose to your needs: https://caddyserver.com/docs/getting-started
|
# To use another port than :80, setup the Caddyfile and the caddy section of the docker-compose to your needs: https://caddyserver.com/docs/getting-started
|
||||||
# To have caddy take care of automatic TLS
|
# To have caddy take care of automatic TLS
|
||||||
|
|||||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -29,6 +29,9 @@ Thumbs.db
|
|||||||
*.bak
|
*.bak
|
||||||
*~
|
*~
|
||||||
|
|
||||||
|
# MCP server config (contains API tokens)
|
||||||
|
.mcp.json
|
||||||
|
|
||||||
# Resolved markdown files (generated by editor)
|
# Resolved markdown files (generated by editor)
|
||||||
*.resolved
|
*.resolved
|
||||||
*.resolved.*
|
*.resolved.*
|
||||||
@@ -46,3 +49,11 @@ workflows/.wmill/tmp/
|
|||||||
!workflows/g/
|
!workflows/g/
|
||||||
!workflows/wmill.yaml
|
!workflows/wmill.yaml
|
||||||
!workflows/wmill-lock.yaml
|
!workflows/wmill-lock.yaml
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
|
# Windmill workflow definitions (managed by git_sync on sync branch)
|
||||||
|
# Local working directory should not track these on main
|
||||||
|
u/
|
||||||
|
workflows/f/
|
||||||
|
workflows/u/
|
||||||
|
workflows/g/
|
||||||
|
|||||||
12
Caddyfile.local
Normal file
12
Caddyfile.local
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
:80 {
|
||||||
|
# LSP - Language Server Protocol for code intelligence
|
||||||
|
reverse_proxy /ws/* http://windmill_extra:3001
|
||||||
|
|
||||||
|
# Debugger - Interactive debugging via DAP WebSocket
|
||||||
|
handle_path /ws_debug/* {
|
||||||
|
reverse_proxy http://windmill_extra:3003
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default: Windmill server
|
||||||
|
reverse_proxy /* http://windmill_server:8000
|
||||||
|
}
|
||||||
112
HANDOFF.md
Normal file
112
HANDOFF.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Windmill 作業引き継ぎメモ
|
||||||
|
|
||||||
|
> 作成: 2026-02-25(keinasystem_t02 セッションから移管)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 現在の状態
|
||||||
|
|
||||||
|
### git_sync フロー(修正済み ✅)
|
||||||
|
|
||||||
|
**問題**: `u/antigravity/git_sync` フローが `wmill sync pull` で認証エラー
|
||||||
|
**原因**: `$WM_TOKEN`(ジョブトークン)はワークスペーススコープのため、
|
||||||
|
wmill CLIが内部で呼ぶ `/api/users/whoami`(グローバルAPI)で401
|
||||||
|
**解決**:
|
||||||
|
- `/home/windmill/windmill/wmill_config/remotes.ndjson` を作成(永続設定)
|
||||||
|
- グローバルスコープトークン `CQKYm1bUwszHCT4Ww6TGyQX97XMs8qg8`(ラベル: `git-sync`)を使用
|
||||||
|
- フロースクリプトを `--config-dir /workspace/wmill_config` を使う形に修正
|
||||||
|
- 動作確認: Success: True (2秒) ✅
|
||||||
|
|
||||||
|
### windmill.keinafarm.net 外部アクセス(504 未修正 ❌)
|
||||||
|
|
||||||
|
- 外部からアクセスすると 30秒後に 504 Gateway Timeout
|
||||||
|
- サーバー内部からは `http://localhost:8000` で正常にアクセスできる
|
||||||
|
- **Caddyfile がこのディレクトリにある** → 原因調査・修正が必要
|
||||||
|
|
||||||
|
### Windmill MCP サーバー(未着手 ⬜)
|
||||||
|
|
||||||
|
- LLM(Claude)が直接 Windmill を操作できるようにする
|
||||||
|
- 外部アクセスが直れば `https://windmill.keinafarm.net` に接続
|
||||||
|
- 直らない場合は SSH トンネル経由
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 重要な情報
|
||||||
|
|
||||||
|
### サーバー接続
|
||||||
|
|
||||||
|
```
|
||||||
|
SSH: root@keinafarm.net
|
||||||
|
Windmill内部URL: http://localhost:8000
|
||||||
|
Windmillサーバー上のパス: /home/windmill/windmill/
|
||||||
|
```
|
||||||
|
|
||||||
|
### API トークン
|
||||||
|
|
||||||
|
| トークン | スコープ | 用途 |
|
||||||
|
|---------|---------|------|
|
||||||
|
| `qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh` | ワークスペース(admins) | 通常のAPI操作 |
|
||||||
|
| `CQKYm1bUwszHCT4Ww6TGyQX97XMs8qg8` | グローバル | git-sync用(wmill CLI) |
|
||||||
|
|
||||||
|
### 2つの Git リポジトリ(別物!)
|
||||||
|
|
||||||
|
| リポジトリ | パス | 用途 |
|
||||||
|
|-----------|------|------|
|
||||||
|
| `windmill.git` (Gitea) | サーバー `/home/windmill/windmill/` | wmill CLI で自動同期 |
|
||||||
|
| `windmill_workflow.git` (Gitea) | ローカル `C:\Users\akira\Develop\windmill` | このディレクトリ |
|
||||||
|
|
||||||
|
### wmill_config(永続設定)
|
||||||
|
|
||||||
|
```
|
||||||
|
サーバーパス: /home/windmill/windmill/wmill_config/
|
||||||
|
コンテナ内パス: /workspace/wmill_config/
|
||||||
|
remotes.ndjson: {"remote":"http://windmill_server:8000/","workspaceId":"admins","name":"admins","token":"CQKYm1bUwszHCT4Ww6TGyQX97XMs8qg8"}
|
||||||
|
activeWorkspace: admins
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 次にやること(優先順)
|
||||||
|
|
||||||
|
### 1. windmill.keinafarm.net 504 を修正
|
||||||
|
|
||||||
|
`Caddyfile` を確認して、windmill へのリバースプロキシ設定を見直す。
|
||||||
|
タイムアウト設定が足りない可能性が高い。
|
||||||
|
|
||||||
|
```
|
||||||
|
# 確認コマンド(サーバー内部では正常)
|
||||||
|
ssh root@keinafarm.net "curl -s http://localhost:8000/api/version"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Windmill MCP サーバーを実装
|
||||||
|
|
||||||
|
**方針**: カスタム軽量 Python MCP サーバー(6〜8 tools)
|
||||||
|
|
||||||
|
実装する tools:
|
||||||
|
- `windmill_list_flows` — フロー一覧
|
||||||
|
- `windmill_get_flow` — フローのスクリプト取得
|
||||||
|
- `windmill_run_flow` — フローをトリガー
|
||||||
|
- `windmill_list_recent_jobs` — 最近のジョブ一覧(成功/失敗)
|
||||||
|
- `windmill_get_job_logs` — ジョブの詳細ログ
|
||||||
|
- `windmill_list_scripts` — スクリプト一覧
|
||||||
|
- `windmill_get_script` — スクリプト取得
|
||||||
|
|
||||||
|
既存実装: `rothnic/windmill-mcp`(GitHub, スター0, 更新停止)→ 使わず自作
|
||||||
|
|
||||||
|
### 3. mail_filter.flow.json をコミット
|
||||||
|
|
||||||
|
ローカルの `windmill_workflow` に `f/mail/mail_filter.flow.json` が未コミット状態。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考: wmill 設定ファイル形式
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.config/windmill/remotes.ndjson (1行1ワークスペース)
|
||||||
|
{"remote":"http://...../","workspaceId":"...","name":"local_alias","token":"..."}
|
||||||
|
|
||||||
|
~/.config/windmill/activeWorkspace (プレーンテキスト)
|
||||||
|
local_alias
|
||||||
|
```
|
||||||
|
|
||||||
|
`wmill sync pull --config-dir /path/to/config` で任意ディレクトリを指定可能。
|
||||||
155
SERVER_SETUP.md
Normal file
155
SERVER_SETUP.md
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# Windmill サーバー設定手順 (VPS移行版)
|
||||||
|
|
||||||
|
本番環境(VPS)へのデプロイ手順です。
|
||||||
|
既にTraefikが稼働している環境(`traefik-net` ネットワークが存在する環境)を前提としています。
|
||||||
|
|
||||||
|
## 前提条件
|
||||||
|
|
||||||
|
- サーバー上でTraefikが稼働しており、`traefik-net` ネットワークが存在すること。
|
||||||
|
- ドメイン `windmill.keinafarm.net` がサーバーのIPに向けられていること。
|
||||||
|
|
||||||
|
## ステップ1: リポジトリの準備
|
||||||
|
|
||||||
|
サーバー上の任意の場所(例: `/home/windmill/windmill`)にリポジトリをクローンします。
|
||||||
|
**重要**: WindmillのGit同期機能を使用するため、このディレクトリパスは重要です。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /home/windmill
|
||||||
|
cd /home/windmill
|
||||||
|
git clone https://gitea.keinafarm.net/akira/windmill.git windmill
|
||||||
|
cd windmill
|
||||||
|
```
|
||||||
|
|
||||||
|
## ステップ2: 環境変数の設定
|
||||||
|
|
||||||
|
`.env` ファイルを作成し、本番用の設定を行います。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env .env.production
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
以下の内容を確認・修正してください:
|
||||||
|
- `DATABASE_URL`: `postgres://postgres:あなたの強力なパスワード@db/windmill?sslmode=disable`
|
||||||
|
- `POSTGRES_PASSWORD`: 上記と同じパスワード
|
||||||
|
- `WM_IMAGE`: `ghcr.io/windmill-labs/windmill:main`
|
||||||
|
|
||||||
|
## ステップ3: 起動
|
||||||
|
|
||||||
|
`docker-compose.yml` は本番用に構成されています(Traefik連携済み)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## ステップ4: Git同期用ワークフローのセットアップ
|
||||||
|
|
||||||
|
Windmill上で「登録されたワークフローをGitに保存する」機能を有効にする手順です。
|
||||||
|
`git_sync` フローが定期実行されると、Windmill DB上のスクリプト/フローの変更がGiteaリポジトリに自動コミット&プッシュされます。
|
||||||
|
|
||||||
|
### 4-1. Windmill APIトークンの取得
|
||||||
|
|
||||||
|
1. ブラウザで `https://windmill.keinafarm.net` にログイン
|
||||||
|
2. 左下の **Settings** → **Account** をクリック
|
||||||
|
3. **Tokens** セクションで **Create token** をクリック
|
||||||
|
4. Label(例: `git-sync`)を入力し、作成
|
||||||
|
5. 表示されたトークンをコピーしておく(後のステップで使用)
|
||||||
|
|
||||||
|
### 4-2. ワークフロー定義の取り込み(初回のみ)
|
||||||
|
|
||||||
|
リポジトリの `workflows/` にある定義ファイルをWindmill DBに取り込みます。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windmillサーバーコンテナに入る
|
||||||
|
docker exec -it windmill_server /bin/bash
|
||||||
|
|
||||||
|
# コンテナ内で実行:windmill-cli をインストール
|
||||||
|
npm install -g windmill-cli
|
||||||
|
|
||||||
|
# wmill.yamlがあるディレクトリに移動して sync push
|
||||||
|
cd /workspace/workflows
|
||||||
|
wmill sync push \
|
||||||
|
--token "<4-1で取得したトークン>" \
|
||||||
|
--base-url "http://localhost:8000" \
|
||||||
|
--workspace admins \
|
||||||
|
--yes
|
||||||
|
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意**: `wmill sync push` はディスク→DBへの反映です。
|
||||||
|
> 逆に `wmill sync pull` はDB→ディスクへの反映です。
|
||||||
|
> スケジュールされた `git_sync` フローが `sync pull` を実行するため、
|
||||||
|
> **UIで直接スクリプトを修正した場合、次回の sync pull で正しくディスクにも反映されます。**
|
||||||
|
|
||||||
|
### 4-3. Gitea認証情報の設定(git push用)
|
||||||
|
|
||||||
|
`git_sync` フローが Gitea へ `git push` できるよう、サーバー上のリモートURLにGiteaのアクセストークンを含めます。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# サーバーのホスト側で実行
|
||||||
|
cd ~/windmill
|
||||||
|
|
||||||
|
# 現在のリモートURLを確認
|
||||||
|
git remote -v
|
||||||
|
|
||||||
|
# Giteaのアクセストークンを含んだURLに変更
|
||||||
|
git remote set-url origin https://<username>:<giteaトークン>@gitea.keinafarm.net/akira/windmill.git
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Giteaトークンの作成方法**: Gitea(`https://gitea.keinafarm.net`)にログイン →
|
||||||
|
> 右上アバター → Settings → Applications → Generate New Token
|
||||||
|
|
||||||
|
### 4-4. WM_TOKEN Variable の設定
|
||||||
|
|
||||||
|
WindmillのWeb画面で、`git_sync` フローが使用する変数を登録します。
|
||||||
|
|
||||||
|
1. 左メニューの **Variables** をクリック
|
||||||
|
2. **+ Variable** をクリック
|
||||||
|
3. 以下を入力:
|
||||||
|
- **Path**: `u/antigravity/wm_token`
|
||||||
|
- **Value**: 4-1で取得したWindmill APIトークン
|
||||||
|
- **Is Secret**: ✅ オン
|
||||||
|
4. **Save** をクリック
|
||||||
|
|
||||||
|
> **注意**: `git_sync` フローのスクリプト(`a.sh`)内で `$WM_TOKEN` として参照されます。
|
||||||
|
> フローのInput設定で、この変数が正しく紐づけられていることを確認してください。
|
||||||
|
|
||||||
|
### 4-5. git_sync フローの手動実行テスト
|
||||||
|
|
||||||
|
1. Windmill UI で **`u/antigravity/git_sync`** フローを開く
|
||||||
|
2. **Run** ボタンで手動実行
|
||||||
|
3. **Runs** ページで実行ログを確認
|
||||||
|
4. 成功すれば、Giteaリポジトリに自動コミットが作成されているはず
|
||||||
|
|
||||||
|
### 4-6. スケジュール実行の確認
|
||||||
|
|
||||||
|
`git_sync.schedule.yaml` により、2分ごとに自動実行されるスケジュールが登録されています。
|
||||||
|
左メニューの **Schedules** から、スケジュールが有効になっていることを確認してください。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## トラブルシューティング
|
||||||
|
|
||||||
|
### ディスク上のファイルが古い内容に戻る
|
||||||
|
`git_sync` フローが `wmill sync pull`(DB→ディスク)を実行するため、UIで修正した内容がディスクに上書きされます。
|
||||||
|
スクリプトの修正は **Windmill UI上で直接編集** するのが確実です。
|
||||||
|
|
||||||
|
### git push が失敗する
|
||||||
|
```bash
|
||||||
|
# サーバー上でリモートURLにトークンが含まれているか確認
|
||||||
|
cd ~/windmill
|
||||||
|
git remote -v
|
||||||
|
# https://<user>:<token>@gitea.keinafarm.net/... の形式であること
|
||||||
|
```
|
||||||
|
|
||||||
|
### 開発環境(ローカル)での起動
|
||||||
|
ローカルで起動する場合は `docker-compose-dev.yml` を使用します:
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose-dev.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### ログ確認
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
152
docker-compose-dev.yml
Normal file
152
docker-compose-dev.yml
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
x-logging: &default-logging
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "${LOG_MAX_SIZE:-20m}"
|
||||||
|
max-file: "${LOG_MAX_FILE:-10}"
|
||||||
|
compress: "true"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
windmill-internal:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
image: postgres:16
|
||||||
|
shm_size: 1g
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/postgresql/data
|
||||||
|
expose:
|
||||||
|
- 5432
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
|
POSTGRES_DB: windmill
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
logging: *default-logging
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
|
||||||
|
windmill_server:
|
||||||
|
image: ${WM_IMAGE}
|
||||||
|
container_name: windmill_server
|
||||||
|
pull_policy: if_not_present
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
restart: unless-stopped
|
||||||
|
expose:
|
||||||
|
- 8000
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
|
- MODE=server
|
||||||
|
- BASE_URL=http://localhost
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
logging: *default-logging
|
||||||
|
|
||||||
|
windmill_worker:
|
||||||
|
image: ${WM_IMAGE}
|
||||||
|
pull_policy: if_not_present
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: "1"
|
||||||
|
memory: 2048M
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
|
- MODE=worker
|
||||||
|
- WORKER_GROUP=default
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- worker_dependency_cache:/tmp/windmill/cache
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
logging: *default-logging
|
||||||
|
|
||||||
|
windmill_worker_native:
|
||||||
|
image: ${WM_IMAGE}
|
||||||
|
pull_policy: if_not_present
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: "1"
|
||||||
|
memory: 2048M
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
|
- MODE=worker
|
||||||
|
- WORKER_GROUP=native
|
||||||
|
- NUM_WORKERS=8
|
||||||
|
- SLEEP_QUEUE=200
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
logging: *default-logging
|
||||||
|
|
||||||
|
windmill_extra:
|
||||||
|
image: ghcr.io/windmill-labs/windmill-extra:${WM_VERSION}
|
||||||
|
pull_policy: if_not_present
|
||||||
|
restart: unless-stopped
|
||||||
|
expose:
|
||||||
|
- 3001
|
||||||
|
- 3003
|
||||||
|
environment:
|
||||||
|
- ENABLE_LSP=true
|
||||||
|
- ENABLE_MULTIPLAYER=false
|
||||||
|
- ENABLE_DEBUGGER=true
|
||||||
|
- DEBUGGER_PORT=3003
|
||||||
|
- ENABLE_NSJAIL=false
|
||||||
|
- REQUIRE_SIGNED_DEBUG_REQUESTS=false
|
||||||
|
- WINDMILL_BASE_URL=http://windmill_server:8000
|
||||||
|
volumes:
|
||||||
|
- lsp_cache:/pyls/.cache
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
logging: *default-logging
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:2.9-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile.local:/etc/caddy/Caddyfile
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
logging: *default-logging
|
||||||
|
depends_on:
|
||||||
|
- windmill_server
|
||||||
|
- windmill_extra
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data: null
|
||||||
|
worker_dependency_cache: null
|
||||||
|
worker_logs: null
|
||||||
|
lsp_cache: null
|
||||||
|
caddy_data: null
|
||||||
|
caddy_config: null
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
version: "3.7"
|
|
||||||
|
|
||||||
x-logging: &default-logging
|
x-logging: &default-logging
|
||||||
driver: "json-file"
|
driver: "json-file"
|
||||||
options:
|
options:
|
||||||
@@ -7,10 +5,15 @@ x-logging: &default-logging
|
|||||||
max-file: "${LOG_MAX_FILE:-10}"
|
max-file: "${LOG_MAX_FILE:-10}"
|
||||||
compress: "true"
|
compress: "true"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik-net:
|
||||||
|
external: true # サーバー上の既存Traefikネットワーク
|
||||||
|
windmill-internal:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
services:
|
services:
|
||||||
db:
|
db:
|
||||||
deploy:
|
deploy:
|
||||||
# To use an external database, set replicas to 0 and set DATABASE_URL to the external database url in the .env file
|
|
||||||
replicas: 1
|
replicas: 1
|
||||||
image: postgres:16
|
image: postgres:16
|
||||||
shm_size: 1g
|
shm_size: 1g
|
||||||
@@ -20,7 +23,7 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- 5432
|
- 5432
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: changeme
|
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
POSTGRES_DB: windmill
|
POSTGRES_DB: windmill
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
|
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
|
||||||
@@ -28,197 +31,172 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
|
|
||||||
windmill_server:
|
windmill_server:
|
||||||
image: ${WM_IMAGE}
|
image: ${WM_IMAGE}
|
||||||
pull_policy: always
|
container_name: windmill_server
|
||||||
|
pull_policy: if_not_present
|
||||||
deploy:
|
deploy:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- 8000
|
- 8000
|
||||||
- 2525
|
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
- MODE=server
|
- MODE=server
|
||||||
|
- BASE_URL=https://windmill.keinafarm.net
|
||||||
|
- OAUTH_REDIRECT_BASE_URL=https://windmill.keinafarm.net
|
||||||
|
- GOOGLE_OAUTH_ENABLED=true
|
||||||
|
- GOOGLE_OAUTH_CLIENT_ID=${GOOGLE_OAUTH_CLIENT_ID}
|
||||||
|
- GOOGLE_OAUTH_CLIENT_SECRET=${GOOGLE_OAUTH_CLIENT_SECRET}
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- worker_logs:/tmp/windmill/logs
|
- worker_logs:/tmp/windmill/logs
|
||||||
- /home/akira/develop/windmill:/workspace
|
# Git同期のために、カレントディレクトリ(リポジトリルート)を/workspaceにマウント
|
||||||
|
# これにより、コンテナ内から .git ディレクトリにアクセス可能となり、git pushが可能になる
|
||||||
|
- .:/workspace
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# HTTPSルーター
|
||||||
|
- "traefik.http.routers.windmill.rule=Host(`windmill.keinafarm.net`)"
|
||||||
|
- "traefik.http.routers.windmill.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.windmill.tls=true"
|
||||||
|
- "traefik.http.routers.windmill.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.windmill.loadbalancer.server.port=8000"
|
||||||
|
# HTTPからHTTPSへのリダイレクト
|
||||||
|
- "traefik.http.routers.windmill-http.rule=Host(`windmill.keinafarm.net`)"
|
||||||
|
- "traefik.http.routers.windmill-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.windmill-http.middlewares=windmill-https-redirect"
|
||||||
|
- "traefik.http.middlewares.windmill-https-redirect.redirectscheme.scheme=https"
|
||||||
|
networks:
|
||||||
|
- traefik-net
|
||||||
|
- windmill-internal
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
|
||||||
windmill_worker:
|
windmill_worker:
|
||||||
image: ${WM_IMAGE}
|
image: ${WM_IMAGE}
|
||||||
pull_policy: always
|
pull_policy: if_not_present
|
||||||
deploy:
|
deploy:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpus: "1"
|
cpus: "1"
|
||||||
memory: 2048M
|
memory: 2048M
|
||||||
# for GB, use syntax '2Gi'
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# Uncomment to enable PID namespace isolation (recommended for security)
|
|
||||||
# Requires privileged mode for --mount-proc flag
|
|
||||||
# See: https://www.windmill.dev/docs/advanced/security_isolation
|
|
||||||
# privileged: true
|
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
- MODE=worker
|
- MODE=worker
|
||||||
- WORKER_GROUP=default
|
- WORKER_GROUP=default
|
||||||
# If running with non-root/non-windmill UID (e.g., user: "1001:1001"),
|
|
||||||
# add: - HOME=/tmp
|
|
||||||
# Uncomment to enable PID namespace isolation (requires privileged: true above)
|
|
||||||
# - ENABLE_UNSHARE_PID=true
|
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
# to mount the worker folder to debug, KEEP_JOB_DIR=true and mount /tmp/windmill
|
|
||||||
volumes:
|
volumes:
|
||||||
# mount the docker socket to allow to run docker containers from within the workers
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- worker_dependency_cache:/tmp/windmill/cache
|
- worker_dependency_cache:/tmp/windmill/cache
|
||||||
- worker_logs:/tmp/windmill/logs
|
- worker_logs:/tmp/windmill/logs
|
||||||
# mount the windmill workspace directory for git sync workflow
|
# WorkerからもGit同期が必要な場合に備えてマウント
|
||||||
- /home/akira/develop/windmill:/workspace
|
- .:/workspace
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
|
||||||
## This worker is specialized for "native" jobs. Native jobs run in-process and thus are much more lightweight than other jobs
|
|
||||||
windmill_worker_native:
|
windmill_worker_native:
|
||||||
# Use ghcr.io/windmill-labs/windmill-ee:main for the ee
|
|
||||||
image: ${WM_IMAGE}
|
image: ${WM_IMAGE}
|
||||||
pull_policy: always
|
pull_policy: if_not_present
|
||||||
deploy:
|
deploy:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpus: "1"
|
cpus: "1"
|
||||||
memory: 2048M
|
memory: 2048M
|
||||||
# for GB, use syntax '2Gi'
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# Uncomment to enable PID namespace isolation (recommended for security)
|
|
||||||
# Requires privileged mode for --mount-proc flag
|
|
||||||
# See: https://www.windmill.dev/docs/advanced/security_isolation
|
|
||||||
# privileged: true
|
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
- MODE=worker
|
- MODE=worker
|
||||||
- WORKER_GROUP=native
|
- WORKER_GROUP=native
|
||||||
- NUM_WORKERS=8
|
- NUM_WORKERS=8
|
||||||
- SLEEP_QUEUE=200
|
- SLEEP_QUEUE=200
|
||||||
# Uncomment to enable PID namespace isolation (requires privileged: true above)
|
|
||||||
# - ENABLE_UNSHARE_PID=true
|
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- worker_logs:/tmp/windmill/logs
|
- worker_logs:/tmp/windmill/logs
|
||||||
logging: *default-logging
|
networks:
|
||||||
# This worker is specialized for reports or scraping jobs. It is assigned the "reports" worker group which has an init script that installs chromium and can be targeted by using the "chromium" worker tag.
|
- windmill-internal
|
||||||
# windmill_worker_reports:
|
|
||||||
# image: ${WM_IMAGE}
|
|
||||||
# pull_policy: always
|
|
||||||
# deploy:
|
|
||||||
# replicas: 1
|
|
||||||
# resources:
|
|
||||||
# limits:
|
|
||||||
# cpus: "1"
|
|
||||||
# memory: 2048M
|
|
||||||
# # for GB, use syntax '2Gi'
|
|
||||||
# restart: unless-stopped
|
|
||||||
# # Uncomment to enable PID namespace isolation (recommended for security)
|
|
||||||
# # Requires privileged mode for --mount-proc flag
|
|
||||||
# # See: https://www.windmill.dev/docs/advanced/security_isolation
|
|
||||||
# # privileged: true
|
|
||||||
# environment:
|
|
||||||
# - DATABASE_URL=${DATABASE_URL}
|
|
||||||
# - MODE=worker
|
|
||||||
# - WORKER_GROUP=reports
|
|
||||||
# # Uncomment to enable PID namespace isolation (requires privileged: true above)
|
|
||||||
# # - ENABLE_UNSHARE_PID=true
|
|
||||||
# depends_on:
|
|
||||||
# db:
|
|
||||||
# condition: service_healthy
|
|
||||||
# # to mount the worker folder to debug, KEEP_JOB_DIR=true and mount /tmp/windmill
|
|
||||||
# volumes:
|
|
||||||
# # mount the docker socket to allow to run docker containers from within the workers
|
|
||||||
# - /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
# - worker_dependency_cache:/tmp/windmill/cache
|
|
||||||
# - worker_logs:/tmp/windmill/logs
|
|
||||||
|
|
||||||
# The indexer powers full-text job and log search, an EE feature.
|
|
||||||
windmill_indexer:
|
|
||||||
image: ${WM_IMAGE}
|
|
||||||
pull_policy: always
|
|
||||||
deploy:
|
|
||||||
replicas: 0 # set to 1 to enable full-text job and log search
|
|
||||||
restart: unless-stopped
|
|
||||||
expose:
|
|
||||||
- 8002
|
|
||||||
environment:
|
|
||||||
- PORT=8002
|
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
|
||||||
- MODE=indexer
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
volumes:
|
|
||||||
- windmill_index:/tmp/windmill/search
|
|
||||||
- worker_logs:/tmp/windmill/logs
|
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
|
||||||
# Combined extra services: LSP, Multiplayer, and Debugger
|
|
||||||
# Each service can be enabled/disabled via environment variables:
|
|
||||||
# - ENABLE_LSP=true (default) - Language Server Protocol for code intelligence
|
|
||||||
# - ENABLE_MULTIPLAYER=false - Real-time collaboration (Enterprise Edition)
|
|
||||||
# - ENABLE_DEBUGGER=false - Interactive debugging via DAP WebSocket
|
|
||||||
windmill_extra:
|
windmill_extra:
|
||||||
image: ghcr.io/windmill-labs/windmill-extra:latest
|
image: ghcr.io/windmill-labs/windmill-extra:${WM_VERSION}
|
||||||
pull_policy: always
|
pull_policy: if_not_present
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- 3001 # LSP
|
- 3001
|
||||||
- 3002 # Multiplayer
|
- 3002
|
||||||
- 3003 # Debugger
|
- 3003
|
||||||
environment:
|
environment:
|
||||||
- ENABLE_LSP=true
|
- ENABLE_LSP=true
|
||||||
- ENABLE_MULTIPLAYER=false # Set to true to enable multiplayer (Enterprise Edition)
|
- ENABLE_MULTIPLAYER=false
|
||||||
- ENABLE_DEBUGGER=true # Set to true to enable debugger
|
- ENABLE_DEBUGGER=true
|
||||||
- DEBUGGER_PORT=3003 # Debugger service port
|
- DEBUGGER_PORT=3003
|
||||||
- ENABLE_NSJAIL=false # Set to true for nsjail sandboxing (requires privileged: true)
|
- ENABLE_NSJAIL=false
|
||||||
- REQUIRE_SIGNED_DEBUG_REQUESTS=false # Set to true to require JWT tokens for debug sessions
|
- REQUIRE_SIGNED_DEBUG_REQUESTS=false
|
||||||
- WINDMILL_BASE_URL=http://windmill_server:8000
|
- WINDMILL_BASE_URL=http://windmill_server:8000
|
||||||
volumes:
|
volumes:
|
||||||
- lsp_cache:/pyls/.cache
|
- lsp_cache:/pyls/.cache
|
||||||
|
networks:
|
||||||
|
- windmill-internal
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
labels:
|
||||||
|
# LSPなどのWebSocket用設定(Caddyfileの代替)
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# LSPへのルーティング (/ws/* -> 3001)
|
||||||
|
- "traefik.http.routers.windmill-lsp.rule=Host(`windmill.keinafarm.net`) && PathPrefix(`/ws/`)"
|
||||||
|
- "traefik.http.routers.windmill-lsp.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.windmill-lsp.tls=true"
|
||||||
|
- "traefik.http.services.windmill-lsp.loadbalancer.server.port=3001"
|
||||||
|
# Debuggerへのルーティング (/ws_debug/* -> 3003)
|
||||||
|
- "traefik.http.routers.windmill-debug.rule=Host(`windmill.keinafarm.net`) && PathPrefix(`/ws_debug/`)"
|
||||||
|
- "traefik.http.routers.windmill-debug.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.windmill-debug.tls=true"
|
||||||
|
- "traefik.http.services.windmill-debug.loadbalancer.server.port=3003"
|
||||||
|
|
||||||
caddy:
|
windmill_mcp:
|
||||||
image: ghcr.io/windmill-labs/caddy-l4:latest
|
build:
|
||||||
|
context: ./mcp
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: windmill_mcp
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# Configure the mounted Caddyfile and the exposed ports or use another reverse proxy if needed
|
expose:
|
||||||
volumes:
|
- 8001
|
||||||
- ./Caddyfile:/etc/caddy/Caddyfile
|
|
||||||
- caddy_data:/data
|
|
||||||
# - ./certs:/certs # Provide custom certificate files like cert.pem and key.pem to enable HTTPS - See the corresponding section in the Caddyfile
|
|
||||||
ports:
|
|
||||||
# To change the exposed port, simply change 80:80 to <desired_port>:80. No other changes needed
|
|
||||||
- 80:80
|
|
||||||
- 25:25
|
|
||||||
# - 443:443 # Uncomment to enable HTTPS handling by Caddy
|
|
||||||
environment:
|
environment:
|
||||||
- BASE_URL=":80"
|
- WINDMILL_TOKEN=${WINDMILL_TOKEN}
|
||||||
# - BASE_URL=":443" # uncomment and comment line above to enable HTTPS via custom certificate and key files
|
- WINDMILL_URL=https://windmill.keinafarm.net
|
||||||
# - BASE_URL=mydomain.com # Uncomment and comment line above to enable HTTPS handling by Caddy
|
- WINDMILL_WORKSPACE=admins
|
||||||
|
- MCP_TRANSPORT=sse
|
||||||
|
- MCP_HOST=0.0.0.0
|
||||||
|
- MCP_PORT=8001
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# HTTPS ルーター
|
||||||
|
- "traefik.http.routers.windmill-mcp.rule=Host(`windmill-mcp.keinafarm.net`)"
|
||||||
|
- "traefik.http.routers.windmill-mcp.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.windmill-mcp.tls=true"
|
||||||
|
- "traefik.http.routers.windmill-mcp.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.windmill-mcp.loadbalancer.server.port=8001"
|
||||||
|
# HTTP → HTTPS リダイレクト
|
||||||
|
- "traefik.http.routers.windmill-mcp-http.rule=Host(`windmill-mcp.keinafarm.net`)"
|
||||||
|
- "traefik.http.routers.windmill-mcp-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.windmill-mcp-http.middlewares=windmill-https-redirect"
|
||||||
|
networks:
|
||||||
|
- traefik-net
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
db_data: null
|
db_data: null
|
||||||
worker_dependency_cache: null
|
worker_dependency_cache: null
|
||||||
worker_logs: null
|
worker_logs: null
|
||||||
worker_memory: null
|
|
||||||
windmill_index: null
|
|
||||||
lsp_cache: null
|
lsp_cache: null
|
||||||
caddy_data: null
|
|
||||||
|
|||||||
5
env.host
Normal file
5
env.host
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
WM_IMAGE=ghcr.io/windmill-labs/windmill:main
|
||||||
|
POSTGRES_PASSWORD=MyS3cur3P@ssw0rd!2024
|
||||||
|
DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/windmill
|
||||||
|
LOG_MAX_SIZE=20m
|
||||||
|
LOG_MAX_FILE=10
|
||||||
12
mcp/.env.example
Normal file
12
mcp/.env.example
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Windmill MCP Server の設定
|
||||||
|
# このファイルを .env にコピーして値を設定してください
|
||||||
|
|
||||||
|
# Windmill のベース URL(デフォルト: https://windmill.keinafarm.net)
|
||||||
|
WINDMILL_URL=https://windmill.keinafarm.net
|
||||||
|
|
||||||
|
# Windmill API トークン(必須)
|
||||||
|
# Windmill の「設定 > トークン」から作成してください
|
||||||
|
WINDMILL_TOKEN=your_token_here
|
||||||
|
|
||||||
|
# 対象ワークスペース(デフォルト: admins)
|
||||||
|
WINDMILL_WORKSPACE=admins
|
||||||
14
mcp/Dockerfile
Normal file
14
mcp/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY windmill_mcp.py .
|
||||||
|
|
||||||
|
ENV MCP_TRANSPORT=sse
|
||||||
|
ENV MCP_HOST=0.0.0.0
|
||||||
|
ENV MCP_PORT=8001
|
||||||
|
|
||||||
|
CMD ["python", "windmill_mcp.py"]
|
||||||
14
mcp/claude_mcp_config.json
Normal file
14
mcp/claude_mcp_config.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"windmill": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["windmill_mcp.py"],
|
||||||
|
"cwd": "/path/to/mcp",
|
||||||
|
"env": {
|
||||||
|
"WINDMILL_TOKEN": "your_api_token_here",
|
||||||
|
"WINDMILL_URL": "https://windmill.keinafarm.net",
|
||||||
|
"WINDMILL_WORKSPACE": "admins"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
mcp/requirements.txt
Normal file
2
mcp/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mcp>=1.0.0
|
||||||
|
httpx>=0.27.0
|
||||||
343
mcp/windmill_mcp.py
Normal file
343
mcp/windmill_mcp.py
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Windmill MCP Server - Claude が Windmill を直接操作できるようにする"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import httpx
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
WINDMILL_URL = os.environ.get("WINDMILL_URL", "https://windmill.keinafarm.net")
|
||||||
|
WINDMILL_TOKEN = os.environ.get("WINDMILL_TOKEN", "")
|
||||||
|
WINDMILL_WORKSPACE = os.environ.get("WINDMILL_WORKSPACE", "admins")
|
||||||
|
MCP_HOST = os.environ.get("MCP_HOST", "127.0.0.1")
|
||||||
|
MCP_PORT = int(os.environ.get("MCP_PORT", "8001"))
|
||||||
|
|
||||||
|
if not WINDMILL_TOKEN:
|
||||||
|
print("Error: WINDMILL_TOKEN 環境変数が設定されていません", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
mcp = FastMCP("windmill", host=MCP_HOST, port=MCP_PORT)
|
||||||
|
|
||||||
|
|
||||||
|
def _headers() -> dict:
|
||||||
|
return {"Authorization": f"Bearer {WINDMILL_TOKEN}"}
|
||||||
|
|
||||||
|
|
||||||
|
def _api(path: str) -> str:
|
||||||
|
return f"{WINDMILL_URL}/api/w/{WINDMILL_WORKSPACE}/{path}"
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_list_flows(per_page: int = 20) -> str:
|
||||||
|
"""Windmill のフロー一覧を取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
per_page: 取得件数(最大100)
|
||||||
|
"""
|
||||||
|
resp = httpx.get(
|
||||||
|
_api("flows/list"),
|
||||||
|
headers=_headers(),
|
||||||
|
params={"per_page": min(per_page, 100)},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
flows = resp.json()
|
||||||
|
if not flows:
|
||||||
|
return "フローが見つかりませんでした"
|
||||||
|
lines = [
|
||||||
|
f"- {f['path']}: {f.get('summary', '(概要なし)')}" for f in flows
|
||||||
|
]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_get_flow(path: str) -> str:
|
||||||
|
"""指定したパスのフロー定義(スクリプト含む)を取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: フローのパス (例: u/antigravity/git_sync)
|
||||||
|
"""
|
||||||
|
resp = httpx.get(_api(f"flows/get/{path}"), headers=_headers(), timeout=30)
|
||||||
|
resp.raise_for_status()
|
||||||
|
return json.dumps(resp.json(), indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_run_flow(path: str, args: str = "{}") -> str:
|
||||||
|
"""フローをトリガーして実行する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: フローのパス (例: u/antigravity/git_sync)
|
||||||
|
args: JSON形式の入力引数 (例: {"key": "value"})
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
args_dict = json.loads(args)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
return f"Error: argsのJSON形式が不正です: {e}"
|
||||||
|
|
||||||
|
resp = httpx.post(
|
||||||
|
_api(f"jobs/run/f/{path}"),
|
||||||
|
headers=_headers(),
|
||||||
|
json=args_dict,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
job_id = resp.text.strip().strip('"')
|
||||||
|
return (
|
||||||
|
f"フローを開始しました。\n"
|
||||||
|
f"ジョブID: {job_id}\n"
|
||||||
|
f"詳細URL: {WINDMILL_URL}/run/{job_id}?workspace={WINDMILL_WORKSPACE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_list_recent_jobs(
|
||||||
|
limit: int = 20,
|
||||||
|
success_only: bool = False,
|
||||||
|
failure_only: bool = False,
|
||||||
|
script_path_filter: str = "",
|
||||||
|
) -> str:
|
||||||
|
"""最近のジョブ一覧を取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
limit: 取得件数(最大100)
|
||||||
|
success_only: Trueにすると成功ジョブのみ表示
|
||||||
|
failure_only: Trueにすると失敗ジョブのみ表示
|
||||||
|
script_path_filter: パスで絞り込む (例: u/antigravity/git_sync)
|
||||||
|
"""
|
||||||
|
params: dict = {"per_page": min(limit, 100)}
|
||||||
|
if success_only:
|
||||||
|
params["success"] = "true"
|
||||||
|
if failure_only:
|
||||||
|
params["success"] = "false"
|
||||||
|
if script_path_filter:
|
||||||
|
params["script_path_filter"] = script_path_filter
|
||||||
|
|
||||||
|
resp = httpx.get(_api("jobs/list"), headers=_headers(), params=params, timeout=30)
|
||||||
|
resp.raise_for_status()
|
||||||
|
jobs = resp.json()
|
||||||
|
if not jobs:
|
||||||
|
return "ジョブが見つかりませんでした"
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for j in jobs:
|
||||||
|
success = j.get("success")
|
||||||
|
if success is True:
|
||||||
|
status = "[OK]"
|
||||||
|
elif success is False:
|
||||||
|
status = "[FAIL]"
|
||||||
|
else:
|
||||||
|
status = "[RUNNING]"
|
||||||
|
path = j.get("script_path", "unknown")
|
||||||
|
started = (j.get("started_at") or "")[:19] or "pending"
|
||||||
|
job_id = j.get("id", "")
|
||||||
|
lines.append(f"{status} [{started}] {path} (ID: {job_id})")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_get_job_logs(job_id: str) -> str:
|
||||||
|
"""ジョブの詳細情報とログを取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
job_id: ジョブのID(windmill_list_recent_jobs で確認できる)
|
||||||
|
"""
|
||||||
|
resp = httpx.get(_api(f"jobs_u/get/{job_id}"), headers=_headers(), timeout=30)
|
||||||
|
resp.raise_for_status()
|
||||||
|
job = resp.json()
|
||||||
|
|
||||||
|
success = job.get("success")
|
||||||
|
if success is True:
|
||||||
|
state = "成功 [OK]"
|
||||||
|
elif success is False:
|
||||||
|
state = "失敗 [FAIL]"
|
||||||
|
else:
|
||||||
|
state = "実行中 [RUNNING]"
|
||||||
|
|
||||||
|
result_parts = [
|
||||||
|
f"ジョブID: {job_id}",
|
||||||
|
f"パス: {job.get('script_path', 'N/A')}",
|
||||||
|
f"状態: {state}",
|
||||||
|
f"開始: {job.get('started_at', 'N/A')}",
|
||||||
|
f"終了: {job.get('created_at', 'N/A')}",
|
||||||
|
]
|
||||||
|
|
||||||
|
log_resp = httpx.get(
|
||||||
|
_api(f"jobs_u/getlogs/{job_id}"), headers=_headers(), timeout=30
|
||||||
|
)
|
||||||
|
if log_resp.status_code == 200:
|
||||||
|
result_parts.append("\n--- ログ ---")
|
||||||
|
result_parts.append(log_resp.text)
|
||||||
|
|
||||||
|
result_val = job.get("result")
|
||||||
|
if result_val is not None:
|
||||||
|
result_parts.append("\n--- 実行結果 ---")
|
||||||
|
result_parts.append(
|
||||||
|
json.dumps(result_val, indent=2, ensure_ascii=False)
|
||||||
|
if isinstance(result_val, (dict, list))
|
||||||
|
else str(result_val)
|
||||||
|
)
|
||||||
|
|
||||||
|
return "\n".join(result_parts)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_create_flow(path: str, summary: str, flow_definition: str, description: str = "") -> str:
|
||||||
|
"""新しいフローを作成する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: フローのパス (例: u/admin/my_flow)
|
||||||
|
summary: フローの概要
|
||||||
|
flow_definition: フローの定義 (JSON形式の文字列)
|
||||||
|
description: フローの詳細説明 (省略可)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
flow_value = json.loads(flow_definition)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
return f"Error: flow_definitionのJSON形式が不正です: {e}"
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"path": path,
|
||||||
|
"summary": summary,
|
||||||
|
"description": description,
|
||||||
|
"value": flow_value,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = httpx.post(
|
||||||
|
_api("flows/create"),
|
||||||
|
headers=_headers(),
|
||||||
|
json=payload,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
return (
|
||||||
|
f"フローを作成しました。\n"
|
||||||
|
f"パス: {path}\n"
|
||||||
|
f"URL: {WINDMILL_URL}/flows/edit/{path}?workspace={WINDMILL_WORKSPACE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_update_flow(path: str, summary: str, flow_definition: str, description: str = "") -> str:
|
||||||
|
"""既存のフローを更新する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: フローのパス (例: u/admin/my_flow)
|
||||||
|
summary: フローの概要
|
||||||
|
flow_definition: フローの定義 (JSON形式の文字列)
|
||||||
|
description: フローの詳細説明 (省略可)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
flow_value = json.loads(flow_definition)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
return f"Error: flow_definitionのJSON形式が不正です: {e}"
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"path": path,
|
||||||
|
"summary": summary,
|
||||||
|
"description": description,
|
||||||
|
"value": flow_value,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = httpx.post(
|
||||||
|
_api(f"flows/update/{path}"),
|
||||||
|
headers=_headers(),
|
||||||
|
json=payload,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
return (
|
||||||
|
f"フローを更新しました。\n"
|
||||||
|
f"パス: {path}\n"
|
||||||
|
f"URL: {WINDMILL_URL}/flows/edit/{path}?workspace={WINDMILL_WORKSPACE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_create_script(
|
||||||
|
path: str, language: str, content: str, summary: str = "", description: str = ""
|
||||||
|
) -> str:
|
||||||
|
"""新しいスクリプトを作成する(既存パスの場合は新バージョンを登録する)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: スクリプトのパス (例: u/admin/my_script)
|
||||||
|
language: 言語 (python3, deno, bun, bash など)
|
||||||
|
content: スクリプトのソースコード
|
||||||
|
summary: スクリプトの概要 (省略可)
|
||||||
|
description: スクリプトの詳細説明 (省略可)
|
||||||
|
"""
|
||||||
|
payload = {
|
||||||
|
"path": path,
|
||||||
|
"language": language,
|
||||||
|
"content": content,
|
||||||
|
"summary": summary,
|
||||||
|
"description": description,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = httpx.post(
|
||||||
|
_api("scripts/create"),
|
||||||
|
headers=_headers(),
|
||||||
|
json=payload,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
hash_val = resp.text.strip().strip('"')
|
||||||
|
return (
|
||||||
|
f"スクリプトを作成しました。\n"
|
||||||
|
f"パス: {path}\n"
|
||||||
|
f"ハッシュ: {hash_val}\n"
|
||||||
|
f"URL: {WINDMILL_URL}/scripts/edit/{path}?workspace={WINDMILL_WORKSPACE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_list_scripts(per_page: int = 20) -> str:
|
||||||
|
"""Windmill のスクリプト一覧を取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
per_page: 取得件数(最大100)
|
||||||
|
"""
|
||||||
|
resp = httpx.get(
|
||||||
|
_api("scripts/list"),
|
||||||
|
headers=_headers(),
|
||||||
|
params={"per_page": min(per_page, 100)},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
scripts = resp.json()
|
||||||
|
if not scripts:
|
||||||
|
return "スクリプトが見つかりませんでした"
|
||||||
|
lines = [
|
||||||
|
f"- {s['path']} [{s.get('language', '?')}]: {s.get('summary', '(概要なし)')}"
|
||||||
|
for s in scripts
|
||||||
|
]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def windmill_get_script(path: str) -> str:
|
||||||
|
"""指定したパスのスクリプトのソースコードを取得する
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: スクリプトのパス (例: u/antigravity/test_git_sync)
|
||||||
|
"""
|
||||||
|
resp = httpx.get(_api(f"scripts/get/{path}"), headers=_headers(), timeout=30)
|
||||||
|
resp.raise_for_status()
|
||||||
|
script = resp.json()
|
||||||
|
|
||||||
|
result_parts = [
|
||||||
|
f"パス: {script.get('path', 'N/A')}",
|
||||||
|
f"言語: {script.get('language', 'N/A')}",
|
||||||
|
f"概要: {script.get('summary', 'N/A')}",
|
||||||
|
"",
|
||||||
|
"--- コード ---",
|
||||||
|
script.get("content", "(コードなし)"),
|
||||||
|
]
|
||||||
|
return "\n".join(result_parts)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
transport = os.environ.get("MCP_TRANSPORT", "stdio")
|
||||||
|
mcp.run(transport=transport)
|
||||||
@@ -5,19 +5,34 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# 色付き出力
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'#!/bin/bash
|
||||||
|
|
||||||
|
# Windmill Workflow Git Auto-Sync Script for Gitea
|
||||||
|
# このスクリプトは、Windmillワークフローを自動的にGiteaにコミット&プッシュします
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
# 色付き出力
|
# 色付き出力
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
echo -e "${GREEN}=== Windmill Workflow Git Sync ===${NC}"
|
echo -e "${GREEN}=== Windmill Workflow Git Sync (Gitea) ===${NC}"
|
||||||
|
|
||||||
# ディレクトリに移動
|
# 作業ディレクトリに移動
|
||||||
cd /home/akira/develop/windmill/workflows
|
cd /workspace
|
||||||
|
|
||||||
# PATHを設定
|
# PATHを設定
|
||||||
export PATH=~/.npm-global/bin:$PATH
|
export PATH=~/.npm-global/bin:$PATH
|
||||||
|
|
||||||
|
# Git設定(safe.directoryエラー対策)
|
||||||
|
git config --global --add safe.directory /workspace
|
||||||
|
git config --global user.email "bot@example.com"
|
||||||
|
git config --global user.name "Windmill Bot"
|
||||||
|
|
||||||
# Windmillから最新を取得
|
# Windmillから最新を取得
|
||||||
echo -e "${YELLOW}Pulling from Windmill...${NC}"
|
echo -e "${YELLOW}Pulling from Windmill...${NC}"
|
||||||
wmill sync pull --skip-variables --skip-secrets --skip-resources --yes
|
wmill sync pull --skip-variables --skip-secrets --skip-resources --yes
|
||||||
@@ -35,7 +50,17 @@ if [[ -n $(git status --porcelain) ]]; then
|
|||||||
|
|
||||||
Synced workflows from Windmill workspace"
|
Synced workflows from Windmill workspace"
|
||||||
|
|
||||||
echo -e "${GREEN}✓ Changes committed to Git${NC}"
|
|
||||||
|
# Giteaにプッシュ
|
||||||
|
echo -e "${YELLOW}Pushing to Gitea...${NC}"
|
||||||
|
git push origin main || {
|
||||||
|
echo -e "${RED}Failed to push to Gitea. Check credentials.${NC}"
|
||||||
|
# トークンや認証情報が設定されていない場合のヒント
|
||||||
|
echo -e "${YELLOW}Hint: Ensure you have set up git credentials or use a token in the remote URL.${NC}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓ Changes pushed to Gitea${NC}"
|
||||||
else
|
else
|
||||||
echo -e "${GREEN}✓ No changes detected${NC}"
|
echo -e "${GREEN}✓ No changes detected${NC}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,22 +1,68 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -x
|
set -e
|
||||||
export WM_BASE_URL="http://windmill_server:8000"
|
|
||||||
export WM_WORKSPACE="admins"
|
|
||||||
export PATH=$HOME/.npm-global/bin:$PATH
|
|
||||||
|
|
||||||
echo "=== START SYNC ==="
|
# 色付き出力
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}=== Windmill Workflow Git Sync ===${NC}"
|
||||||
|
|
||||||
|
# リポジトリルート(コンテナ内: docker-compose.ymlの .:/workspace マウント)
|
||||||
|
REPO_ROOT="/workspace"
|
||||||
|
# wmill.yamlがあるディレクトリ(Windmill CLIはここで実行する)
|
||||||
|
WMILL_DIR="${REPO_ROOT}/workflows"
|
||||||
|
|
||||||
|
# Windmill CLIのセットアップ
|
||||||
if ! command -v wmill &> /dev/null; then
|
if ! command -v wmill &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}Installing windmill-cli...${NC}"
|
||||||
npm install -g windmill-cli
|
npm install -g windmill-cli
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wmill sync pull --token "$WM_TOKEN" --base-url "$WM_BASE_URL" --workspace "$WM_WORKSPACE" --skip-variables --skip-secrets --skip-resources --yes --verbose || exit 1
|
# 環境変数チェック
|
||||||
|
if [ -z "$WM_TOKEN" ]; then
|
||||||
|
echo -e "${RED}Error: WM_TOKEN is not set.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# WM_BASE_URLはWindmill内で自動設定される場合があるが、念のため
|
||||||
|
: "${WM_BASE_URL:=http://windmill_server:8000}"
|
||||||
|
# Workspaceは環境変数または引数で
|
||||||
|
: "${WM_WORKSPACE:=admins}"
|
||||||
|
|
||||||
git config --global --add safe.directory /workspace
|
# Git設定(コンテナ内での一時設定)
|
||||||
git config --global user.email "bot@example.com"
|
git config --global --add safe.directory "$REPO_ROOT"
|
||||||
git config --global user.name "Bot"
|
git config --global user.email "bot@keinafarm.net"
|
||||||
|
git config --global user.name "Windmill Bot"
|
||||||
|
|
||||||
git add .
|
# 1. Windmill(DB) -> Local Disk(wmill.yamlがあるディレクトリで実行)
|
||||||
git commit -m "Auto-sync $(date)" || echo "No changes"
|
echo -e "${YELLOW}Pulling from Windmill...${NC}"
|
||||||
|
cd "$WMILL_DIR"
|
||||||
|
wmill sync pull --token "$WM_TOKEN" --base-url "$WM_BASE_URL" --workspace "$WM_WORKSPACE" --skip-variables --skip-secrets --skip-resources --yes || exit 1
|
||||||
|
|
||||||
echo "=== END SYNC ==="
|
# 2. Local Disk -> Git Remote(Gitリポジトリルートに戻ってgit操作)
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
if [[ -n $(git status --porcelain) ]]; then
|
||||||
|
echo -e "${YELLOW}Changes detected, committing to Git...${NC}"
|
||||||
|
|
||||||
|
git add -A
|
||||||
|
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
git commit -m "Auto-sync: ${TIMESTAMP}"
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Pushing to Gitea...${NC}"
|
||||||
|
# リモートの変更を先に取り込む(ローカルPCからのpushがある場合に備えて)
|
||||||
|
git pull --rebase origin main || {
|
||||||
|
echo -e "${RED}Failed to pull from remote. Trying push anyway...${NC}"
|
||||||
|
}
|
||||||
|
git push origin main || {
|
||||||
|
echo -e "${RED}Failed to push. Need credentials in git remote url or credential helper.${NC}"
|
||||||
|
echo -e "${YELLOW}Hint: git remote set-url origin https://<token>@gitea.keinafarm.net/...${NC}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓ Changes pushed to Gitea${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ No changes detected${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}=== Sync Complete ===${NC}"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
def main():
|
def main():
|
||||||
print("Hello from Git Sync Test")
|
print("Hello from Git Sync Test")
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user