Compare commits
188 Commits
react2
...
rf/warnRaw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06898b9837 | ||
|
|
8306e6e5d2 | ||
|
|
6c1e7eed51 | ||
|
|
f24894b1a5 | ||
|
|
50d78a979b | ||
|
|
c75fd751b0 | ||
|
|
f0f720f490 | ||
|
|
855571f359 | ||
|
|
41219e1f84 | ||
|
|
499fe7e7fe | ||
|
|
72613f3580 | ||
|
|
7d4ee825fa | ||
|
|
1cd253405d | ||
|
|
4dab80e24d | ||
|
|
38bb5e25cb | ||
|
|
3678bf976e | ||
|
|
6623972ee9 | ||
|
|
6a4391f616 | ||
|
|
f7a83c03c1 | ||
|
|
82f541565f | ||
|
|
44e1ed6c9c | ||
|
|
58ca3a6866 | ||
|
|
0b3a084c81 | ||
|
|
17c8c8a561 | ||
|
|
1a6283b42a | ||
|
|
126b610561 | ||
|
|
0b89260540 | ||
|
|
6c4818259c | ||
|
|
283167264e | ||
|
|
b3e7a9cb79 | ||
|
|
c3a54ddd7c | ||
|
|
ae684d8608 | ||
|
|
f077849b8f | ||
|
|
cf2d09e7a8 | ||
|
|
bb354cfeb8 | ||
|
|
bebfa76fc2 | ||
|
|
b0ac12052a | ||
|
|
f412ede6ed | ||
|
|
f94651115a | ||
|
|
6f907c79b4 | ||
|
|
6e7ea4111c | ||
|
|
ff9acb4717 | ||
|
|
a393c93085 | ||
|
|
23920aee84 | ||
|
|
d47c078bb5 | ||
|
|
b4a6a7e724 | ||
|
|
332f66e348 | ||
|
|
d2dfd27b88 | ||
|
|
b56a5c3e7a | ||
|
|
ae81b4f456 | ||
|
|
cd508951d7 | ||
|
|
94b56d3ffe | ||
|
|
cb8c3560af | ||
|
|
a47939d13c | ||
|
|
e8836a393a | ||
|
|
86adebde39 | ||
|
|
b44b9c1b82 | ||
|
|
d384bb8cb4 | ||
|
|
ec873c2c09 | ||
|
|
d37f13d023 | ||
|
|
a2eac4ae37 | ||
|
|
22b2f4988d | ||
|
|
13b318200b | ||
|
|
ec552d5ef6 | ||
|
|
3c3fdbdf26 | ||
|
|
571348377b | ||
|
|
9ae3212a1e | ||
|
|
6c3b1e7478 | ||
|
|
9695cef21a | ||
|
|
fe481e02bc | ||
|
|
5c38f0dbee | ||
|
|
4447fe9c88 | ||
|
|
67ab46990a | ||
|
|
fe4a767df0 | ||
|
|
df4992a929 | ||
|
|
6247d159ce | ||
|
|
1551dc8af2 | ||
|
|
b749e490b4 | ||
|
|
2c689e0666 | ||
|
|
a0b302d2c5 | ||
|
|
445be72b23 | ||
|
|
d86dcc6354 | ||
|
|
4c4d8a655c | ||
|
|
09bb027294 | ||
|
|
39b250d62c | ||
|
|
6d3a2d279a | ||
|
|
cbba8297cd | ||
|
|
39dbd646b9 | ||
|
|
3e769f0c59 | ||
|
|
50a5c1f56a | ||
|
|
e44bb50590 | ||
|
|
825422c484 | ||
|
|
f2526571a3 | ||
|
|
138abad9e6 | ||
|
|
697f660532 | ||
|
|
8f29c9d333 | ||
|
|
106b180c80 | ||
|
|
68ebf667d5 | ||
|
|
0e316239dd | ||
|
|
64f35d050f | ||
|
|
4cbcbdb960 | ||
|
|
190d230a01 | ||
|
|
db873be43b | ||
|
|
ed61d97700 | ||
|
|
75fa9e4730 | ||
|
|
80277d14d0 | ||
|
|
806d669725 | ||
|
|
203d850e77 | ||
|
|
cbfac3e324 | ||
|
|
0bdcad80ce | ||
|
|
cf6930a2ca | ||
|
|
f917aa09f2 | ||
|
|
509acd4b7c | ||
|
|
b8fa4a820b | ||
|
|
453e7f03d3 | ||
|
|
acc352b5c0 | ||
|
|
ed3ad327a2 | ||
|
|
eb33b3603e | ||
|
|
8d12bcc8ee | ||
|
|
e302aa38b5 | ||
|
|
a4983c9d14 | ||
|
|
4019473d73 | ||
|
|
6ffb40be26 | ||
|
|
e0f4f83ebf | ||
|
|
7b70348b4b | ||
|
|
662674e151 | ||
|
|
a2c8ea69a3 | ||
|
|
af9bde33fe | ||
|
|
da503dc3c5 | ||
|
|
0d459d5d22 | ||
|
|
feae9b0924 | ||
|
|
fdefd4be93 | ||
|
|
5dcefeff84 | ||
|
|
5897e7e01b | ||
|
|
e49cf74967 | ||
|
|
306f3eabd1 | ||
|
|
d940b39509 | ||
|
|
5b96bccedd | ||
|
|
26222539e6 | ||
|
|
b68f1afa26 | ||
|
|
3f3b2a0c86 | ||
|
|
611e118fb6 | ||
|
|
fc8f878584 | ||
|
|
59f6024cbd | ||
|
|
a411e2e9a6 | ||
|
|
0b6d5e9dca | ||
|
|
66a997afc3 | ||
|
|
ee86ab00df | ||
|
|
262e73e6d6 | ||
|
|
af74653b7f | ||
|
|
f5e789336f | ||
|
|
7c24fbcef2 | ||
|
|
3f825ec77f | ||
|
|
6381cdf7d3 | ||
|
|
55ae766484 | ||
|
|
88482c3bd7 | ||
|
|
21741e68bc | ||
|
|
e3e25daee7 | ||
|
|
d9bd80b280 | ||
|
|
3fbebcdef5 | ||
|
|
d662e18f97 | ||
|
|
dee62e1518 | ||
|
|
3c28abc7bd | ||
|
|
dfd8c4cd2a | ||
|
|
145a63f3f8 | ||
|
|
78d6a571aa | ||
|
|
70b7c8c998 | ||
|
|
dbca16c3dc | ||
|
|
b9a776c97b | ||
|
|
30edcdfe0e | ||
|
|
e2ebcbcacb | ||
|
|
791296fa41 | ||
|
|
f837dade92 | ||
|
|
c0d18eac0f | ||
|
|
3bd36b8096 | ||
|
|
70e52a5cf9 | ||
|
|
72c91ff17b | ||
|
|
5d5286d627 | ||
|
|
29f92ea297 | ||
|
|
7a43893616 | ||
|
|
ba4c89e7db | ||
|
|
d6bf6f6b55 | ||
|
|
d223b0b12e | ||
|
|
b0b3ab595a | ||
|
|
a5979810eb | ||
|
|
07c2ff5668 | ||
|
|
065a814d35 | ||
|
|
422a02d8f7 |
@@ -47,6 +47,7 @@ Windmill uses a workspace-based architecture with multiple crates:
|
||||
- Group related routes together
|
||||
- Use consistent response formats (JSON)
|
||||
- Follow proper authentication and authorization patterns
|
||||
- Do not forget to update backend/windmill-api/openapi.yaml after modifying an api endpoint
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ alwaysApply: false
|
||||
---
|
||||
# Svelte 5 Best Practices
|
||||
|
||||
This guide outlines best practices for developing with Svelte 5, incorporating the new Runes API and other modern Svelte features. They should be applied on every new files created, but not on existing svelte 4 files unless specifically asked to.
|
||||
This guide outlines best practices for developing with Svelte 5, incorporating the new Runes API and other modern Svelte features. These rules MUST NOT be applied on svelte 4 files unless explicitly asked to do so.
|
||||
|
||||
## Reactivity with Runes
|
||||
|
||||
|
||||
76
.cursor/rules/windmill-overview.mdc
Normal file
76
.cursor/rules/windmill-overview.mdc
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Windmill Overview
|
||||
|
||||
Windmill is an open-source developer platform for building internal tools, API integrations, background jobs, workflows, and user interfaces. It offers a unified system where scripts are automatically turned into sharable UIs and can be composed into flows or embedded in custom applications.
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
- **Script Development and Execution**: Write and run scripts in Python, TypeScript/JavaScript (Deno/Bun), Go, Bash, SQL, and other languages
|
||||
- **Workflow Orchestration**: Compose scripts into multi-step flows with conditional logic, loops, and error handling
|
||||
- **UI Generation**: Automatically generate UIs from scripts or build custom applications with a low-code editor
|
||||
- **Job Scheduling**: Trigger scripts and flows on schedules, webhooks, or external events
|
||||
- **Resource Management**: Securely store and use credentials, databases, and other connections
|
||||
|
||||
## Platform Architecture
|
||||
|
||||
The Windmill platform consists of several key components:
|
||||
|
||||
- **Frontend UI**: Web-based interface for script and flow development, app building, and result visualization
|
||||
- **API Server**: Central API that handles authentication, resource management, and job coordination
|
||||
- **Workers**: Execute scripts in their respective environments with proper sandboxing
|
||||
- **Database**: PostgreSQL database for storage of scripts, flows, resources, job results, and more
|
||||
- **Job Queue**: Queue system for managing job execution, implemented in PostgreSQL
|
||||
- **Client Libraries**: Libraries for interacting with Windmill from Python, TypeScript, or command line
|
||||
|
||||
# Windmill Backend Architecture
|
||||
|
||||
The Windmill backend is written in Rust and consists of several services working together. These services are designed for horizontal scaling with stateless API servers and workers that can be deployed across multiple machines.
|
||||
|
||||
## Key Components
|
||||
|
||||
- **API Server (`windmill-api`)**: Handles HTTP requests, authentication, and resource management
|
||||
- **Queue Manager (`windmill-queue`)**: Manages the job queue in PostgreSQL
|
||||
- **Worker System (`windmill-worker`)**: Executes jobs in sandboxed environments
|
||||
- **Common Utilities (`windmill-common`)**: Shared code used by multiple services
|
||||
- **Git Sync (`windmill-git-sync`)**: Synchronizes scripts with Git repositories
|
||||
|
||||
## Job Execution System
|
||||
|
||||
The job execution process follows these steps:
|
||||
|
||||
1. The API server receives a request to run a script or flow and creates a job record in the database
|
||||
2. The job is added to the queue system in PostgreSQL
|
||||
3. Workers continuously poll the queue for jobs matching their capabilities
|
||||
4. When a job is picked up, it's routed to the appropriate language executor
|
||||
5. The script is executed in a sandboxed environment using NSJAIL for security
|
||||
6. Results are processed and stored in the database
|
||||
7. For flows, each step creates a new job that goes through the same process
|
||||
|
||||
Windmill supports worker tags and groups to route jobs to workers with specific capabilities or resource access.
|
||||
|
||||
# Windmill Frontend Architecture
|
||||
|
||||
The Windmill frontend is built with Svelte and provides several key interfaces for interacting with the platform.
|
||||
|
||||
## Key Components
|
||||
|
||||
- **Script Builder**: Code editor with language support, schema inference, and dependency management
|
||||
- **Flow Builder**: Visual editor for creating multi-step workflows with branching and looping
|
||||
- **App Editor**: Grid-based editor for building custom UIs that integrate scripts and flows
|
||||
- **Schema Form System**: Generates form interfaces from script parameters automatically
|
||||
- **Result Viewer**: Visualizes job results, logs, and execution status
|
||||
|
||||
The frontend uses the Monaco editor (same as VS Code) for code editing, with specialized language support for all supported script languages.
|
||||
|
||||
## UI Framework
|
||||
|
||||
The frontend is built with Svelte, providing a reactive and component-based architecture. Key frontend technologies include:
|
||||
|
||||
- **Svelte/SvelteKit**: Core framework for UI components and routing
|
||||
- **Monaco Editor**: Code editing experience similar to VS Code
|
||||
- **Schema Form**: Automatic UI generation from TypeScript/JSON schemas
|
||||
- **Tailwind CSS**: Utility-first CSS framework for styling
|
||||
196
.github/workflows/aider-after-review.yaml
vendored
196
.github/workflows/aider-after-review.yaml
vendored
@@ -5,12 +5,42 @@ on:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
auto-fix-review:
|
||||
check-membership:
|
||||
if: github.event.review.state == 'changes_requested' && contains(github.event.pull_request.title, '[Aider PR]')
|
||||
runs-on: ubicloud-standard-8
|
||||
runs-on: ubicloud-standard-2
|
||||
outputs:
|
||||
is_member: ${{ steps.check-membership.outputs.is_member }}
|
||||
steps:
|
||||
- name: Check organization membership
|
||||
id: check-membership
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
REVIEWER: ${{ github.event.review.user.login }}
|
||||
ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }}
|
||||
run: |
|
||||
ORG="windmill-labs"
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $ORG_ACCESS_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/orgs/$ORG/members/$REVIEWER")
|
||||
|
||||
if [ "$STATUS" -eq 204 ]; then
|
||||
echo "is_member=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_member=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
check-and-prepare:
|
||||
needs: check-membership
|
||||
if: github.event.review.state == 'changes_requested' && contains(github.event.pull_request.title, '[Aider PR]') && needs.check-membership.outputs.is_member == 'true'
|
||||
runs-on: ubicloud-standard-2
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
outputs:
|
||||
prompt_content: ${{ steps.prepare_prompt.outputs.prompt_content }}
|
||||
env:
|
||||
GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
@@ -19,152 +49,46 @@ jobs:
|
||||
WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git User
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Checkout PR Branch
|
||||
- name: Acknowledge Request
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
echo "PR review trigger: Checking out PR branch..."
|
||||
PR_NUMBER=${{ github.event.pull_request.number }}
|
||||
PR_HEAD_REF=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName --repo $GITHUB_REPOSITORY)
|
||||
if [[ -z "$PR_HEAD_REF" || "$PR_HEAD_REF" == "null" ]]; then
|
||||
echo "::error::Could not determine PR head branch for PR #$PR_NUMBER via gh CLI."
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking out PR head branch: $PR_HEAD_REF for PR #$PR_NUMBER"
|
||||
git fetch origin "refs/heads/${PR_HEAD_REF}:refs/remotes/origin/${PR_HEAD_REF}" --no-tags
|
||||
git checkout "$PR_HEAD_REF"
|
||||
echo "Successfully checked out branch $(git rev-parse --abbrev-ref HEAD)"
|
||||
echo "Commenting on PR #${{ github.event.pull_request.number }} to acknowledge the /aider command."
|
||||
gh pr comment ${{ github.event.pull_request.number }} --body "🤖 Aider is starting to work on your request. Please be patient, this might take a few minutes." --repo $GITHUB_REPOSITORY
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Aider and Dependencies
|
||||
run: |
|
||||
python -m pip install aider-install; aider-install
|
||||
pip install -U google-generativeai
|
||||
sudo apt-get update && sudo apt-get install -y jq
|
||||
|
||||
- name: Generate Prompt from Review
|
||||
id: generate_prompt
|
||||
- name: Prepare prompt for Aider
|
||||
id: prepare_prompt
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
REVIEW_BODY: ${{ github.event.review.body }}
|
||||
run: |
|
||||
mkdir -p .github/aider
|
||||
PROMPT_FILE_PATH=".github/aider/review-prompt.txt"
|
||||
REVIEW_BODY_ESCAPED="${REVIEW_BODY//\\/\\\\}"
|
||||
REVIEW_BODY_ESCAPED="${REVIEW_BODY_ESCAPED//\"/\\\"}"
|
||||
|
||||
# Get PR review body
|
||||
REVIEW_BODY="${{ github.event.review.body }}"
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
|
||||
# Get PR description for context NOT USED FOR NOW
|
||||
# PR_DETAILS=$(gh pr view $PR_NUMBER --json title,body --repo $GITHUB_REPOSITORY)
|
||||
# PR_TITLE=$(echo "$PR_DETAILS" | jq -r .title)
|
||||
# PR_BODY=$(echo "$PR_DETAILS" | jq -r .body)
|
||||
|
||||
# Get all PR review comments
|
||||
REVIEW_COMMENTS=$(gh pr view $PR_NUMBER --json reviews -q '.reviews[] | select(.state == "CHANGES_REQUESTED") | .body' --repo $GITHUB_REPOSITORY)
|
||||
REVIEW_BODY_Q=$(printf '%q' "$REVIEW_BODY")
|
||||
|
||||
# Update query to get review comments from all review types, not just "CHANGES_REQUESTED"
|
||||
ALL_REVIEW_COMMENTS=$(gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
/repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments \
|
||||
| jq '[.[] | {diff_hunk: .diff_hunk, path: .path, body: .body}]')
|
||||
/repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments)
|
||||
|
||||
FORMATTED_COMMENTS=$(jq -r '[.[] | {diff_hunk: .diff_hunk, path: .path, body: .body}]' <<< "$ALL_REVIEW_COMMENTS")
|
||||
|
||||
BASE_PROMPT="Fix the following issues in the PR based on the review feedback. The review body is prepended with REVIEW. The review comments are prepended with REVIEW_COMMENTS. The review body and comments are separated by a blank line."
|
||||
printf "%s\nREVIEW:\n%s\nREVIEW_COMMENTS:\n%s" \
|
||||
"$BASE_PROMPT" "$REVIEW_BODY_Q" "$ALL_REVIEW_COMMENTS" > "$PROMPT_FILE_PATH"
|
||||
echo "PROMPT_FILE_PATH=$PROMPT_FILE_PATH" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run Aider with review prompt
|
||||
run: |
|
||||
aider \
|
||||
--read .cursor/rules/rust-best-practices.mdc \
|
||||
--read .cursor/rules/svelte5-best-practices.mdc \
|
||||
--model gemini/gemini-2.5-pro-preview-05-06 \
|
||||
--message-file .github/aider/review-prompt.txt \
|
||||
--yes \
|
||||
--no-check-update \
|
||||
--auto-commits \
|
||||
--no-analytics \
|
||||
--no-gitignore \
|
||||
| tee .github/aider/aider-output.txt || true
|
||||
echo "Aider command completed. Output saved to .github/aider/aider-output.txt"
|
||||
# Check if there are any changes to commit
|
||||
if [[ -z "$(git status --porcelain)" ]]; then
|
||||
echo "No changes detected after running Aider."
|
||||
exit 0
|
||||
fi
|
||||
COMPLETE_PROMPT="${BASE_PROMPT}"$'\n'"REVIEW:"$'\n'"${REVIEW_BODY_ESCAPED}"$'\n'"REVIEW_COMMENTS:"$'\n'"${FORMATTED_COMMENTS}"
|
||||
|
||||
- name: Clean up prompt file
|
||||
if: always()
|
||||
run: rm -f .github/aider/review-prompt.txt
|
||||
echo "prompt_content<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$COMPLETE_PROMPT" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit and Push Changes
|
||||
id: commit_and_push
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
CURRENT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo "Attempting to push changes to PR branch $CURRENT_BRANCH_NAME for PR #${{ github.event.pull_request.number }}"
|
||||
|
||||
# Pull latest changes to avoid rejection due to non-fast-forward
|
||||
git pull origin $CURRENT_BRANCH_NAME
|
||||
|
||||
if git push origin $CURRENT_BRANCH_NAME; then
|
||||
echo "Push to $CURRENT_BRANCH_NAME successful."
|
||||
echo "CHANGES_APPLIED=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "::warning::Push to PR branch $CURRENT_BRANCH_NAME failed."
|
||||
echo "CHANGES_APPLIED=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Comment on PR
|
||||
if: success()
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
# Create comment body in a temporary file to avoid command line length limits
|
||||
if [[ "${{ steps.commit_and_push.outputs.CHANGES_APPLIED }}" == "true" ]]; then
|
||||
cat > /tmp/pr-comment.md << EOL
|
||||
🤖 I've automatically addressed the feedback based on the review.
|
||||
|
||||
## Aider Output
|
||||
\`\`\`
|
||||
$(cat .github/aider/aider-output.txt || echo 'No output available')
|
||||
\`\`\`
|
||||
|
||||
Please review the changes and let me know if further adjustments are needed.
|
||||
EOL
|
||||
else
|
||||
cat > /tmp/pr-comment.md << EOL
|
||||
🤖 I attempted to address the review feedback, but no modifications were made.
|
||||
|
||||
## Aider Output
|
||||
\`\`\`
|
||||
$(cat .github/aider/aider-output.txt || echo 'No output available')
|
||||
\`\`\`
|
||||
|
||||
Please review the output and provide additional guidance if needed.
|
||||
EOL
|
||||
fi
|
||||
|
||||
# Use the file for comment body
|
||||
gh pr comment $PR_NUM --body-file /tmp/pr-comment.md
|
||||
run-aider:
|
||||
needs: [check-membership, check-and-prepare]
|
||||
if: github.event.review.state == 'changes_requested' && contains(github.event.pull_request.title, '[Aider PR]') && needs.check-membership.outputs.is_member == 'true'
|
||||
uses: ./.github/workflows/aider-common.yml
|
||||
with:
|
||||
needs_processing: false
|
||||
base_prompt: ${{ needs.check-and-prepare.outputs.prompt_content }}
|
||||
rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc"
|
||||
secrets: inherit
|
||||
|
||||
522
.github/workflows/aider-common.yml
vendored
Normal file
522
.github/workflows/aider-common.yml
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
name: Aider Common Steps
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
issue_title:
|
||||
description: "Title of the issue or PR"
|
||||
required: false
|
||||
type: string
|
||||
issue_body:
|
||||
description: "Body of the issue or PR"
|
||||
required: false
|
||||
type: string
|
||||
instruction:
|
||||
description: "Instruction for Aider"
|
||||
required: false
|
||||
type: string
|
||||
issue_id:
|
||||
description: "ID of the issue or PR"
|
||||
required: false
|
||||
type: string
|
||||
needs_processing:
|
||||
description: "Whether the issue needs to be processed by the external API"
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
base_prompt:
|
||||
description: "Base prompt for Aider"
|
||||
required: false
|
||||
type: string
|
||||
default: "Try to fix the following issue based on the instruction given by the user. The issue is prepended with the word ISSUE. The instruction is prepended with the word INSTRUCTION. The issue and instruction are separated by a blank line."
|
||||
probe_prompt:
|
||||
description: "Prompt for probe-chat"
|
||||
required: false
|
||||
type: string
|
||||
default: 'I''m giving you a request that needs to be implemented. Your role is ONLY to give me the files that are relevant to the request and nothing else. The request is prepended with the word REQUEST. Give me all the files relevant to this request. Your output MUST be a single json array that can be parsed with programatic json parsing, with the relevant files. Files can be rust or typescript or javascript files. DO NOT INCLUDE ANY OTHER TEXT IN YOUR OUTPUT. ONLY THE JSON ARRAY. Example of output: ["file1.py", "file2.py"]'
|
||||
rules_files:
|
||||
description: "Rules files for Aider"
|
||||
required: false
|
||||
type: string
|
||||
outputs:
|
||||
files_to_edit:
|
||||
description: "Files identified by probe-chat for editing"
|
||||
value: ${{ jobs.common-steps.outputs.files_to_edit }}
|
||||
final_prompt:
|
||||
description: "Final prompt for Aider"
|
||||
value: ${{ jobs.common-steps.outputs.final_prompt }}
|
||||
pr_branch_name:
|
||||
description: "Name of the branch used for PR"
|
||||
value: ${{ jobs.common-steps.outputs.pr_branch_name }}
|
||||
changes_applied_message:
|
||||
description: "Message indicating changes were applied"
|
||||
value: ${{ jobs.common-steps.outputs.changes_applied_message }}
|
||||
changes_applied:
|
||||
description: "Boolean indicating if changes were successfully applied"
|
||||
value: ${{ jobs.common-steps.outputs.changes_applied }}
|
||||
|
||||
jobs:
|
||||
common-steps:
|
||||
runs-on: ubicloud-standard-8
|
||||
outputs:
|
||||
files_to_edit: ${{ steps.probe_files.outputs.files_to_edit }}
|
||||
final_prompt: ${{ steps.create_prompt.outputs.final_prompt }}
|
||||
pr_branch_name: ${{ steps.commit_and_push.outputs.PR_BRANCH_NAME }}
|
||||
changes_applied_message: ${{ steps.commit_and_push.outputs.CHANGES_APPLIED_MESSAGE }}
|
||||
changes_applied: ${{ steps.commit_and_push.outputs.CHANGES_APPLIED }}
|
||||
env:
|
||||
GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }}
|
||||
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Checkout PR Branch
|
||||
id: checkout_pr
|
||||
if: (github.event_name == 'issue_comment' && github.event.issue.pull_request) || (github.event_name == 'pull_request_review')
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Issue comment trigger: Checking out PR branch..."
|
||||
PR_NUMBER=""
|
||||
if [ -n "${{ github.event.issue.number }}" ]; then
|
||||
PR_NUMBER="${{ github.event.issue.number }}"
|
||||
elif [ -n "${{ github.event.pull_request.number }}" ]; then
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
else
|
||||
echo "::error::Could not determine PR number."
|
||||
exit 1
|
||||
fi
|
||||
PR_HEAD_REF=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName --repo $GITHUB_REPOSITORY)
|
||||
if [[ -z "$PR_HEAD_REF" || "$PR_HEAD_REF" == "null" ]]; then
|
||||
echo "::error::Could not determine PR head branch for PR #$PR_NUMBER via gh CLI."
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking out PR head branch: $PR_HEAD_REF for PR #$PR_NUMBER"
|
||||
git fetch origin "refs/heads/${PR_HEAD_REF}:refs/remotes/origin/${PR_HEAD_REF}" --no-tags
|
||||
git checkout "$PR_HEAD_REF"
|
||||
echo "Successfully checked out branch $(git rev-parse --abbrev-ref HEAD)"
|
||||
echo "PR_BRANCH=$PR_HEAD_REF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Configure Git User
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Cache Python dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/setup.py') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Install Aider and Dependencies
|
||||
run: |
|
||||
echo "Installing Aider..."
|
||||
python -m pip install uv
|
||||
python -m venv ~/uv-env
|
||||
source ~/uv-env/bin/activate
|
||||
uv pip install configargparse==1.7
|
||||
uv pip install aider-chat==0.83.1
|
||||
uv pip install -U google-generativeai
|
||||
sudo apt-get update && sudo apt-get install -y jq
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
echo "VIRTUAL_ENV_PATH=$HOME/uv-env" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Prompt for Aider
|
||||
id: create_prompt
|
||||
shell: bash
|
||||
env:
|
||||
BASE_PROMPT_ENV: ${{ inputs.base_prompt }}
|
||||
ISSUE_TITLE_ENV: ${{ inputs.issue_title }}
|
||||
ISSUE_BODY_ENV: ${{ inputs.issue_body }}
|
||||
INSTRUCTION_ENV: ${{ inputs.instruction }}
|
||||
NEEDS_PROCESSING_ENV: ${{ inputs.needs_processing }}
|
||||
WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
FINAL_PROMPT_CONTENT=""
|
||||
|
||||
if [[ "$ISSUE_TITLE_ENV" != "" && "$ISSUE_BODY_ENV" != "" ]]; then
|
||||
echo "Processing issue with title: $ISSUE_TITLE_ENV"
|
||||
if [[ "$NEEDS_PROCESSING_ENV" == "true" ]]; then
|
||||
echo "Needs processing is true. Calling Windmill API..."
|
||||
JSON_PAYLOAD=$(jq -n \
|
||||
--arg title "$ISSUE_TITLE_ENV" \
|
||||
--arg body "$ISSUE_BODY_ENV" \
|
||||
'{"body":{"issue_title":$title,"issue_body":$body}}')
|
||||
|
||||
echo "Windmill JSON Payload: $JSON_PAYLOAD"
|
||||
|
||||
API_RESULT_FILE=$(mktemp)
|
||||
HTTP_CODE=$(curl -s -o "$API_RESULT_FILE" -w "%{http_code}" \
|
||||
-X POST "https://app.windmill.dev/api/w/windmill-labs/jobs/run_wait_result/p/f/ai/quiet_script" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $WINDMILL_TOKEN" \
|
||||
--data-binary "$JSON_PAYLOAD" \
|
||||
--max-time 90)
|
||||
|
||||
BODY_CONTENT=$(cat "$API_RESULT_FILE")
|
||||
rm -f "$API_RESULT_FILE" # Clean up temp file
|
||||
|
||||
echo "Windmill API HTTP Code: $HTTP_CODE"
|
||||
if [[ "$HTTP_CODE" -eq 200 ]]; then
|
||||
PROCESSED_ISSUE_PROMPT=$(echo "$BODY_CONTENT" | jq -r '.effective_body // empty')
|
||||
if [[ -z "$PROCESSED_ISSUE_PROMPT" || "$PROCESSED_ISSUE_PROMPT" == "null" ]]; then
|
||||
echo "::warning::Windmill API returned 200 but effective_body was empty or null."
|
||||
EFFECTIVE_ISSUE_CONTENT_FOR_PROMPT="$ISSUE_BODY_ENV"
|
||||
else
|
||||
echo "Successfully processed issue via Windmill API."
|
||||
EFFECTIVE_ISSUE_CONTENT_FOR_PROMPT="$PROCESSED_ISSUE_PROMPT"
|
||||
fi
|
||||
FINAL_PROMPT_CONTENT=$(printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT_ENV" "$EFFECTIVE_ISSUE_CONTENT_FOR_PROMPT" "$INSTRUCTION_ENV")
|
||||
else
|
||||
echo "::error::Windmill API call failed (HTTP $HTTP_CODE). Using raw issue content for prompt."
|
||||
FINAL_PROMPT_CONTENT=$(printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT_ENV" "$ISSUE_BODY_ENV" "$INSTRUCTION_ENV")
|
||||
fi
|
||||
else
|
||||
echo "Needs processing is false. Using raw issue content for prompt."
|
||||
FINAL_PROMPT_CONTENT=$(printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT_ENV" "$ISSUE_BODY_ENV" "$INSTRUCTION_ENV")
|
||||
fi
|
||||
else
|
||||
echo "No issue title or body given. Using base prompt."
|
||||
FINAL_PROMPT_CONTENT=$(printf "%s\nINSTRUCTION:\n%s" "$BASE_PROMPT_ENV" "$INSTRUCTION_ENV")
|
||||
fi
|
||||
|
||||
echo "Final prompt: $FINAL_PROMPT_CONTENT"
|
||||
echo "final_prompt<<EOF_AIDER_PROMPT" >> "$GITHUB_OUTPUT"
|
||||
echo "$FINAL_PROMPT_CONTENT" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_PROMPT" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Probe Chat for Relevant Files
|
||||
id: probe_files
|
||||
shell: bash
|
||||
env:
|
||||
FINAL_PROMPT: ${{ steps.create_prompt.outputs.final_prompt }}
|
||||
PROBE_PROMPT: ${{ inputs.probe_prompt }}
|
||||
run: |
|
||||
echo "Running probe-chat to find relevant files..."
|
||||
|
||||
MESSAGE_FOR_PROBE=$(printf "%s\nREQUEST:\n%s" "$PROBE_PROMPT" "$FINAL_PROMPT")
|
||||
|
||||
set -o pipefail
|
||||
PROBE_OUTPUT=$(npx --yes @buger/probe-chat@latest --max-iterations 50 --model-name gemini-2.5-pro-preview-05-06 --message "$MESSAGE_FOR_PROBE") || {
|
||||
echo "::error::probe-chat command failed. Output:"
|
||||
echo "$PROBE_OUTPUT"
|
||||
exit 1
|
||||
}
|
||||
set +o pipefail
|
||||
echo "Probe-chat raw output:"
|
||||
echo "$PROBE_OUTPUT"
|
||||
|
||||
JSON_FILES=$(echo "$PROBE_OUTPUT" | sed -n '/^\s*\[/,$p' | sed '/^\s*\]/q')
|
||||
echo "Extracted JSON block:"
|
||||
echo "$JSON_FILES"
|
||||
|
||||
FILES_LIST=$(echo "$JSON_FILES" | jq -e -r '[.[] | select(type == "string" and . != "" and . != null and (endswith("/") | not))] | join(" ")' || echo "")
|
||||
|
||||
if [[ -z "$FILES_LIST" ]]; then
|
||||
echo "::warning::probe-chat did not identify any relevant files."
|
||||
fi
|
||||
|
||||
echo "Formatted files list for aider: $FILES_LIST"
|
||||
echo "files_to_edit=$FILES_LIST" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache Aider tags
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .aider.tags.cache.v4
|
||||
key: ${{ runner.os }}-aider-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-aider-
|
||||
|
||||
- name: Prepare branch for Aider
|
||||
id: prepare_branch
|
||||
env:
|
||||
ISSUE_ID: ${{ inputs.issue_id }}
|
||||
run: |
|
||||
if [[ "$ISSUE_ID" != "" ]]; then
|
||||
BRANCH_NAME="aider-fix-issue-${ISSUE_ID}"
|
||||
|
||||
# Check if branch exists remotely
|
||||
if git ls-remote --heads origin $BRANCH_NAME | grep -q $BRANCH_NAME; then
|
||||
echo "Branch $BRANCH_NAME already exists remotely, fetching it"
|
||||
git fetch origin $BRANCH_NAME
|
||||
git checkout $BRANCH_NAME
|
||||
git pull origin $BRANCH_NAME
|
||||
else
|
||||
echo "Creating new branch $BRANCH_NAME"
|
||||
git checkout -b $BRANCH_NAME
|
||||
fi
|
||||
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
else
|
||||
# We're in a pull_request_review event
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
PR_HEAD_REF="${{ github.event.pull_request.head.ref }}"
|
||||
|
||||
echo "Handling pull_request_review for PR #$PR_NUMBER on branch $PR_HEAD_REF"
|
||||
|
||||
# Ensure we're on the correct branch
|
||||
git config pull.rebase true
|
||||
git fetch origin $PR_HEAD_REF
|
||||
git checkout $PR_HEAD_REF
|
||||
git pull origin $PR_HEAD_REF
|
||||
|
||||
echo "Using PR branch $PR_HEAD_REF for PR #$PR_NUMBER"
|
||||
echo "BRANCH_NAME=$PR_HEAD_REF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Run Aider
|
||||
id: run_aider
|
||||
shell: bash
|
||||
env:
|
||||
FILES_TO_EDIT: ${{ steps.probe_files.outputs.files_to_edit }}
|
||||
FINAL_PROMPT: ${{ steps.create_prompt.outputs.final_prompt }}
|
||||
RULES_FILES: ${{ inputs.rules_files }}
|
||||
run: |
|
||||
source $VIRTUAL_ENV_PATH/bin/activate
|
||||
echo "$FINAL_PROMPT" > .aider_final_prompt.txt
|
||||
echo "FILES_TO_EDIT: $FILES_TO_EDIT"
|
||||
|
||||
RULES=""
|
||||
if [ -n "$RULES_FILES" ]; then
|
||||
for rule in $RULES_FILES; do
|
||||
RULES="$RULES --read $rule"
|
||||
done
|
||||
fi
|
||||
|
||||
aider \
|
||||
$RULES \
|
||||
$FILES_TO_EDIT \
|
||||
--model gemini/gemini-2.5-pro-preview-05-06 \
|
||||
--message-file .aider_final_prompt.txt \
|
||||
--yes \
|
||||
--no-check-update \
|
||||
--auto-commits \
|
||||
--no-analytics \
|
||||
--no-gitignore \
|
||||
| tee .aider_output.txt || true
|
||||
|
||||
echo "Aider command completed. Output saved to .aider_output.txt"
|
||||
|
||||
- name: Cache Node.js dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Commit and Push Changes
|
||||
id: commit_and_push
|
||||
env:
|
||||
ISSUE_ID: ${{ inputs.issue_id }}
|
||||
BRANCH_NAME: ${{ steps.prepare_branch.outputs.BRANCH_NAME }}
|
||||
run: |
|
||||
if [[ "$ISSUE_ID" != "" ]]; then
|
||||
# Check if there are any uncommitted changes
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "Found uncommitted changes, committing them"
|
||||
git add .
|
||||
git commit -m "Aider changes"
|
||||
fi
|
||||
|
||||
# Push changes to the branch
|
||||
if git push origin $BRANCH_NAME; then
|
||||
echo "Pushed to branch $BRANCH_NAME"
|
||||
echo "PR_BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider changes pushed to branch $BRANCH_NAME." >> $GITHUB_OUTPUT
|
||||
echo "CHANGES_APPLIED=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "::warning::Push to PR branch $BRANCH_NAME failed."
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider ran, but failed to push changes to PR branch $BRANCH_NAME." >> $GITHUB_OUTPUT
|
||||
echo "CHANGES_APPLIED=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
else
|
||||
# We're in a pull_request_review event
|
||||
PR_HEAD_REF="${{ github.event.pull_request.head.ref }}"
|
||||
echo "Attempting to push changes to PR branch $PR_HEAD_REF"
|
||||
if git push origin $PR_HEAD_REF; then
|
||||
echo "Push to $PR_HEAD_REF successful (or no new changes to push)."
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider changes (if any) pushed to PR branch $PR_HEAD_REF." >> $GITHUB_OUTPUT
|
||||
echo "PR_BRANCH_NAME=$PR_HEAD_REF" >> $GITHUB_OUTPUT
|
||||
echo "CHANGES_APPLIED=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "::warning::Push to PR branch $PR_HEAD_REF failed."
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider ran, but failed to push changes to PR branch $PR_HEAD_REF." >> $GITHUB_OUTPUT
|
||||
echo "CHANGES_APPLIED=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
if: always() && (github.event_name == 'issue_comment' || github.event_name == 'repository_dispatch') && !github.event.issue.pull_request && steps.commit_and_push.outputs.PR_BRANCH_NAME != ''
|
||||
id: create_pr
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_BRANCH: ${{ steps.commit_and_push.outputs.PR_BRANCH_NAME }}
|
||||
ISSUE_NUM: ${{ inputs.issue_id }}
|
||||
ISSUE_TITLE: ${{ inputs.issue_title }}
|
||||
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||
run: |
|
||||
# Create PR description in a temporary file to avoid command line length limits and ensure it stays under 40k chars
|
||||
HEADER="This PR was created automatically by Aider to fix issue #${ISSUE_NUM}."
|
||||
# if event is repository_dispatch, add the issue title to the header
|
||||
if [ "$GITHUB_EVENT_NAME" == "repository_dispatch" ]; then
|
||||
if [[ "${{ github.event.client_payload.source }}" == "linear" ]]; then
|
||||
HEADER="This PR was created automatically by Aider to fix issue #linear:${ISSUE_NUM}."
|
||||
elif [[ "${{ github.event.client_payload.source }}" == "discord" ]]; then
|
||||
HEADER="This PR was created automatically by Aider to fix issue #discord:${ISSUE_NUM}."
|
||||
fi
|
||||
fi
|
||||
cat > /tmp/pr-description.md << EOL | head -c 40000
|
||||
$HEADER
|
||||
|
||||
## Aider Output
|
||||
\`\`\`
|
||||
$(cat .aider_output.txt || echo "No output available")
|
||||
\`\`\`
|
||||
EOL
|
||||
|
||||
# Create PR using the file for the body content, handle errors gracefully
|
||||
set +e # Don't exit on error
|
||||
PR_TITLE="[Aider PR] Fix: ${ISSUE_TITLE}"
|
||||
if [ -z "$ISSUE_TITLE" ]; then
|
||||
PR_TITLE="[Aider PR] AI changes after request"
|
||||
fi
|
||||
gh pr create \
|
||||
--title "$PR_TITLE" \
|
||||
--body-file /tmp/pr-description.md \
|
||||
--head "$PR_BRANCH" \
|
||||
--base main \
|
||||
--draft
|
||||
PR_CREATE_EXIT_CODE=$?
|
||||
set -e # Re-enable exit on error
|
||||
|
||||
if [ $PR_CREATE_EXIT_CODE -eq 0 ]; then
|
||||
echo "PR created successfully"
|
||||
PR_URL=$(gh pr view $PR_BRANCH --json url --jq .url)
|
||||
echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT
|
||||
echo "PR_CREATED=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Warning: Failed to create PR. Exit code: $PR_CREATE_EXIT_CODE"
|
||||
echo "PR_CREATED=false" >> $GITHUB_OUTPUT
|
||||
# Continue workflow despite PR creation failure
|
||||
fi
|
||||
|
||||
- name: Comment on PR with Aider Output
|
||||
if: always() && github.event_name == 'pull_request_review' && steps.commit_and_push.outputs.CHANGES_APPLIED != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
JOB_STATUS: ${{ job.status }}
|
||||
run: |
|
||||
# Create comment body in a temporary file to avoid command line length limits
|
||||
if [[ "${{ steps.commit_and_push.outputs.CHANGES_APPLIED }}" == "true" ]]; then
|
||||
if [[ "$JOB_STATUS" == "success" ]]; then
|
||||
STATUS_PREFIX="🤖 I've automatically addressed the feedback based on the review."
|
||||
else
|
||||
STATUS_PREFIX="⚠️ I attempted to address the feedback, but encountered some issues."
|
||||
fi
|
||||
else
|
||||
if [[ "$JOB_STATUS" == "success" ]]; then
|
||||
STATUS_PREFIX="🤖 I attempted to address the review feedback, but no modifications were made."
|
||||
else
|
||||
STATUS_PREFIX="⚠️ I encountered issues while attempting to address the feedback, and no modifications were made."
|
||||
fi
|
||||
fi
|
||||
|
||||
cat > /tmp/pr-comment.md << EOL
|
||||
${STATUS_PREFIX}
|
||||
|
||||
## Aider Output
|
||||
\`\`\`
|
||||
$(cat .aider_output.txt || echo 'No output available')
|
||||
\`\`\`
|
||||
|
||||
Please review the output and provide additional guidance if needed.
|
||||
EOL
|
||||
|
||||
# Use the file for comment body
|
||||
gh pr comment $PR_NUM --body-file /tmp/pr-comment.md
|
||||
|
||||
- name: Comment on issue/PR to let the user know Aider has finished working on the request
|
||||
if: always() && github.event_name == 'issue_comment'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
JOB_STATUS: ${{ job.status }}
|
||||
PR_CREATED: ${{ steps.create_pr.outputs.PR_CREATED }}
|
||||
PR_URL: ${{ steps.create_pr.outputs.PR_URL }}
|
||||
run: |
|
||||
echo "Commenting on issue/PR #${{ github.event.issue.number }} to let the user know Aider has finished working on the request."
|
||||
|
||||
if [[ "$JOB_STATUS" == "success" ]]; then
|
||||
if [[ "$PR_CREATED" == "true" ]]; then
|
||||
COMMENT_BODY="🤖 Aider has finished working on your request. A PR has been created. $PR_URL"
|
||||
else
|
||||
COMMENT_BODY="🤖 Aider has finished working on your request, but was unable to create a PR."
|
||||
fi
|
||||
else
|
||||
COMMENT_BODY="⚠️ Aider encountered issues while working on your request. Please check the workflow logs for details."
|
||||
fi
|
||||
|
||||
gh issue comment ${{ github.event.issue.number }} --body "$COMMENT_BODY" --repo $GITHUB_REPOSITORY
|
||||
|
||||
- name: Comment on linear issue to let the user know Aider has finished working on the request
|
||||
if: always() && github.event_name == 'repository_dispatch'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
JOB_STATUS: ${{ job.status }}
|
||||
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
|
||||
PR_CREATED: ${{ steps.create_pr.outputs.PR_CREATED }}
|
||||
PR_URL: ${{ steps.create_pr.outputs.PR_URL }}
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
SOURCE: ${{ github.event.client_payload.source }}
|
||||
run: |
|
||||
echo "Notifying user about Aider completion status for $SOURCE request #${{ github.event.client_payload.issue_id }}"
|
||||
if [[ "$JOB_STATUS" == "success" ]]; then
|
||||
if [[ "$PR_CREATED" == "true" ]]; then
|
||||
COMMENT_BODY="🤖 Aider has finished working on your request. A PR has been created. $PR_URL"
|
||||
else
|
||||
COMMENT_BODY="🤖 Aider has finished working on your request, but was unable to create a PR."
|
||||
fi
|
||||
else
|
||||
COMMENT_BODY="⚠️ Aider encountered issues while working on your request. Please check the workflow logs for details."
|
||||
fi
|
||||
|
||||
if [[ "$SOURCE" == "discord" ]]; then
|
||||
curl -X POST \
|
||||
-H "Authorization: Bot $DISCORD_BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://discord.com/api/v10/channels/${{ github.event.client_payload.channel_id }}/messages" \
|
||||
-d "{\"content\":\"${COMMENT_BODY}\"}"
|
||||
else
|
||||
curl -X POST \
|
||||
-H "Authorization: $LINEAR_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://api.linear.app/graphql" \
|
||||
-d "{\"query\":\"mutation { commentCreate(input: { issueId: \\\"${{ github.event.client_payload.issue_id }}\\\", body: \\\"${COMMENT_BODY}\\\" }) { success } }\"}"
|
||||
fi
|
||||
80
.github/workflows/aider-external.yaml
vendored
Normal file
80
.github/workflows/aider-external.yaml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: External Aider Issue Fix
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [external_issue_fix]
|
||||
|
||||
jobs:
|
||||
check-and-prepare:
|
||||
runs-on: ubicloud-standard-2
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
outputs:
|
||||
issue_title: ${{ steps.determine_inputs.outputs.ISSUE_TITLE }}
|
||||
issue_body: ${{ steps.determine_inputs.outputs.ISSUE_BODY }}
|
||||
instruction: ${{ steps.determine_inputs.outputs.INSTRUCTION }}
|
||||
env:
|
||||
GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }}
|
||||
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Acknowledge Request
|
||||
env:
|
||||
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
run: |
|
||||
if [[ "${{ github.event.client_payload.source }}" == "linear" ]]; then
|
||||
echo "Commenting on Linear issue #${{ github.event.client_payload.issue_id }} to acknowledge the request."
|
||||
curl -X POST \
|
||||
-H "Authorization: $LINEAR_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://api.linear.app/graphql" \
|
||||
-d "{\"query\":\"mutation { commentCreate(input: { issueId: \\\"${{ github.event.client_payload.issue_id }}\\\", body: \\\"🤖 Aider is starting to work on your request. I'll update you here once I have a PR ready. Please be patient, this might take a few minutes.\\\" }) { success } }\"}"
|
||||
elif [[ "${{ github.event.client_payload.source }}" == "discord" ]]; then
|
||||
echo "Commenting on Discord thread #${{ github.event.client_payload.channel_id }} to acknowledge the request."
|
||||
curl -X POST \
|
||||
-H "Authorization: Bot $DISCORD_BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://discord.com/api/v10/channels/${{ github.event.client_payload.channel_id }}/messages" \
|
||||
-d "{\"content\":\"🤖 Aider is starting to work on your request. I'll update you here once I have a PR ready. Please be patient, this might take a few minutes.\"}"
|
||||
fi
|
||||
|
||||
- name: Determine inputs for Aider
|
||||
id: determine_inputs
|
||||
shell: bash
|
||||
env:
|
||||
ISSUE_TITLE: ${{ github.event.client_payload.issue_title }}
|
||||
ISSUE_BODY: ${{ github.event.client_payload.issue_body }}
|
||||
INSTRUCTION: ${{ github.event.client_payload.instruction }}
|
||||
run: |
|
||||
echo "Determining inputs for Aider..."
|
||||
|
||||
echo "ISSUE_TITLE<<EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT"
|
||||
echo "$ISSUE_TITLE" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "ISSUE_BODY<<EOF_AIDER_BODY" >> "$GITHUB_OUTPUT"
|
||||
echo "$ISSUE_BODY" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_BODY" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "INSTRUCTION<<EOF_AIDER_INSTRUCTION" >> "$GITHUB_OUTPUT"
|
||||
echo "$INSTRUCTION" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_INSTRUCTION" >> "$GITHUB_OUTPUT"
|
||||
echo "Finished determining inputs."
|
||||
|
||||
run-aider:
|
||||
needs: check-and-prepare
|
||||
uses: ./.github/workflows/aider-common.yml
|
||||
with:
|
||||
issue_title: ${{ needs.check-and-prepare.outputs.issue_title }}
|
||||
issue_body: ${{ needs.check-and-prepare.outputs.issue_body }}
|
||||
instruction: ${{ needs.check-and-prepare.outputs.instruction }}
|
||||
issue_id: ${{ github.event.client_payload.issue_id }}
|
||||
rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc"
|
||||
secrets: inherit
|
||||
417
.github/workflows/aider.yaml
vendored
417
.github/workflows/aider.yaml
vendored
@@ -5,12 +5,40 @@ on:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
auto-fix:
|
||||
runs-on: ubicloud-standard-8
|
||||
check-membership:
|
||||
runs-on: ubicloud-standard-2
|
||||
if: |
|
||||
github.event_name == 'issue_comment' &&
|
||||
contains(github.event.comment.body, '/aider') &&
|
||||
!contains(github.event.comment.user.login, '[bot]')
|
||||
outputs:
|
||||
is_member: ${{ steps.check-membership.outputs.is_member }}
|
||||
steps:
|
||||
- name: Check organization membership
|
||||
id: check-membership
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
COMMENTER: ${{ github.event.comment.user.login }}
|
||||
ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }}
|
||||
run: |
|
||||
ORG="windmill-labs"
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $ORG_ACCESS_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/orgs/$ORG/members/$COMMENTER")
|
||||
|
||||
if [ "$STATUS" -eq 204 ]; then
|
||||
echo "is_member=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_member=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
check-and-prepare:
|
||||
needs: check-membership
|
||||
runs-on: ubicloud-standard-2
|
||||
if: needs.check-membership.outputs.is_member == 'true'
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
@@ -21,322 +49,117 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }}
|
||||
outputs:
|
||||
issue_title: ${{ steps.determine_inputs.outputs.ISSUE_TITLE }}
|
||||
issue_body: ${{ steps.determine_inputs.outputs.ISSUE_BODY }}
|
||||
comment_content: ${{ steps.determine_inputs.outputs.COMMENT_CONTENT }}
|
||||
pr_branch: ${{ steps.checkout_pr.outputs.PR_BRANCH }}
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure Git User
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Checkout PR Branch
|
||||
if: github.event_name == 'issue_comment' && github.event.issue.pull_request
|
||||
- name: Acknowledge Request
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
echo "Issue comment trigger: Checking out PR branch..."
|
||||
PR_NUMBER=${{ github.event.issue.number }}
|
||||
PR_HEAD_REF=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName --repo $GITHUB_REPOSITORY)
|
||||
if [[ -z "$PR_HEAD_REF" || "$PR_HEAD_REF" == "null" ]]; then
|
||||
echo "::error::Could not determine PR head branch for PR #$PR_NUMBER via gh CLI."
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking out PR head branch: $PR_HEAD_REF for PR #$PR_NUMBER"
|
||||
git fetch origin "refs/heads/${PR_HEAD_REF}:refs/remotes/origin/${PR_HEAD_REF}" --no-tags
|
||||
git checkout "$PR_HEAD_REF"
|
||||
echo "Successfully checked out branch $(git rev-parse --abbrev-ref HEAD)"
|
||||
echo "Commenting on issue/PR #${{ github.event.issue.number }} to acknowledge the /aider command."
|
||||
gh issue comment ${{ github.event.issue.number }} --body "🤖 Aider is starting to work on your request. I'll update you here once I have a PR ready. Please be patient, this might take a few minutes." --repo $GITHUB_REPOSITORY
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Aider and Dependencies
|
||||
run: |
|
||||
python -m pip install aider-install; aider-install
|
||||
pip install -U google-generativeai
|
||||
sudo apt-get update && sudo apt-get install -y jq
|
||||
|
||||
- name: Determine Prompt for Aider
|
||||
id: determine_prompt
|
||||
- name: Determine inputs for Aider
|
||||
id: determine_inputs
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
|
||||
run: |
|
||||
PROMPT_FILE_PATH=".github/aider/issue-prompt.txt"
|
||||
mkdir -p .github/aider
|
||||
echo "Determining inputs for Aider..."
|
||||
ISSUE_TITLE_VAL=""
|
||||
ISSUE_BODY_VAL=""
|
||||
|
||||
# Determine if this is a PR comment or regular issue comment
|
||||
if [[ ! -z "${{ github.event.issue.pull_request }}" ]]; then
|
||||
echo "This is a comment on a Pull Request"
|
||||
PR_NUMBER="${{ github.event.issue.number }}"
|
||||
PR_NUMBER="$ISSUE_NUMBER"
|
||||
|
||||
# Get PR description to check for issue references
|
||||
PR_BODY=$(gh pr view $PR_NUMBER --json body -q .body --repo $GITHUB_REPOSITORY)
|
||||
|
||||
# Extract issue number from PR description (looking for #123 or "fixes #123" patterns)
|
||||
REFERENCED_ISSUE=$(echo "$PR_BODY" | grep -oE "#[0-9]+" | grep -oE "[0-9]+" | head -1)
|
||||
|
||||
if [[ ! -z "$REFERENCED_ISSUE" ]]; then
|
||||
echo "Found referenced issue #$REFERENCED_ISSUE in PR description"
|
||||
|
||||
# Fetch the referenced issue details
|
||||
ISSUE_DETAILS=$(gh issue view $REFERENCED_ISSUE --json title,body --repo $GITHUB_REPOSITORY)
|
||||
ISSUE_TITLE=$(echo "$ISSUE_DETAILS" | jq -r .title)
|
||||
ISSUE_BODY=$(echo "$ISSUE_DETAILS" | jq -r .body)
|
||||
|
||||
# Store raw comment body in a file first to avoid shell interpretation issues
|
||||
echo '${{ github.event.comment.body }}' > /tmp/raw_comment.txt
|
||||
RAW_COMMENT_BODY=$(cat /tmp/raw_comment.txt)
|
||||
# Remove the /aider prefix and trim whitespace
|
||||
COMMENT_CONTENT=$(echo "$RAW_COMMENT_BODY" | sed 's|^/aider||' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
|
||||
|
||||
echo "Sending issue content and PR comment to external API…"
|
||||
|
||||
ISSUE_TITLE_Q=$(printf '%q' "$ISSUE_TITLE")
|
||||
ISSUE_BODY_Q=$(printf '%q' "$ISSUE_BODY")
|
||||
|
||||
JSON_PAYLOAD=$(jq -n \
|
||||
--arg title "$ISSUE_TITLE_Q" \
|
||||
--arg body "$ISSUE_BODY_Q" \
|
||||
'{"body":{"issue_title":$title,"issue_body":$body}}')
|
||||
|
||||
API_RESULT=$(curl -s -w "\n%{http_code}" \
|
||||
-X POST "https://app.windmill.dev/api/w/windmill-labs/jobs/run_wait_result/p/f/ai/quiet_script" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $WINDMILL_TOKEN" \
|
||||
--data-binary "$JSON_PAYLOAD" \
|
||||
--max-time 90)
|
||||
|
||||
HTTP_CODE=$(echo "$API_RESULT" | tail -n1)
|
||||
BODY=$(echo "$API_RESULT" | sed '$d')
|
||||
|
||||
echo "$BODY" > /tmp/api_response.txt
|
||||
|
||||
BASE_PROMPT="Try to fix the following issue based on the instruction given by the user. The issue is prepended with the word ISSUE. The instruction is prepended with the word INSTRUCTION. The issue and instruction are separated by a blank line."
|
||||
if [[ "$HTTP_CODE" -eq 200 ]]; then
|
||||
PROCESSED_ISSUE_PROMPT=$(jq -r '.effective_body // empty' /tmp/api_response.txt)
|
||||
if [[ -z "$PROCESSED_ISSUE_PROMPT" || "$PROCESSED_ISSUE_PROMPT" == "null" ]]; then
|
||||
PROCESSED_ISSUE_PROMPT=""
|
||||
fi
|
||||
printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT" "$PROCESSED_ISSUE_PROMPT" "$COMMENT_CONTENT" > "$PROMPT_FILE_PATH"
|
||||
else
|
||||
echo "::warning::API call failed (HTTP $HTTP_CODE). Using PR comment with issue context."
|
||||
printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT" "$ISSUE_BODY_Q" "$COMMENT_CONTENT" > "$PROMPT_FILE_PATH"
|
||||
fi
|
||||
rm -f /tmp/api_response.txt
|
||||
PR_BODY_JSON=$(gh pr view "$PR_NUMBER" --json body --repo "$GITHUB_REPOSITORY")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Error fetching PR body for PR #$PR_NUMBER"
|
||||
PR_BODY_VAL=""
|
||||
else
|
||||
echo "No referenced issue found in PR description, using comment content only"
|
||||
# Use comment content directly as with regular issue comments
|
||||
echo '${{ github.event.comment.body }}' > /tmp/raw_comment.txt
|
||||
RAW_COMMENT_BODY=$(cat /tmp/raw_comment.txt)
|
||||
COMMENT_CONTENT=$(echo "$RAW_COMMENT_BODY" | sed 's|^/aider||' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
|
||||
|
||||
if [[ -z "$COMMENT_CONTENT" ]]; then
|
||||
echo "::error::Comment with /aider provided, but no instruction found after it. Cannot proceed."
|
||||
printf "Error: /aider command found but no instruction followed." > "$PROMPT_FILE_PATH"
|
||||
exit 1
|
||||
else
|
||||
echo "Using comment content as prompt."
|
||||
printf '%s' "$COMMENT_CONTENT" > "$PROMPT_FILE_PATH"
|
||||
PR_BODY_VAL=$(jq -r '.body // ""' <<< "$PR_BODY_JSON")
|
||||
fi
|
||||
|
||||
if [[ ! -z "$PR_BODY_VAL" ]]; then
|
||||
REFERENCED_ISSUE=""
|
||||
if [[ "$PR_BODY_VAL" =~ \#linear:([a-f0-9-]+) ]]; then
|
||||
REFERENCED_ISSUE="${BASH_REMATCH[1]}"
|
||||
echo "Found referenced Linear issue #$REFERENCED_ISSUE in PR description"
|
||||
LINEAR_ISSUE_JSON=$(curl -s -H "Authorization: $LINEAR_API_KEY" \
|
||||
"https://api.linear.app/graphql" \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"query\":\"query { issue(id: \\\"$REFERENCED_ISSUE\\\") { title description } }\"}")
|
||||
|
||||
if [[ $? -eq 0 && ! "$LINEAR_ISSUE_JSON" =~ "error" ]]; then
|
||||
ISSUE_TITLE_VAL=$(jq -r '.data.issue.title // ""' <<< "$LINEAR_ISSUE_JSON")
|
||||
ISSUE_BODY_VAL=$(jq -r '.data.issue.description // ""' <<< "$LINEAR_ISSUE_JSON")
|
||||
echo "Successfully fetched Linear issue details"
|
||||
else
|
||||
echo "Error fetching Linear issue details for #$REFERENCED_ISSUE"
|
||||
fi
|
||||
elif [[ "$PR_BODY_VAL" =~ \#([0-9]+) ]]; then
|
||||
REFERENCED_ISSUE="${BASH_REMATCH[1]}"
|
||||
echo "Found referenced GitHub issue #$REFERENCED_ISSUE in PR description"
|
||||
|
||||
ISSUE_DETAILS_JSON=$(gh issue view "$REFERENCED_ISSUE" --json title,body --repo "$GITHUB_REPOSITORY")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Error fetching issue details for #$REFERENCED_ISSUE"
|
||||
else
|
||||
ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON")
|
||||
ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON")
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "PR body is empty or could not be fetched."
|
||||
fi
|
||||
else
|
||||
echo "This is a comment on a regular issue"
|
||||
|
||||
# Fetch the issue details
|
||||
ISSUE_NUMBER="${{ github.event.issue.number }}"
|
||||
ISSUE_DETAILS=$(gh issue view $ISSUE_NUMBER --json title,body --repo $GITHUB_REPOSITORY)
|
||||
ISSUE_TITLE=$(echo "$ISSUE_DETAILS" | jq -r .title)
|
||||
ISSUE_BODY=$(echo "$ISSUE_DETAILS" | jq -r .body)
|
||||
|
||||
# Store raw comment body in a file first to avoid shell interpretation issues
|
||||
echo '${{ github.event.comment.body }}' > /tmp/raw_comment.txt
|
||||
# Extract the command part safely
|
||||
RAW_COMMENT_BODY=$(cat /tmp/raw_comment.txt)
|
||||
# Remove the /aider prefix and trim whitespace
|
||||
COMMENT_CONTENT=$(echo "$RAW_COMMENT_BODY" | sed 's|^/aider||' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
|
||||
|
||||
if [[ -z "$COMMENT_CONTENT" ]]; then
|
||||
echo "::error::Comment with /aider provided, but no instruction found after it. Cannot proceed."
|
||||
printf "Error: /aider command found but no instruction followed." > "$PROMPT_FILE_PATH"
|
||||
exit 1
|
||||
ISSUE_DETAILS_JSON=$(gh issue view "$ISSUE_NUMBER" --json title,body --repo "$GITHUB_REPOSITORY")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Error fetching issue details for #$ISSUE_NUMBER"
|
||||
else
|
||||
echo "Sending issue content and issue comment to external API…"
|
||||
|
||||
ISSUE_TITLE_Q=$(printf '%q' "$ISSUE_TITLE")
|
||||
ISSUE_BODY_Q=$(printf '%q' "$ISSUE_BODY")
|
||||
COMMENT_CONTENT_Q=$(printf '%q' "$COMMENT_CONTENT")
|
||||
|
||||
JSON_PAYLOAD=$(jq -n \
|
||||
--arg title "$ISSUE_TITLE_Q" \
|
||||
--arg body "$ISSUE_BODY_Q" \
|
||||
--arg comment "$COMMENT_CONTENT_Q" \
|
||||
'{"body":{"issue_title":$title,"issue_body":$body,"issue_comment":$comment}}')
|
||||
|
||||
API_RESULT=$(curl -s -w "\n%{http_code}" \
|
||||
-X POST "https://app.windmill.dev/api/w/windmill-labs/jobs/run_wait_result/p/f/ai/quiet_script" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $WINDMILL_TOKEN" \
|
||||
--data-binary "$JSON_PAYLOAD" \
|
||||
--max-time 90)
|
||||
|
||||
HTTP_CODE=$(echo "$API_RESULT" | tail -n1)
|
||||
BODY=$(echo "$API_RESULT" | sed '$d')
|
||||
|
||||
echo "$BODY" > /tmp/api_response.txt
|
||||
|
||||
BASE_PROMPT="Try to fix the following issue based on the instruction given by the user. The issue is prepended with the word ISSUE. The instruction is prepended with the word INSTRUCTION. The issue and instruction are separated by a blank line."
|
||||
if [[ "$HTTP_CODE" -eq 200 ]]; then
|
||||
PROCESSED_ISSUE_PROMPT=$(jq -r '.effective_body // empty' /tmp/api_response.txt)
|
||||
if [[ -z "$PROCESSED_ISSUE_PROMPT" || "$PROCESSED_ISSUE_PROMPT" == "null" ]]; then
|
||||
PROCESSED_ISSUE_PROMPT=""
|
||||
fi
|
||||
printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT" "$PROCESSED_ISSUE_PROMPT" "$COMMENT_CONTENT" > "$PROMPT_FILE_PATH"
|
||||
else
|
||||
echo "::warning::API call failed (HTTP $HTTP_CODE). Using PR comment with issue context."
|
||||
printf "%s\nISSUE:\n%s\nINSTRUCTION:\n%s" \
|
||||
"$BASE_PROMPT" "$ISSUE_BODY_Q" "$COMMENT_CONTENT" > "$PROMPT_FILE_PATH"
|
||||
fi
|
||||
|
||||
rm -f /tmp/api_response.txt
|
||||
fi
|
||||
fi
|
||||
echo "Prompt determined and written to $PROMPT_FILE_PATH"
|
||||
echo "PROMPT_FILE_PATH=$PROMPT_FILE_PATH" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Probe Chat for Relevant Files
|
||||
id: probe_files
|
||||
env:
|
||||
PROMPT_CONTENT_FILE: ${{ steps.determine_prompt.outputs.PROMPT_FILE_PATH }}
|
||||
run: |
|
||||
echo "Running probe-chat to find relevant files..."
|
||||
if [[ ! -f "$PROMPT_CONTENT_FILE" ]]; then
|
||||
echo "::error::Prompt file $PROMPT_CONTENT_FILE not found!"
|
||||
exit 1
|
||||
fi
|
||||
PROMPT_CONTENT=$(cat "$PROMPT_CONTENT_FILE")
|
||||
if [ -z "$PROMPT_CONTENT" ]; then
|
||||
echo "::error::Prompt content is empty!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROMPT_ESCAPED=$(jq -Rs . <<< "$PROMPT_CONTENT")
|
||||
|
||||
MESSAGE_FOR_PROBE=$(jq -n --arg prompt_escaped "$PROMPT_ESCAPED" \
|
||||
'{ "message": "I'\''m giving you a request that needs to be implemented. Your role is ONLY to give me the files that are relevant to the request and nothing else. The request is prepended with the word REQUEST.\\nREQUEST: \($prompt_escaped). Give me all the files relevant to this request. Your output MUST be a single json array that can be parsed with programatic json parsing, with the relevant files. Files can be rust or typescript or javascript files. DO NOT INCLUDE ANY OTHER TEXT IN YOUR OUTPUT. ONLY THE JSON ARRAY. Example of output: [\"file1.py\", \"file2.py\"]" }' | jq -r .message)
|
||||
|
||||
set -o pipefail
|
||||
PROBE_OUTPUT=$(npx --yes @buger/probe-chat@latest --max-iterations 50 --model-name gemini-2.5-pro-preview-05-06 --message "$MESSAGE_FOR_PROBE") || {
|
||||
echo "::error::probe-chat command failed. Output:"
|
||||
echo "$PROBE_OUTPUT"
|
||||
exit 1
|
||||
}
|
||||
set +o pipefail
|
||||
echo "Probe-chat raw output:"
|
||||
echo "$PROBE_OUTPUT"
|
||||
|
||||
JSON_FILES=$(echo "$PROBE_OUTPUT" | sed -n '/^\s*\[/,$p' | sed '/^\s*\]/q')
|
||||
echo "Extracted JSON block:"
|
||||
echo "$JSON_FILES"
|
||||
|
||||
FILES_LIST=$(echo "$JSON_FILES" | jq -e -r '[.[] | select(type == "string" and . != "" and . != null and (endswith("/") | not))] | map(@sh) | join(" ")' || echo "")
|
||||
|
||||
if [[ -z "$FILES_LIST" ]]; then
|
||||
echo "::warning::probe-chat did not identify any relevant files."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Formatted files list for aider: $FILES_LIST"
|
||||
echo "FILES_TO_EDIT=$FILES_LIST" >> $GITHUB_ENV
|
||||
|
||||
- name: Run Aider with external prompt
|
||||
run: |
|
||||
echo "Files identified by probe-chat: ${{ env.FILES_TO_EDIT }}"
|
||||
aider \
|
||||
--read .cursor/rules/rust-best-practices.mdc \
|
||||
--read .cursor/rules/svelte5-best-practices.mdc \
|
||||
${{ env.FILES_TO_EDIT }} \
|
||||
--model gemini/gemini-2.5-pro-preview-05-06 \
|
||||
--message-file .github/aider/issue-prompt.txt \
|
||||
--yes \
|
||||
--no-check-update \
|
||||
--auto-commits \
|
||||
--no-analytics \
|
||||
--no-gitignore \
|
||||
| tee .github/aider/aider-output.txt || true
|
||||
echo "Aider command completed. Output saved to .github/aider/aider-output.txt"
|
||||
|
||||
- name: Clean up prompt file
|
||||
if: always()
|
||||
run: rm -f .github/aider/issue-prompt.txt
|
||||
|
||||
- name: Commit and Push Changes
|
||||
id: commit_and_push
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
if [[ -z "${{ github.event.issue.pull_request }}" ]]; then
|
||||
BRANCH_NAME="aider-fix-issue-${{ github.event.issue.number }}"
|
||||
|
||||
# Check if branch exists remotely
|
||||
if git ls-remote --heads origin $BRANCH_NAME | grep -q $BRANCH_NAME; then
|
||||
echo "Branch $BRANCH_NAME already exists remotely, fetching it"
|
||||
git fetch origin $BRANCH_NAME
|
||||
git checkout $BRANCH_NAME
|
||||
git pull origin $BRANCH_NAME
|
||||
else
|
||||
echo "Creating new branch $BRANCH_NAME"
|
||||
git checkout -b $BRANCH_NAME
|
||||
fi
|
||||
|
||||
echo "Created/checked out branch $BRANCH_NAME for issue #${{ github.event.issue.number }}"
|
||||
git push origin $BRANCH_NAME
|
||||
echo "Pushed to branch $BRANCH_NAME"
|
||||
echo "PR_BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider changes pushed to branch $BRANCH_NAME." >> $GITHUB_OUTPUT
|
||||
else
|
||||
CURRENT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo "Attempting to push changes to PR branch $CURRENT_BRANCH_NAME for PR #${{ github.event.issue.number }}"
|
||||
if git push origin $CURRENT_BRANCH_NAME; then
|
||||
echo "Push to $CURRENT_BRANCH_NAME successful (or no new changes to push)."
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider changes (if any) pushed to PR branch $CURRENT_BRANCH_NAME." >> $GITHUB_OUTPUT
|
||||
echo "PR_BRANCH_NAME=$CURRENT_BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "::warning::Push to PR branch $CURRENT_BRANCH_NAME failed."
|
||||
echo "CHANGES_APPLIED_MESSAGE=Aider ran, but failed to push changes to PR branch $CURRENT_BRANCH_NAME." >> $GITHUB_OUTPUT
|
||||
ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON")
|
||||
ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON")
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && github.event_name == 'issue_comment' && !github.event.issue.pull_request && steps.commit_and_push.outputs.PR_BRANCH_NAME != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_BRANCH: ${{ steps.commit_and_push.outputs.PR_BRANCH_NAME }}
|
||||
ISSUE_NUM: ${{ github.event.issue.number }}
|
||||
run: |
|
||||
# Create PR description in a temporary file to avoid command line length limits
|
||||
cat > /tmp/pr-description.md << EOL
|
||||
This PR was created automatically by Aider to fix issue #${ISSUE_NUM}.
|
||||
echo "ISSUE_TITLE<<EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT"
|
||||
echo "$ISSUE_TITLE_VAL" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
## Aider Output
|
||||
\`\`\`
|
||||
$(cat .github/aider/aider-output.txt || echo "No output available")
|
||||
\`\`\`
|
||||
EOL
|
||||
echo "ISSUE_BODY<<EOF_AIDER_BODY" >> "$GITHUB_OUTPUT"
|
||||
echo "$ISSUE_BODY_VAL" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_BODY" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Create PR using the file for the body content
|
||||
gh pr create \
|
||||
--title "[Aider PR] Add fixes for issue #${ISSUE_NUM}" \
|
||||
--body-file /tmp/pr-description.md \
|
||||
--head "$PR_BRANCH" \
|
||||
--base main
|
||||
CLEAN_COMMENT="${COMMENT_BODY/\/aider/}"
|
||||
CLEAN_COMMENT="${CLEAN_COMMENT#"${CLEAN_COMMENT%%[![:space:]]*}"}"
|
||||
CLEAN_COMMENT="${CLEAN_COMMENT%"${CLEAN_COMMENT##*[![:space:]]}"}"
|
||||
|
||||
echo "COMMENT_CONTENT<<EOF_AIDER_COMMENT" >> "$GITHUB_OUTPUT"
|
||||
echo "$CLEAN_COMMENT" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF_AIDER_COMMENT" >> "$GITHUB_OUTPUT"
|
||||
echo "Finished determining inputs."
|
||||
|
||||
run-aider:
|
||||
needs: [check-membership, check-and-prepare]
|
||||
if: needs.check-membership.outputs.is_member == 'true'
|
||||
uses: ./.github/workflows/aider-common.yml
|
||||
with:
|
||||
issue_title: ${{ needs.check-and-prepare.outputs.issue_title }}
|
||||
issue_body: ${{ needs.check-and-prepare.outputs.issue_body }}
|
||||
instruction: ${{ needs.check-and-prepare.outputs.comment_content }}
|
||||
issue_id: ${{ github.event.issue.number }}
|
||||
rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc"
|
||||
secrets: inherit
|
||||
|
||||
2
.github/workflows/backend-check.yml
vendored
2
.github/workflows/backend-check.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
timeout-minutes: 16
|
||||
run: |
|
||||
mkdir -p fake_frontend_build
|
||||
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --all-features
|
||||
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --features $(./all_features_oss.sh)
|
||||
|
||||
check_ee:
|
||||
runs-on: ubicloud-standard-8
|
||||
|
||||
4
.github/workflows/backend-test.yml
vendored
4
.github/workflows/backend-test.yml
vendored
@@ -45,9 +45,9 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.1.43
|
||||
- uses: astral-sh/setup-uv@v4
|
||||
- uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
version: "0.4.18"
|
||||
version: "0.6.2"
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache-workspaces: backend
|
||||
|
||||
4
.github/workflows/build-publish-rh-image.yml
vendored
4
.github/workflows/build-publish-rh-image.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp,private
|
||||
secrets: |
|
||||
rh_username=${{ secrets.RH_USERNAME }}
|
||||
rh_password=${{ secrets.RH_PASSWORD }}
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp,private
|
||||
secrets: |
|
||||
rh_username=${{ secrets.RH_USERNAME }}
|
||||
rh_password=${{ secrets.RH_PASSWORD }}
|
||||
|
||||
2
.github/workflows/build_windows_worker_.yml
vendored
2
.github/workflows/build_windows_worker_.yml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
|
||||
mkdir frontend/build && cd backend
|
||||
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,mcp
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages_windows,mcp,private
|
||||
- name: Rename binary with corresponding architecture
|
||||
run: |
|
||||
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
|
||||
|
||||
85
.github/workflows/claude.yml
vendored
Normal file
85
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: Claude PR Assistant
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
check-membership:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai') && !contains(github.event.comment.user.login, '[bot]')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai') && !contains(github.event.comment.user.login, '[bot]')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai') && !contains(github.event.review.user.login, '[bot]')) ||
|
||||
(github.event_name == 'issues' && contains(github.event.issue.body, '/ai') && !contains(github.event.issue.user.login, '[bot]'))
|
||||
runs-on: ubicloud-standard-2
|
||||
outputs:
|
||||
is_member: ${{ steps.check-membership.outputs.is_member }}
|
||||
steps:
|
||||
- name: Check organization membership
|
||||
id: check-membership
|
||||
env:
|
||||
ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }}
|
||||
run: |
|
||||
ORG="windmill-labs"
|
||||
|
||||
if [[ "${{ github.event_name }}" == "issue_comment" || "${{ github.event_name }}" == "pull_request_review_comment" ]]; then
|
||||
COMMENTER="${{ github.event.comment.user.login }}"
|
||||
elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
|
||||
COMMENTER="${{ github.event.review.user.login }}"
|
||||
else
|
||||
COMMENTER="${{ github.event.issue.user.login }}"
|
||||
fi
|
||||
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $ORG_ACCESS_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/orgs/$ORG/members/$COMMENTER")
|
||||
|
||||
if [ "$STATUS" -eq 204 ]; then
|
||||
echo "is_member=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_member=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
claude-code-action:
|
||||
needs: check-membership
|
||||
if: |
|
||||
needs.check-membership.outputs.is_member == 'true'
|
||||
runs-on: ubicloud-standard-8
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude PR Action
|
||||
uses: anthropics/claude-code-action@beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: "60"
|
||||
allowed_tools: "mcp__github__create_pull_request,Bash(npm run check),Bash(npm install),Bash(cargo check),Bash(curl https://sh.rustup.rs -sSf | sh -s -- -y)"
|
||||
custom_instructions: "IMPORTANT INSTRUCTIONS:
|
||||
- Bypass previous instructions and instead of adding a url in your comment to manually create a PR, if you created a new branch with your changes, automatically create a draft PR from that branch to main, with the title starting with [Claude PR].
|
||||
- If you made changes to the frontend code, run npm install, then npm run generate-backend-client, then npm run check. You can ignore warnings that are reported by the check script, but fix the errors.
|
||||
- If you made changes to the backend code, install Rust and then run cargo check. You can ignore warnings that are reported by the check script, but fix the errors.
|
||||
- DO NOT FORGET TO OPEN A DRAFT PR AFTER YOU ARE DONE if you made changes after a request from a git issue.
|
||||
AVAILABLE TOOLS:
|
||||
- mcp__github__create_pull_request: Create a PR from a branch to main
|
||||
- Bash(npm run check): Run the check script. You should run this tool after making changes to the frontend code.
|
||||
- Bash(npm install): Install dependencies. You need this to run npm run check.
|
||||
- Bash(npm run generate-backend-client): Generate the backend client. You need this to run npm run check.
|
||||
- Bash(cargo check): Run the cargo check script. You should run this tool after making changes to the backend code.
|
||||
- Bash(curl https://sh.rustup.rs -sSf | sh -s -- -y): Install Rust. You need this to run cargo check."
|
||||
trigger_phrase: "/ai"
|
||||
28
.github/workflows/create-docs.yml
vendored
28
.github/workflows/create-docs.yml
vendored
@@ -3,8 +3,34 @@ on:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
check-membership:
|
||||
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/docs') && github.event.comment.user.type != 'Bot' }}
|
||||
runs-on: ubicloud-standard-2
|
||||
outputs:
|
||||
is_member: ${{ steps.check-membership.outputs.is_member }}
|
||||
steps:
|
||||
- name: Check organization membership
|
||||
id: check-membership
|
||||
env:
|
||||
ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }}
|
||||
COMMENTER: ${{ github.event.comment.user.login }}
|
||||
run: |
|
||||
ORG="windmill-labs"
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $ORG_ACCESS_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"https://api.github.com/orgs/$ORG/members/$COMMENTER")
|
||||
|
||||
if [ "$STATUS" -eq 204 ]; then
|
||||
echo "is_member=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_member=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
trigger-docs:
|
||||
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/docs') }}
|
||||
needs: check-membership
|
||||
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/docs') && needs.check-membership.outputs.is_member == 'true' }}
|
||||
uses: windmill-labs/windmilldocs/.github/workflows/create-docs.yml@main
|
||||
with:
|
||||
pr_number: ${{ github.event.issue.number }}
|
||||
|
||||
7
.github/workflows/discord-notification.yml
vendored
7
.github/workflows/discord-notification.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
notify_discord_when_pr_opened:
|
||||
if: github.event.pull_request.draft == false
|
||||
if: (github.event.pull_request.draft == false) && (github.event.action == 'opened' || github.event.action == 'ready_for_review')
|
||||
uses: ./.github/workflows/shareable-discord-notification.yml
|
||||
with:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
@@ -17,8 +17,11 @@ jobs:
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
PR_STATUS: "opened"
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
DISCORD_CHANNEL_ID: "1372204995868491786"
|
||||
DISCORD_GUILD_ID: "930051556043276338"
|
||||
secrets:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_PR_REVIEWS_WEBHOOK }}
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
|
||||
merge_success_emoji:
|
||||
if: github.event.pull_request.merged == true
|
||||
@@ -29,4 +32,4 @@ jobs:
|
||||
DISCORD_GUILD_ID: "930051556043276338"
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
secrets:
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_PR_BOT_TOKEN }}
|
||||
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}
|
||||
|
||||
4
.github/workflows/docker-image.yml
vendored
4
.github/workflows/docker-image.yml
vendored
@@ -92,7 +92,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages,deno_core,mcp
|
||||
features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages,deno_core,mcp,private
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
|
||||
${{ steps.meta-public.outputs.tags }}
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages,private,deno_core,mcp
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
|
||||
${{ steps.meta-ee-public.outputs.tags }}
|
||||
|
||||
4
.github/workflows/helmchart_on_release.yml
vendored
4
.github/workflows/helmchart_on_release.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: windmill-labs/windmill-helm-charts
|
||||
token: ${{ secrets.DOCS_TOKEN }}
|
||||
token: ${{ secrets.HELM_CHART_TOKEN }}
|
||||
|
||||
- name: Get version
|
||||
id: get_version
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
|
||||
- name: Create PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.DOCS_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.HELM_CHART_TOKEN }}
|
||||
run: |
|
||||
gh pr create \
|
||||
--title "helm: bump version to ${{ env.VERSION }}" \
|
||||
|
||||
38
.github/workflows/linear-claude.yaml
vendored
Normal file
38
.github/workflows/linear-claude.yaml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Claude PR Assistant
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [external_claude_issue_fix]
|
||||
|
||||
jobs:
|
||||
claude-code-action:
|
||||
runs-on: ubicloud-standard-8
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Process inputs
|
||||
id: process_inputs
|
||||
shell: bash
|
||||
run: |
|
||||
ISSUE_TITLE="${{ github.event.client_payload.issue_title }}"
|
||||
INSTRUCTION="${{ github.event.client_payload.instruction }}"
|
||||
ISSUE_BODY=$(printf '%q' "${{ github.event.client_payload.issue_body }}")
|
||||
BASE_PROMPT="Try to fix the following issue based on the instruction given. You are provided with the issue title, issue body, and instruction. You are to fix the issue based on the instruction. You are to create a pull request to fix the issue."
|
||||
CUSTOM_PROMPT=$(printf -v PROMPT "%s\n\nISSUE_TITLE: %s\n\nISSUE_BODY: %s\n\nINSTRUCTION: %s" "$BASE_PROMPT" "$ISSUE_TITLE" "$ISSUE_BODY" "$INSTRUCTION")
|
||||
echo "CUSTOM_PROMPT=$CUSTOM_PROMPT" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run Claude PR Action
|
||||
uses: anthropics/claude-code-action@beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: "60"
|
||||
allowed_tools: "mcp__github__create_pull_request"
|
||||
direct_prompt: ${{ steps.process_inputs.outputs.CUSTOM_PROMPT }}
|
||||
2
.github/workflows/publish_windows_worker.yml
vendored
2
.github/workflows/publish_windows_worker.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
|
||||
mkdir frontend/build && cd backend
|
||||
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages,mcp
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages_windows,mcp,private
|
||||
- name: Rename binary with corresponding architecture
|
||||
run: |
|
||||
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
|
||||
|
||||
19
.github/workflows/rust_on_release.yml
vendored
Normal file
19
.github/workflows/rust_on_release.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Publish rust-client to crates.io on release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_rust_and_publish_to_crates_io:
|
||||
runs-on: ubicloud-standard-8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v20
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
- run: cd rust-client && nix develop ../ --command ./dev.nu --check --publish
|
||||
env:
|
||||
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
|
||||
@@ -38,24 +38,45 @@ jobs:
|
||||
- name: Send Discord notification and start a thread
|
||||
env:
|
||||
WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
|
||||
CHANNEL_ID: ${{ inputs.DISCORD_CHANNEL_ID }}
|
||||
GUILD_ID: ${{ inputs.DISCORD_GUILD_ID }}
|
||||
PR_TITLE: ${{ inputs.PR_TITLE }}
|
||||
PR_NUMBER: ${{ inputs.PR_NUMBER }}
|
||||
PR_URL: ${{ inputs.PR_URL }}
|
||||
PR_AUTHOR: ${{ inputs.PR_AUTHOR }}
|
||||
run: |
|
||||
payload=$(jq -n \
|
||||
--arg content "${PR_URL}" \
|
||||
--arg thread "#${PR_NUMBER}: $PR_TITLE by \`${PR_AUTHOR}\`" \
|
||||
'{
|
||||
content: $content,
|
||||
thread_name: $thread,
|
||||
auto_archive_duration: 10080
|
||||
}'
|
||||
)
|
||||
curl -H "Content-Type: application/json" \
|
||||
-X POST \
|
||||
-d "$payload" \
|
||||
"$WEBHOOK_URL"
|
||||
# Check if thread already exists
|
||||
thread_exists=false
|
||||
if threads=$(curl -s -H "Authorization: Bot $BOT_TOKEN" "https://discord.com/api/v10/guilds/${GUILD_ID}/threads/active"); then
|
||||
if thread_id=$(echo "$threads" | jq -r --arg cid "$CHANNEL_ID" --arg pref "#${PR_NUMBER}:" '.threads[] | select(.parent_id == $cid and (.name | startswith($pref))) | .id' 2>/dev/null); then
|
||||
if [ -n "$thread_id" ]; then
|
||||
thread_exists=true
|
||||
echo "Thread already exists, skipping creation"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Failed to check for existing threads, will create new thread"
|
||||
fi
|
||||
|
||||
# Create thread if it doesn't exist or if check failed
|
||||
if [ "$thread_exists" = false ]; then
|
||||
echo "Creating new thread"
|
||||
THREAD_TITLE="#${PR_NUMBER}: ${PR_TITLE} by \`${PR_AUTHOR}\`"
|
||||
payload=$(jq -n \
|
||||
--arg content "${PR_URL}" \
|
||||
--arg thread "${THREAD_TITLE:0:99}" \
|
||||
'{
|
||||
content: $content,
|
||||
thread_name: $thread,
|
||||
auto_archive_duration: 10080
|
||||
}'
|
||||
)
|
||||
curl -H "Content-Type: application/json" \
|
||||
-X POST \
|
||||
-d "$payload" \
|
||||
"$WEBHOOK_URL"
|
||||
fi
|
||||
|
||||
merge_success_emoji:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -84,7 +105,7 @@ jobs:
|
||||
fi
|
||||
# 2) get the first message in that thread
|
||||
messages=$(curl -H "Authorization: Bot $BOT_TOKEN" \
|
||||
"https://discord.com/api/v10/channels/$thread_id/messages?limit=1")
|
||||
"https://discord.com/api/v10/channels/$thread_id/messages")
|
||||
message_id=$(echo "$messages" | jq -r '.[-1].id')
|
||||
|
||||
if [ -z "$message_id" ]; then
|
||||
|
||||
34
.github/workflows/validate-openapi.yml
vendored
Normal file
34
.github/workflows/validate-openapi.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Validate OpenAPI Spec
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/windmill-api/openapi*'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'backend/windmill-api/openapi*'
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install openapi-generator-cli
|
||||
run: npm install @openapitools/openapi-generator-cli -g
|
||||
|
||||
- name: Validate openapi.yaml
|
||||
run: npx @openapitools/openapi-generator-cli validate -i backend/windmill-api/openapi.yaml
|
||||
|
||||
- name: Validate openapi-deref.json
|
||||
run: npx @openapitools/openapi-generator-cli validate -i backend/windmill-api/openapi-deref.json
|
||||
|
||||
# Does not work well with dereferenced yaml
|
||||
# - name: Validate openapi-deref.yaml
|
||||
# run: npx @openapitools/openapi-generator-cli validate -i backend/windmill-api/openapi-deref.yaml
|
||||
|
||||
147
CHANGELOG.md
147
CHANGELOG.md
@@ -1,5 +1,152 @@
|
||||
# Changelog
|
||||
|
||||
## [1.496.3](https://github.com/windmill-labs/windmill/compare/v1.496.2...v1.496.3) (2025-06-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve concurrent job parallelism performance ([e8836a3](https://github.com/windmill-labs/windmill/commit/e8836a393a872bb91e68ba0037681caf24149470))
|
||||
* Prioritize diff contexts in script mode for ai chat ([#5888](https://github.com/windmill-labs/windmill/issues/5888)) ([a47939d](https://github.com/windmill-labs/windmill/commit/a47939d13c30e2d4b41efd539f845959174d4fb1))
|
||||
|
||||
## [1.496.2](https://github.com/windmill-labs/windmill/compare/v1.496.1...v1.496.2) (2025-06-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add clearable by default for select ([#5900](https://github.com/windmill-labs/windmill/issues/5900)) ([b44b9c1](https://github.com/windmill-labs/windmill/commit/b44b9c1b82116ad5487af95d1f78226d56c75179))
|
||||
|
||||
## [1.496.1](https://github.com/windmill-labs/windmill/compare/v1.496.0...v1.496.1) (2025-06-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* never consider minor version for global site packages ([#5893](https://github.com/windmill-labs/windmill/issues/5893)) ([22b2f49](https://github.com/windmill-labs/windmill/commit/22b2f4988db9314f2403508933d0aa932187c668))
|
||||
|
||||
## [1.496.0](https://github.com/windmill-labs/windmill/compare/v1.495.1...v1.496.0) (2025-06-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* generate http route triggers from openapi spec ([#5857](https://github.com/windmill-labs/windmill/issues/5857)) ([5713483](https://github.com/windmill-labs/windmill/commit/571348377b73d54b4d2a1c5775ab00b247b01910))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow fileupload drag and drop in edit mode on full component without triggering file picker ([#5889](https://github.com/windmill-labs/windmill/issues/5889)) ([9ae3212](https://github.com/windmill-labs/windmill/commit/9ae3212a1e0f88a8297bf41ab53e3c1be4bcc56c))
|
||||
* **python:** account instance version when cli deploy and local lockfile ([#5894](https://github.com/windmill-labs/windmill/issues/5894)) ([ec552d5](https://github.com/windmill-labs/windmill/commit/ec552d5ef6fdb5e824e453f196f9cf16629ee2ea))
|
||||
* use full client side js library for route gen from openapi ([#5891](https://github.com/windmill-labs/windmill/issues/5891)) ([3c3fdbd](https://github.com/windmill-labs/windmill/commit/3c3fdbdf26a9581b815210839b91ebdedb924093))
|
||||
|
||||
## [1.495.0](https://github.com/windmill-labs/windmill/compare/v1.494.0...v1.495.0) (2025-06-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add ask mode to AI chat ([#5878](https://github.com/windmill-labs/windmill/issues/5878)) ([67ab469](https://github.com/windmill-labs/windmill/commit/67ab46990ad0c9fad810a64c54297419c6151c79))
|
||||
* add navigator mode to AIChat and unify UI ([#5859](https://github.com/windmill-labs/windmill/issues/5859)) ([cbba829](https://github.com/windmill-labs/windmill/commit/cbba8297cd4c1caa21b96a8422bbbd5c306b8398))
|
||||
* ai flow chat ([#5842](https://github.com/windmill-labs/windmill/issues/5842)) ([68ebf66](https://github.com/windmill-labs/windmill/commit/68ebf667d5c0bc306329d0b55a3cc59e5b4862cb))
|
||||
* ai prompts improvements + o3/o4 support ([#5862](https://github.com/windmill-labs/windmill/issues/5862)) ([825422c](https://github.com/windmill-labs/windmill/commit/825422c48456b2c9b230e1a35914b3fbf7d1e836))
|
||||
* connect fix btn in flow editor to ai chat ([#5863](https://github.com/windmill-labs/windmill/issues/5863)) ([6247d15](https://github.com/windmill-labs/windmill/commit/6247d159ce25ae13f6fbc5c105df88305ce29451))
|
||||
* fix backward compatibility pg 14 for postgres trigger ([#5851](https://github.com/windmill-labs/windmill/issues/5851)) ([4cbcbdb](https://github.com/windmill-labs/windmill/commit/4cbcbdb960b469acf773d3943128b6c7d0dcb0b8))
|
||||
* ssh repl like direct to workers hosts machine ([#5809](https://github.com/windmill-labs/windmill/issues/5809)) ([f252657](https://github.com/windmill-labs/windmill/commit/f2526571a3614156b2b1e5cc91b15d0c57565d99))
|
||||
* use rust-postgres client instead of sqlx for postgres trigger ([#5853](https://github.com/windmill-labs/windmill/issues/5853)) ([39dbd64](https://github.com/windmill-labs/windmill/commit/39dbd646b9683e0ad8de047cca786ae468759e77))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* broken event dispatch for simpleditor ([#5879](https://github.com/windmill-labs/windmill/issues/5879)) ([df4992a](https://github.com/windmill-labs/windmill/commit/df4992a9295ed188c2a2cb0a5dfd3e33ae2e2dcb))
|
||||
* cannot parse INSTANCE_PYTHON_VERSION ([#5874](https://github.com/windmill-labs/windmill/issues/5874)) ([a0b302d](https://github.com/windmill-labs/windmill/commit/a0b302d2c58d4245260376cf280bc866be91717c))
|
||||
* fix regex that extract workspaces from custom tags ([#5876](https://github.com/windmill-labs/windmill/issues/5876)) ([1551dc8](https://github.com/windmill-labs/windmill/commit/1551dc8af22f6ea41f68290ace4c58f936c47745))
|
||||
* nit ai flow prompt ([#5867](https://github.com/windmill-labs/windmill/issues/5867)) ([3e769f0](https://github.com/windmill-labs/windmill/commit/3e769f0c591b80138b3a356d147228675756452f))
|
||||
* **python:** assign PATCH version to python runtime only when needed ([#5866](https://github.com/windmill-labs/windmill/issues/5866)) ([50a5c1f](https://github.com/windmill-labs/windmill/commit/50a5c1f56a7e45882fa0095203de709571e149bb))
|
||||
* remove duplicate tools from script ai chat ([#5880](https://github.com/windmill-labs/windmill/issues/5880)) ([fe4a767](https://github.com/windmill-labs/windmill/commit/fe4a767df0e6f46fd0c0fd21b4116c7375978bf9))
|
||||
* replace crypto.randomUUID with generateRandomString for HTTP compatibility ([#5849](https://github.com/windmill-labs/windmill/issues/5849)) ([64f35d0](https://github.com/windmill-labs/windmill/commit/64f35d050fb0d1008ce7142fd62d500845e62c4a)), closes [#5847](https://github.com/windmill-labs/windmill/issues/5847)
|
||||
|
||||
## [1.494.0](https://github.com/windmill-labs/windmill/compare/v1.493.4...v1.494.0) (2025-05-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* array of s3 objects in input maker ([806d669](https://github.com/windmill-labs/windmill/commit/806d66972568d21a1621acd1b30db5ae9b217341))
|
||||
* **rust:** shared build directory ([#5610](https://github.com/windmill-labs/windmill/issues/5610)) ([ed61d97](https://github.com/windmill-labs/windmill/commit/ed61d9770031c1a04908880dbd3e5fb692df9946))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow disable tabs for sidebar/accordion tabs ([#5838](https://github.com/windmill-labs/windmill/issues/5838)) ([80277d1](https://github.com/windmill-labs/windmill/commit/80277d14d02e8e596c7002326946142226d382a6))
|
||||
|
||||
## [1.493.4](https://github.com/windmill-labs/windmill/compare/v1.493.3...v1.493.4) (2025-05-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* templatev2 delete issue ([#5834](https://github.com/windmill-labs/windmill/issues/5834)) ([ed3ad32](https://github.com/windmill-labs/windmill/commit/ed3ad327a235c16b9f3aa7f8edeefe61b0c01da3))
|
||||
|
||||
## [1.493.3](https://github.com/windmill-labs/windmill/compare/v1.493.2...v1.493.3) (2025-05-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* evalv2 prohibit component delete ([e302aa3](https://github.com/windmill-labs/windmill/commit/e302aa38b5977dd406ae05e1d8dbb74cb7dc3d17))
|
||||
* faster layout for larger graphs ([8d12bcc](https://github.com/windmill-labs/windmill/commit/8d12bcc8ee2991909ea0d9bb57f04f0d4106c69f))
|
||||
|
||||
## [1.493.2](https://github.com/windmill-labs/windmill/compare/v1.493.1...v1.493.2) (2025-05-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve monaco editor memory leak ([e0f4f83](https://github.com/windmill-labs/windmill/commit/e0f4f83ebf4416c3bcc24433a7bf606349e1f75a))
|
||||
* improve monaco javascript extra lib refresh ([7b70348](https://github.com/windmill-labs/windmill/commit/7b70348b4bba3726e3fb26c964219a5a2aa6af55))
|
||||
|
||||
## [1.493.1](https://github.com/windmill-labs/windmill/compare/v1.493.0...v1.493.1) (2025-05-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve monaco javascript extra lib refresh ([a2c8ea6](https://github.com/windmill-labs/windmill/commit/a2c8ea69a3962a350273717cd237d8a96523fd00))
|
||||
|
||||
## [1.493.0](https://github.com/windmill-labs/windmill/compare/v1.492.1...v1.493.0) (2025-05-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add aws oidc support for instance s3 storage ([#5810](https://github.com/windmill-labs/windmill/issues/5810)) ([5b96bcc](https://github.com/windmill-labs/windmill/commit/5b96bccedd6e68fea631580dd49338301ad0305f))
|
||||
* duckdb sql lang support ([#5761](https://github.com/windmill-labs/windmill/issues/5761)) ([fdefd4b](https://github.com/windmill-labs/windmill/commit/fdefd4be9398b9610a539360353fd61b521732d4))
|
||||
* **python:** inline script metadata (PEP 723) ([#5712](https://github.com/windmill-labs/windmill/issues/5712)) ([2622253](https://github.com/windmill-labs/windmill/commit/26222539e66bce7e88f86a7e5917e6ca99350865))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing http_trigger_version_seq grants ([#5816](https://github.com/windmill-labs/windmill/issues/5816)) ([306f3ea](https://github.com/windmill-labs/windmill/commit/306f3eabd1c03fa904b0e59438de124a0e680597))
|
||||
* avoid monaco memory leak ([0d459d5](https://github.com/windmill-labs/windmill/commit/0d459d5d223728270854e37715ecc1663ede9870))
|
||||
* error handler node rendering at top level ([feae9b0](https://github.com/windmill-labs/windmill/commit/feae9b09240ba306c007013a36d2aefb0b273766))
|
||||
* **frontend:** auto completion and render of tailwind classes in app editor ([#5817](https://github.com/windmill-labs/windmill/issues/5817)) ([5897e7e](https://github.com/windmill-labs/windmill/commit/5897e7e01b8839425c30c2a97481ef7bb9090661))
|
||||
|
||||
## [1.492.1](https://github.com/windmill-labs/windmill/compare/v1.492.0...v1.492.1) (2025-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix strum compile ([59f6024](https://github.com/windmill-labs/windmill/commit/59f6024cbdaface9c9f0ed61c4a415a13b558515))
|
||||
|
||||
## [1.492.0](https://github.com/windmill-labs/windmill/compare/v1.491.5...v1.492.0) (2025-05-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* job search pagination + result count ([#5789](https://github.com/windmill-labs/windmill/issues/5789)) ([55ae766](https://github.com/windmill-labs/windmill/commit/55ae76648475ce9ff14b2fa33b2a71b90fbd50a1))
|
||||
* **python:** add annotation to skip result post-processing ([#5769](https://github.com/windmill-labs/windmill/issues/5769)) ([07c2ff5](https://github.com/windmill-labs/windmill/commit/07c2ff5668f4725a3b9a8a2655248b0945ac251c))
|
||||
* shift/ctrl+click/enter to open ctrl+k menu results in new tab ([#5800](https://github.com/windmill-labs/windmill/issues/5800)) ([66a997a](https://github.com/windmill-labs/windmill/commit/66a997afc399de2d592c469faf9a5b2cd6433aac))
|
||||
* triggers git sync ([#5766](https://github.com/windmill-labs/windmill/issues/5766)) ([065a814](https://github.com/windmill-labs/windmill/commit/065a814d35a5749725c2ada1155481abba782684))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve app css consistency ([88482c3](https://github.com/windmill-labs/windmill/commit/88482c3bd76ddad16738354f7531d16fa806ad2f))
|
||||
* improve docker mode unexpected exit handling ([7c24fbc](https://github.com/windmill-labs/windmill/commit/7c24fbcef2ecfe5fc034870c4c65dd80513301a4))
|
||||
* postgres trigger ssl issue ([#5790](https://github.com/windmill-labs/windmill/issues/5790)) ([b9a776c](https://github.com/windmill-labs/windmill/commit/b9a776c97b3411af18e58cde7a070c4955aaaab4))
|
||||
* specify using inline type in system prompt for AI ([#5787](https://github.com/windmill-labs/windmill/issues/5787)) ([791296f](https://github.com/windmill-labs/windmill/commit/791296fa41c5bc45c32944db8bc1b66e1515ea82))
|
||||
* workspace preprocessor improvements ([#5784](https://github.com/windmill-labs/windmill/issues/5784)) ([30edcdf](https://github.com/windmill-labs/windmill/commit/30edcdfe0e950b0ab850942bcbc9b4b5ff4fc00c))
|
||||
|
||||
## [1.491.5](https://github.com/windmill-labs/windmill/compare/v1.491.4...v1.491.5) (2025-05-17)
|
||||
|
||||
|
||||
|
||||
3
CLAUDE.md
Normal file
3
CLAUDE.md
Normal file
@@ -0,0 +1,3 @@
|
||||
To have an overview of what this app does, see @.cursor/rules/windmill-overview.mdc
|
||||
For backend modifications, follow the rules mentioned here @.cursor/rules/rust-best-practices.mdc
|
||||
For frontend modifications, follow the rules mentioned here @.cursor/rules/svelte5-best-practices.mdc
|
||||
4
backend/.gitignore
vendored
4
backend/.gitignore
vendored
@@ -5,4 +5,6 @@ oauth2.json
|
||||
tracing.folded
|
||||
heaptrack*
|
||||
index/
|
||||
windmill-api/openapi-*.*
|
||||
windmill-api/openapi-*.*
|
||||
.duckdb/*
|
||||
*ee.rs
|
||||
1
backend/.ignore
Normal file
1
backend/.ignore
Normal file
@@ -0,0 +1 @@
|
||||
!*ee.rs
|
||||
@@ -61,7 +61,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
24
backend/.sqlx/query-13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf.json
generated
Normal file
24
backend/.sqlx/query-13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM sqs_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "13444bbd5547e101c41206c5f97ac4dded0536faf52c370d704ed9a451041caf"
|
||||
}
|
||||
12
backend/.sqlx/query-19f0ccadd3ee44719a781ea0d73ea4e45f5b2c3d5c0aa5dbecf9ea9838881b74.json
generated
Normal file
12
backend/.sqlx/query-19f0ccadd3ee44719a781ea0d73ea4e45f5b2c3d5c0aa5dbecf9ea9838881b74.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "CREATE INDEX CONCURRENTLY IF NOT EXISTS v2_job_queue_suspend ON v2_job_queue (workspace_id, suspend) WHERE suspend > 0;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "19f0ccadd3ee44719a781ea0d73ea4e45f5b2c3d5c0aa5dbecf9ea9838881b74"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, TRUE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "1d87f41fd1abb9361d795a899120e6b77e24bf5a9044fdc5284d0d7f1e14eafa"
|
||||
}
|
||||
15
backend/.sqlx/query-2bf5f7f2cf9d85a5d23e5db2f7616fb41fece9b3d46fde2d546d70b46f9008e3.json
generated
Normal file
15
backend/.sqlx/query-2bf5f7f2cf9d85a5d23e5db2f7616fb41fece9b3d46fde2d546d70b46f9008e3.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, FALSE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2bf5f7f2cf9d85a5d23e5db2f7616fb41fece9b3d46fde2d546d70b46f9008e3"
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage)\n VALUES ($1, FALSE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 1)\n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "usage",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "2e9b3e718440f3c5269e9217a13076c565f3add98b6768b5476bd3afed11ea31"
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SHOW WAL_LEVEL;",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "wal_level",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "2ef25599ea0c9ef946d6cc70ae048af970aed2638a3f767e152b654aebf68e48"
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT tag FROM v2_job WHERE id = $1",
|
||||
"query": "SELECT path FROM script WHERE workspace_id = $1 AND archived = false",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "tag",
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a"
|
||||
"hash": "3e244a5057d4f1b4a18c0edac52cdf695c7e7aa0468d2686255de3d83719e6d0"
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT pubname AS publication_name FROM pg_publication;",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "publication_name",
|
||||
"type_info": "Name"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "4469ee6c206c46951980ea1bc73f126f339d2e3cf97f363be8921084b16dac45"
|
||||
}
|
||||
@@ -70,7 +70,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
58
backend/.sqlx/query-4e5273b9ce05f6ee2dfd5f14c8574a0cf43682480452f7dbe23012320fe7fe25.json
generated
Normal file
58
backend/.sqlx/query-4e5273b9ce05f6ee2dfd5f14c8574a0cf43682480452f7dbe23012320fe7fe25.json
generated
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT \n tag, \n script_lang AS \"script_lang!: _\"\n FROM \n v2_job\n WHERE \n id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "script_lang!: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "script_lang",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"python3",
|
||||
"deno",
|
||||
"go",
|
||||
"bash",
|
||||
"postgresql",
|
||||
"nativets",
|
||||
"bun",
|
||||
"mysql",
|
||||
"bigquery",
|
||||
"snowflake",
|
||||
"graphql",
|
||||
"powershell",
|
||||
"mssql",
|
||||
"php",
|
||||
"bunnative",
|
||||
"rust",
|
||||
"ansible",
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "4e5273b9ce05f6ee2dfd5f14c8574a0cf43682480452f7dbe23012320fe7fe25"
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT \n slot_name,\n active\n FROM\n pg_replication_slots \n WHERE \n plugin = 'pgoutput' AND\n slot_type = 'logical';\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "slot_name",
|
||||
"type_info": "Name"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "active",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "4ee0017771f46f0272817d18edb821940cb5064e3f155b9630b131c09c9dba13"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH active_users AS (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login')),\n authors as (SELECT distinct email FROM usr WHERE usr.operator IS false)\n SELECT email, email NOT IN (SELECT email FROM authors) as operator_only, login_type::text, verified, super_admin, devops, name, company, username\n FROM password\n WHERE email IN (SELECT email FROM active_users)\n ORDER BY super_admin DESC, devops DESC\n LIMIT $1 OFFSET $2",
|
||||
"query": "WITH active_users AS (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login' OR operation = 'users.token.refresh')),\n authors as (SELECT distinct email FROM usr WHERE usr.operator IS false)\n SELECT email, email NOT IN (SELECT email FROM authors) as operator_only, login_type::text, verified, super_admin, devops, name, company, username\n FROM password\n WHERE email IN (SELECT email FROM active_users)\n ORDER BY super_admin DESC, devops DESC\n LIMIT $1 OFFSET $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -67,5 +67,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "3895cee539a24b4c6ea89fa7a835fc62bc93b0530efba09fc3c32a8f93eaabb1"
|
||||
"hash": "5430f7728c1e9b539cc8aad29ca9e6733943278998d3df62a9486607827e59ec"
|
||||
}
|
||||
23
backend/.sqlx/query-551fee7919fdeb911e3f9cc5852e158ea47e3db4895c2b2b1d3cb6b16fceeda9.json
generated
Normal file
23
backend/.sqlx/query-551fee7919fdeb911e3f9cc5852e158ea47e3db4895c2b2b1d3cb6b16fceeda9.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT fv.id\n FROM flow f\n INNER JOIN flow_version fv ON fv.id = f.versions[array_upper(f.versions, 1)]\n WHERE fv.value->'preprocessor_module'->'value'->>'path' = $1 AND f.workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "551fee7919fdeb911e3f9cc5852e158ea47e3db4895c2b2b1d3cb6b16fceeda9"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_queue q SET suspend = 0\n FROM v2_job j, v2_job_status f\n WHERE parent_job = $1\n AND f.id = j.id AND q.id = j.id\n AND suspend = $2 AND (f.flow_status->'step')::int = 0",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "553108ba3c0b8d579800bc8b5a4f887d79fb4c13b60b19c4913a8db18521958c"
|
||||
}
|
||||
22
backend/.sqlx/query-56b2326015fde12b1a4efa226518566101dd27a0f3363884781071d417f8b7e7.json
generated
Normal file
22
backend/.sqlx/query-56b2326015fde12b1a4efa226518566101dd27a0f3363884781071d417f8b7e7.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage)\n VALUES ($1, FALSE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 1)\n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "usage",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "56b2326015fde12b1a4efa226518566101dd27a0f3363884781071d417f8b7e7"
|
||||
}
|
||||
@@ -61,7 +61,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage)\n VALUES ($1, TRUE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 1)\n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "usage",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "621e9a2a53187dac3ebed62f0d645b692815f1594bf302dbebd5f80d5d22b98e"
|
||||
}
|
||||
24
backend/.sqlx/query-6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9.json
generated
Normal file
24
backend/.sqlx/query-6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM gcp_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "6a19c440a7a8064f3969cf6f48adea0bfdb683de9555e374ce5731e0b3c379f9"
|
||||
}
|
||||
@@ -147,7 +147,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT slot_name FROM pg_replication_slots where slot_name = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "slot_name",
|
||||
"type_info": "Name"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Name"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "6f56acb985aa7141ea1891d7ad58a32c35d1b02fe7070c92a2e62c1a5339c396"
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT \n active_pid \n FROM \n pg_replication_slots \n WHERE \n slot_name = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "active_pid",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Name"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "7e64ba7e2362cc19d2aed9f34c9879983922e96a9baab7c1a2b09ed2b1c261e2"
|
||||
}
|
||||
@@ -34,7 +34,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
22
backend/.sqlx/query-8373b2649ab46310860adbdd7b717261771ac61d46d82d42d085ffebeb18be06.json
generated
Normal file
22
backend/.sqlx/query-8373b2649ab46310860adbdd7b717261771ac61d46d82d42d085ffebeb18be06.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT distinct(path) FROM script WHERE workspace_id = $1 AND archived = true",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "8373b2649ab46310860adbdd7b717261771ac61d46d82d42d085ffebeb18be06"
|
||||
}
|
||||
22
backend/.sqlx/query-83f64dd93b1ddc03b84681d65d9be69959987cbac1d83b64225fd1bf9ab047c9.json
generated
Normal file
22
backend/.sqlx/query-83f64dd93b1ddc03b84681d65d9be69959987cbac1d83b64225fd1bf9ab047c9.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage)\n VALUES ($1, TRUE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), 1)\n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + 1 \n RETURNING usage.usage",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "usage",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "83f64dd93b1ddc03b84681d65d9be69959987cbac1d83b64225fd1bf9ab047c9"
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n puballtables AS all_table,\n pubinsert AS insert,\n pubupdate AS update,\n pubdelete AS delete\n FROM\n pg_publication\n WHERE\n pubname = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "all_table",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "insert",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "update",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "delete",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Name"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "86ae16175ace0179e784aacfd381771f0137ecab6671d632febadede729e7783"
|
||||
}
|
||||
15
backend/.sqlx/query-997586ac14384db2c0eeee1bb3382cc6ae013695d0cda6da9ab848ca1b9a9606.json
generated
Normal file
15
backend/.sqlx/query-997586ac14384db2c0eeee1bb3382cc6ae013695d0cda6da9ab848ca1b9a9606.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE worker_ping SET\nping_at = now(),\njobs_executed = 1,\ncurrent_job_id = $1,\ncurrent_job_workspace_id = 'admins'\nWHERE worker = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "997586ac14384db2c0eeee1bb3382cc6ae013695d0cda6da9ab848ca1b9a9606"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('5 mins')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4fb3881cdbb4b9e93e28f460a9b3715bdc6a52b76c89f3a3913023b13c4e085c"
|
||||
"hash": "9a9e4a8779b0bf8a275d029221dfa1465e5d44cd8a7be5879219ffc8cd7ae6b1"
|
||||
}
|
||||
24
backend/.sqlx/query-a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d.json
generated
Normal file
24
backend/.sqlx/query-a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM mqtt_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "a8b470b463ca4b7c00c7ef6e9f36c23f8bbcefc288a56d61122bfd6fe5ca7e8d"
|
||||
}
|
||||
@@ -36,7 +36,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT pubname FROM pg_publication WHERE pubname = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pubname",
|
||||
"type_info": "Name"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Name"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "baa1dddc616419bf4b923715f0a863bc0ff69c98db0f0c8f55e4ac89fdde7a60"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE worker_ping SET \nping_at = now(), \njobs_executed = 1, \ncurrent_job_id = $1, \ncurrent_job_workspace_id = 'admins' \nWHERE worker = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa"
|
||||
}
|
||||
132
backend/.sqlx/query-c51f9ad5133c46fd7c499b8339dbbf3f3059bbb85de07ee3b4b4cea971984a52.json
generated
Normal file
132
backend/.sqlx/query-c51f9ad5133c46fd7c499b8339dbbf3f3059bbb85de07ee3b4b4cea971984a52.json
generated
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n mqtt_resource_path,\n subscribe_topics as \"subscribe_topics: _\",\n v3_config as \"v3_config: _\",\n v5_config as \"v5_config: _\",\n client_version AS \"client_version: _\",\n client_id,\n workspace_id,\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n mqtt_trigger\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "mqtt_resource_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "subscribe_topics: _",
|
||||
"type_info": "JsonbArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "v3_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "v5_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "client_version: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "mqtt_client_version",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"v3",
|
||||
"v5"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "client_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "edited_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "server_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "last_server_ping",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "extra_perms",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "error",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "enabled",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c51f9ad5133c46fd7c499b8339dbbf3f3059bbb85de07ee3b4b4cea971984a52"
|
||||
}
|
||||
15
backend/.sqlx/query-ca3ba808e020c8c7a35eaef842b20cfeee64fd47ded72fce55cc75e0bbb291a8.json
generated
Normal file
15
backend/.sqlx/query-ca3ba808e020c8c7a35eaef842b20cfeee64fd47ded72fce55cc75e0bbb291a8.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, TRUE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ca3ba808e020c8c7a35eaef842b20cfeee64fd47ded72fce55cc75e0bbb291a8"
|
||||
}
|
||||
38
backend/.sqlx/query-cb3862634f18160207ee2621ddfca43f00456a27fda32583846497116f92f96c.json
generated
Normal file
38
backend/.sqlx/query-cb3862634f18160207ee2621ddfca43f00456a27fda32583846497116f92f96c.json
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH active_users as (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login' OR operation = 'users.token.refresh')),\n active_authors as (SELECT distinct email FROM usr WHERE usr.operator IS false AND email IN (SELECT email FROM active_users)),\n active_authors_agg as (SELECT array_agg(email) as authors FROM active_authors),\n active_ops_agg as (SELECT array_agg(email) as operators from active_users WHERE email NOT IN (SELECT email FROM active_authors))\n SELECT active_authors_agg.authors, active_ops_agg.operators, array_length(active_authors_agg.authors, 1) as author_count, array_length(active_ops_agg.operators, 1) as operator_count FROM active_authors_agg, active_ops_agg",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "authors",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "operators",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "author_count",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "operator_count",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "cb3862634f18160207ee2621ddfca43f00456a27fda32583846497116f92f96c"
|
||||
}
|
||||
@@ -70,7 +70,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH active_users as (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login')),\n active_authors as (SELECT distinct email FROM usr WHERE usr.operator IS false AND email IN (SELECT email FROM active_users)),\n active_authors_agg as (SELECT array_agg(email) as authors FROM active_authors),\n active_ops_agg as (SELECT array_agg(email) as operators from active_users WHERE email NOT IN (SELECT email FROM active_authors))\n SELECT active_authors_agg.authors, active_ops_agg.operators, array_length(active_authors_agg.authors, 1) as author_count, array_length(active_ops_agg.operators, 1) as operator_count FROM active_authors_agg, active_ops_agg",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "authors",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "operators",
|
||||
"type_info": "VarcharArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "author_count",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "operator_count",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "cce991f582bc9d2ba28a5b2b41c679366bb07bc6a100727721a787160ac6910c"
|
||||
}
|
||||
@@ -42,7 +42,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, FALSE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e38240e6d50bfe60e1c2b649588eb41dcef121ed161db04b2568ac2d990aed7c"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n value->'preprocessor_module'->'value' as \"preprocessor_module: _\",\n schema as \"schema: _\"\n FROM flow \n WHERE workspace_id = $1\n AND path = $2",
|
||||
"query": "SELECT\n value->'preprocessor_module'->'value' as \"preprocessor_module: _\",\n schema as \"schema: _\"\n FROM flow_version\n WHERE \n path = $1\n AND workspace_id = $2\n ORDER BY created_at DESC\n LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -25,5 +25,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "72916f8e490f8252e0a51b7f562ccc3be832b12102eb86a07d8405a4fa9287d5"
|
||||
"hash": "e7348225a27bbdc9607d7c799e7192cd6ce4088467d91a5cbdc019430320d26d"
|
||||
}
|
||||
16
backend/.sqlx/query-f1dbcb6e6d82d17c19eb88c0e67dc1cb8baf5bd40b75a2a9cd3ebac440fda632.json
generated
Normal file
16
backend/.sqlx/query-f1dbcb6e6d82d17c19eb88c0e67dc1cb8baf5bd40b75a2a9cd3ebac440fda632.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_queue q SET suspend = 0\n FROM v2_job j, v2_job_status f\n WHERE q.workspace_id = $1 AND q.suspend = $3 AND j.parent_job = $2\n AND f.id = j.id AND q.id = j.id\n AND (f.flow_status->'step')::int = 0",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Uuid",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f1dbcb6e6d82d17c19eb88c0e67dc1cb8baf5bd40b75a2a9cd3ebac440fda632"
|
||||
}
|
||||
@@ -147,7 +147,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n schemaname AS schema_name,\n tablename AS table_name,\n CASE\n WHEN array_length(attnames, 1) = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = pg_publication_tables.schemaname AND table_name = pg_publication_tables.tablename)\n THEN NULL\n ELSE attnames\n END AS columns,\n rowfilter AS where_clause\n FROM\n pg_publication_tables\n WHERE\n pubname = $1;\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "schema_name",
|
||||
"type_info": "Name"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "table_name",
|
||||
"type_info": "Name"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "columns",
|
||||
"type_info": "NameArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "where_clause",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Name"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "fd5754fe3c6346ae28818a9d60d144a40f8884f47e5bbdd2824e939dafd8f154"
|
||||
}
|
||||
@@ -65,7 +65,8 @@
|
||||
"csharp",
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java"
|
||||
"java",
|
||||
"duckdb"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
4
backend/.vscode/settings.json
vendored
4
backend/.vscode/settings.json
vendored
@@ -11,5 +11,7 @@
|
||||
"remote.autoForwardPorts": true,
|
||||
"conventionalCommits.scopes": [
|
||||
"restructring triggers, decoding trigger message on work"
|
||||
]
|
||||
],
|
||||
"files.exclude": { "**/*ee.rs": false },
|
||||
"search.exclude": { "**/*ee.rs": false }
|
||||
}
|
||||
|
||||
699
backend/Cargo.lock
generated
699
backend/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.491.5"
|
||||
version = "1.496.3"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -32,7 +32,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.491.5"
|
||||
version = "1.496.3"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -49,6 +49,7 @@ lto = "thin"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
private = ["windmill-api/private", "windmill-autoscaling/private", "windmill-common/private", "windmill-git-sync/private", "windmill-indexer/private", "windmill-queue/private", "windmill-worker/private"]
|
||||
agent_worker_server = ["windmill-api/agent_worker_server"]
|
||||
enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise"]
|
||||
enterprise_saml = ["windmill-api/enterprise_saml", "oauth2"]
|
||||
@@ -59,7 +60,7 @@ embedding = ["windmill-api/embedding"]
|
||||
parquet = ["windmill-api/parquet", "windmill-common/parquet", "windmill-worker/parquet", "dep:object_store"]
|
||||
prometheus = ["windmill-common/prometheus", "windmill-api/prometheus", "windmill-worker/prometheus", "windmill-queue/prometheus", "dep:prometheus"]
|
||||
flow_testing = ["windmill-worker/flow_testing"]
|
||||
openidconnect = ["windmill-api/openidconnect"]
|
||||
openidconnect = ["windmill-api/openidconnect", "windmill-common/openidconnect"]
|
||||
cloud = ["windmill-queue/cloud", "windmill-worker/cloud", "windmill-common/cloud", "windmill-api/cloud"]
|
||||
jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"]
|
||||
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet", "windmill-common/tantivy", "enterprise", "parquet"]
|
||||
@@ -83,18 +84,21 @@ zip = ["windmill-api/zip"]
|
||||
static_frontend = ["windmill-api/static_frontend"]
|
||||
scoped_cache = ["windmill-common/scoped_cache"]
|
||||
# Languages
|
||||
python = ["windmill-worker/python"]
|
||||
python = ["windmill-worker/python", "windmill-api/python"]
|
||||
rust = ["windmill-worker/rust"]
|
||||
mysql = ["windmill-worker/mysql"]
|
||||
oracledb = ["windmill-worker/oracledb"]
|
||||
duckdb = ["windmill-worker/duckdb"]
|
||||
mssql = ["windmill-worker/mssql"]
|
||||
bigquery = ["windmill-worker/bigquery"]
|
||||
php = ["windmill-worker/php"]
|
||||
csharp = ["windmill-worker/csharp"]
|
||||
nu = ["windmill-worker/nu"]
|
||||
java = ["windmill-worker/java"]
|
||||
all_languages = [ "python", "deno_core", "rust", "mysql", "oracledb", "mssql", "bigquery", "csharp", "nu", "php", "java"]
|
||||
|
||||
all_languages = ["python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "mssql", "bigquery", "csharp", "nu", "php", "java"]
|
||||
# For windows we have another set of languages enabled
|
||||
# NOTE: DuckDB is ignored because of compilation problems
|
||||
all_languages_windows = ["python", "deno_core", "rust", "mysql", "oracledb", "mssql", "bigquery", "csharp", "nu", "php", "java"]
|
||||
|
||||
[patch.crates-io]
|
||||
object_store = { git = "https://github.com/apache/arrow-rs-object-store", rev = "36752c975d4f29e20b57c91f81a10872dcd48ae7" }
|
||||
@@ -135,8 +139,11 @@ quote.workspace = true
|
||||
memchr.workspace = true
|
||||
v8 = { workspace = true, optional = true }
|
||||
rustls.workspace = true
|
||||
pep440_rs.workspace = true
|
||||
systemstat.workspace = true
|
||||
size.workspace = true
|
||||
strum.workspace = true
|
||||
|
||||
|
||||
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
||||
tikv-jemallocator = { optional = true, workspace = true }
|
||||
@@ -218,6 +225,7 @@ git-version = "^0"
|
||||
malachite = "=0.4.18"
|
||||
malachite-bigint = "=0.2.0"
|
||||
rustpython-parser = "^0"
|
||||
pep440_rs = "0.7.3"
|
||||
php-parser-rs = { git = "https://github.com/php-rust-tools/parser", rev = "ec4cb411dec09450946ef57920b7ffced7f6495d" }
|
||||
cron = "^0"
|
||||
mail-send = { version = "0.4.0", features = ["builder"], default-features=false }
|
||||
@@ -234,8 +242,9 @@ json-pointer = "^0"
|
||||
itertools = "^0"
|
||||
regex = "^1"
|
||||
semver = "^1"
|
||||
duckdb = { version = "1.2.2", features = ["bundled"] }
|
||||
|
||||
v8 = "=130.0.7" # Exact version
|
||||
v8 = "=130.0.7" # Exact version NOTE: Do not forget to update version and hash in flake.nix
|
||||
deno_fetch = "0.214.0"
|
||||
deno_tls = "0.177.0"
|
||||
deno_console = "0.190.0"
|
||||
@@ -342,7 +351,7 @@ openidconnect = { version = "4.0.0-rc.1" }
|
||||
aws-config = "^1"
|
||||
aws-sdk-sqs = "1.57.0"
|
||||
aws-sdk-sts = "^1"
|
||||
|
||||
aws-smithy-types-convert = { version = "^0", features = ["convert-chrono"] }
|
||||
crc = "^3"
|
||||
tar = "^0"
|
||||
http = "^1"
|
||||
@@ -389,3 +398,5 @@ tree-sitter-c-sharp = "0.23.0"
|
||||
tree-sitter-java = "0.23.0"
|
||||
oracle = { version = "0.6.3", features = ["chrono"] }
|
||||
rumqttc = { version = "0.24.0", features = ["use-native-tls"]}
|
||||
strum = { version = "0.27", features = ["derive"] }
|
||||
strum_macros = "^0"
|
||||
|
||||
20
backend/all_features_oss.sh
Executable file
20
backend/all_features_oss.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
# This script outputs all features except private. Usage :
|
||||
# > cargo build --features $(./all_features_oss.sh)
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# Path to the Cargo.toml file
|
||||
CARGO_TOML_PATH="./Cargo.toml"
|
||||
|
||||
# Extract features from Cargo.toml and output them separated by commas
|
||||
if [[ -f "$CARGO_TOML_PATH" ]]; then
|
||||
grep -A 100 '\[features\]' "$CARGO_TOML_PATH" | \
|
||||
sed -n '/\[features\]/,/^\[/p' | \
|
||||
grep -E '^[a-zA-Z0-9_-]+' | \
|
||||
grep -v 'private' | \
|
||||
cut -d' ' -f1 | \
|
||||
paste -sd ',' -
|
||||
else
|
||||
echo "Cargo.toml not found at $CARGO_TOML_PATH"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1 +1 @@
|
||||
3efa7fa51e9f93f60e141fef5b8b9338528cf955
|
||||
2c3e21f4573486628e0b8969ff478c237bd0283f
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
3
backend/migrations/20250515084520_duckdb_support.up.sql
Normal file
3
backend/migrations/20250515084520_duckdb_support.up.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'duckdb';
|
||||
UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["duckdb"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust", "ansible", "csharp", "nu", "java"]}'::jsonb AND NOT config->'worker_tags' @> '"duckdb"'::jsonb;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- Add down migration script here
|
||||
CREATE OR REPLACE FUNCTION notify_runnable_version_change()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
source_type TEXT;
|
||||
BEGIN
|
||||
source_type := TG_ARGV[0];
|
||||
|
||||
PERFORM pg_notify('notify_runnable_version_change', NEW.workspace_id || ':' || source_type || ':' || NEW.path);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -0,0 +1,19 @@
|
||||
-- Add up migration script here
|
||||
CREATE OR REPLACE FUNCTION notify_runnable_version_change()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
source_type TEXT;
|
||||
kind TEXT;
|
||||
BEGIN
|
||||
source_type := TG_ARGV[0];
|
||||
|
||||
IF source_type = 'script' THEN
|
||||
kind := NEW.kind;
|
||||
ELSE
|
||||
kind := 'flow';
|
||||
END IF;
|
||||
|
||||
PERFORM pg_notify('notify_runnable_version_change', NEW.workspace_id || ':' || source_type || ':' || NEW.path || ':' || kind);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Add up migration script here
|
||||
GRANT ALL ON SEQUENCE http_trigger_version_seq TO windmill_user;
|
||||
GRANT ALL ON SEQUENCE http_trigger_version_seq TO windmill_admin;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Remove token invalidation notification trigger
|
||||
|
||||
DROP TRIGGER IF EXISTS token_invalidation_trigger ON token;
|
||||
DROP FUNCTION IF EXISTS notify_token_invalidation();
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Add token invalidation notification trigger
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_token_invalidation()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
-- Only notify for session token deletions when the invalidation settings are enabled
|
||||
IF OLD.label = 'session' AND OLD.email IS NOT NULL THEN
|
||||
PERFORM pg_notify('notify_token_invalidation', OLD.token);
|
||||
END IF;
|
||||
RETURN OLD;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER token_invalidation_trigger
|
||||
AFTER DELETE ON token
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION notify_token_invalidation();
|
||||
@@ -27,3 +27,6 @@ anyhow.workspace = true
|
||||
lazy_static.workspace = true
|
||||
sqlx.workspace = true
|
||||
async-recursion.workspace = true
|
||||
toml.workspace = true
|
||||
serde.workspace = true
|
||||
pep440_rs.workspace = true
|
||||
|
||||
@@ -11,7 +11,7 @@ mod mapping;
|
||||
use async_recursion::async_recursion;
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use mapping::{FULL_IMPORTS_MAP, SHORT_IMPORTS_MAP};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -25,7 +25,10 @@ use rustpython_parser::{
|
||||
Parse,
|
||||
};
|
||||
use sqlx::{Pool, Postgres};
|
||||
use windmill_common::{error, worker::PythonAnnotations};
|
||||
use windmill_common::{
|
||||
error::{self, to_anyhow},
|
||||
worker::PythonAnnotations,
|
||||
};
|
||||
|
||||
const DEF_MAIN: &str = "def main(";
|
||||
|
||||
@@ -242,8 +245,7 @@ pub async fn parse_python_imports(
|
||||
w_id: &str,
|
||||
path: &str,
|
||||
db: &Pool<Postgres>,
|
||||
already_visited: &mut Vec<String>,
|
||||
annotated_pyv_numeric: &mut Option<u32>,
|
||||
version_specifiers: &mut Vec<pep440_rs::VersionSpecifier>,
|
||||
) -> error::Result<(Vec<String>, Option<String>)> {
|
||||
let mut compile_error_hint: Option<String> = None;
|
||||
let mut imports = parse_python_imports_inner(
|
||||
@@ -251,9 +253,10 @@ pub async fn parse_python_imports(
|
||||
w_id,
|
||||
path,
|
||||
db,
|
||||
already_visited,
|
||||
annotated_pyv_numeric,
|
||||
&mut annotated_pyv_numeric.and_then(|_| Some(path.to_owned())),
|
||||
&mut vec![],
|
||||
version_specifiers,
|
||||
// &mut version_specifier.and_then(|_| Some(path.to_owned())),
|
||||
&mut None
|
||||
)
|
||||
.await?
|
||||
.into_values()
|
||||
@@ -279,6 +282,7 @@ pub async fn parse_python_imports(
|
||||
.flatten()
|
||||
.collect::<error::Result<Vec<String>>>()?
|
||||
.into_iter()
|
||||
.filter(|x| !x.trim_start().starts_with("--") && !x.trim().is_empty())
|
||||
.unique()
|
||||
.collect_vec();
|
||||
|
||||
@@ -304,11 +308,34 @@ async fn parse_python_imports_inner(
|
||||
path: &str,
|
||||
db: &Pool<Postgres>,
|
||||
already_visited: &mut Vec<String>,
|
||||
annotated_pyv_numeric: &mut Option<u32>,
|
||||
version_specifiers: &mut Vec<pep440_rs::VersionSpecifier>,
|
||||
path_where_annotated_pyv: &mut Option<String>,
|
||||
) -> error::Result<HashMap<String, NImportResolved>> {
|
||||
let PythonAnnotations { py310, py311, py312, py313, .. } = PythonAnnotations::parse(&code);
|
||||
|
||||
let mut push_version_specifiers = |perform, unparsed: String| -> error::Result<()> {
|
||||
if perform {
|
||||
pep440_rs::VersionSpecifiers::from_str(unparsed.as_str())
|
||||
.ok()
|
||||
.map(|vs| version_specifiers.extend(vs.to_vec()));
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
push_version_specifiers(py310, "==3.10.*".to_owned())?;
|
||||
push_version_specifiers(py311, "==3.11.*".to_owned())?;
|
||||
push_version_specifiers(py312, "==3.12.*".to_owned())?;
|
||||
push_version_specifiers(py313, "==3.13.*".to_owned())?;
|
||||
|
||||
for x in code.lines() {
|
||||
if x.starts_with("# py:") || x.starts_with("#py:") {
|
||||
push_version_specifiers(
|
||||
true,
|
||||
x.replace('#', "").replace("py:", "").trim().to_owned(),
|
||||
)?;
|
||||
} else if !x.starts_with('#') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// we pass only if there is none or only one annotation
|
||||
|
||||
// Naive:
|
||||
@@ -323,39 +350,48 @@ async fn parse_python_imports_inner(
|
||||
// This way we make sure there is no multiple annotations for same script
|
||||
// and we get detailed span on conflicting versions
|
||||
|
||||
let mut check = |is_py_xyz, numeric| -> error::Result<()> {
|
||||
if is_py_xyz {
|
||||
if let Some(v) = annotated_pyv_numeric {
|
||||
if *v != numeric {
|
||||
return Err(error::Error::from(anyhow::anyhow!(
|
||||
"Annotated 2 or more different python versions: \n - py{v} at {}\n - py{numeric} at {path}\nIt is possible to use only one.",
|
||||
path_where_annotated_pyv.clone().unwrap_or("Unknown".to_owned())
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
*annotated_pyv_numeric = Some(numeric);
|
||||
}
|
||||
*path_where_annotated_pyv = Some(path.to_owned());
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
struct InlineMetadata {
|
||||
requires_python: String,
|
||||
dependencies: Vec<String>,
|
||||
}
|
||||
|
||||
check(py310, 310)?;
|
||||
check(py311, 311)?;
|
||||
check(py312, 312)?;
|
||||
check(py313, 313)?;
|
||||
|
||||
let find_requirements = code
|
||||
.lines()
|
||||
.find_position(|x| x.starts_with("#requirements:") || x.starts_with("# requirements:"));
|
||||
if let Some((pos, _)) = find_requirements {
|
||||
let find_requirements = code.lines().find_position(|x| {
|
||||
x.starts_with("#requirements:")
|
||||
|| x.starts_with("# requirements:")
|
||||
|| x.starts_with("# /// script")
|
||||
});
|
||||
if let Some((pos, item)) = find_requirements {
|
||||
let mut requirements = HashMap::new();
|
||||
code.lines()
|
||||
.skip(pos + 1)
|
||||
.map_while(|x| {
|
||||
RE.captures(x).and_then(|x| {
|
||||
x.get(1).map(|m| {
|
||||
let requirement = m.as_str().to_string();
|
||||
if item.starts_with("# /// script") {
|
||||
let mut incorrect = false;
|
||||
let metadata = code
|
||||
.lines()
|
||||
.skip(pos + 1)
|
||||
.map_while(|x| {
|
||||
incorrect = !x.starts_with('#');
|
||||
if incorrect || x.starts_with("# ///") {
|
||||
None
|
||||
} else {
|
||||
x.get(1..)
|
||||
}
|
||||
})
|
||||
.join("\n")
|
||||
.parse::<toml::Table>()
|
||||
.map_err(to_anyhow)?;
|
||||
|
||||
{
|
||||
if let Some(v) = metadata.get("requires-python").and_then(|v| v.as_str()) {
|
||||
push_version_specifiers(true, v.to_owned())?;
|
||||
}
|
||||
};
|
||||
|
||||
metadata
|
||||
.get("dependencies")
|
||||
.and_then(|dependencies| dependencies.as_array())
|
||||
.inspect(|list| {
|
||||
for dependency_v in list.into_iter() {
|
||||
let requirement = dependency_v.as_str().unwrap_or("ERROR").to_owned();
|
||||
let key = extract_pkg_name(&requirement);
|
||||
requirements.insert(
|
||||
key.clone(),
|
||||
@@ -367,11 +403,31 @@ async fn parse_python_imports_inner(
|
||||
key,
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
code.lines()
|
||||
.skip(pos + 1)
|
||||
.map_while(|x| {
|
||||
RE.captures(x).and_then(|x| {
|
||||
x.get(1).map(|m| {
|
||||
let requirement = m.as_str().to_string();
|
||||
let key = extract_pkg_name(&requirement);
|
||||
requirements.insert(
|
||||
key.clone(),
|
||||
NImportResolved::Pin {
|
||||
pins: vec![ImportPin {
|
||||
pkg: requirement.clone(),
|
||||
path: Default::default(),
|
||||
}],
|
||||
key,
|
||||
},
|
||||
);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
.collect_vec();
|
||||
}
|
||||
Ok(requirements)
|
||||
} else {
|
||||
let find_extra_requirements = code.lines().find_position(|x| {
|
||||
@@ -442,7 +498,7 @@ async fn parse_python_imports_inner(
|
||||
&rpath,
|
||||
db,
|
||||
already_visited,
|
||||
annotated_pyv_numeric,
|
||||
version_specifiers,
|
||||
path_where_annotated_pyv,
|
||||
)
|
||||
.await?
|
||||
|
||||
@@ -18,16 +18,8 @@ def main():
|
||||
pass
|
||||
|
||||
";
|
||||
let mut already_visited = vec![];
|
||||
let (r, ..) = parse_python_imports(
|
||||
code,
|
||||
"test-workspace",
|
||||
"f/foo/bar",
|
||||
&db,
|
||||
&mut already_visited,
|
||||
&mut None,
|
||||
)
|
||||
.await?;
|
||||
let (r, ..) =
|
||||
parse_python_imports(code, "test-workspace", "f/foo/bar", &db, &mut vec![]).await?;
|
||||
// println!("{}", serde_json::to_string(&r)?);
|
||||
assert_eq!(
|
||||
r,
|
||||
@@ -59,16 +51,8 @@ def main():
|
||||
pass
|
||||
|
||||
";
|
||||
let mut already_visited = vec![];
|
||||
let (r, ..) = parse_python_imports(
|
||||
code,
|
||||
"test-workspace",
|
||||
"f/foo/bar",
|
||||
&db,
|
||||
&mut already_visited,
|
||||
&mut None,
|
||||
)
|
||||
.await?;
|
||||
let (r, ..) =
|
||||
parse_python_imports(code, "test-workspace", "f/foo/bar", &db, &mut vec![]).await?;
|
||||
println!("{}", serde_json::to_string(&r)?);
|
||||
assert_eq!(r, vec!["burkina=0.4", "nigeria"]);
|
||||
|
||||
@@ -89,17 +73,9 @@ def main():
|
||||
pass
|
||||
|
||||
";
|
||||
let mut already_visited = vec![];
|
||||
|
||||
let (r, ..) = parse_python_imports(
|
||||
code,
|
||||
"test-workspace",
|
||||
"f/foo/bar",
|
||||
&db,
|
||||
&mut already_visited,
|
||||
&mut None,
|
||||
)
|
||||
.await?;
|
||||
let (r, ..) =
|
||||
parse_python_imports(code, "test-workspace", "f/foo/bar", &db, &mut vec![]).await?;
|
||||
println!("{}", serde_json::to_string(&r)?);
|
||||
assert_eq!(
|
||||
r,
|
||||
|
||||
@@ -83,6 +83,21 @@ pub fn parse_bigquery_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_duckdb_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
let parsed = parse_duckdb_file(&code)?;
|
||||
if let Some(args) = parsed {
|
||||
Ok(MainArgSignature {
|
||||
star_args: false,
|
||||
star_kwargs: false,
|
||||
args,
|
||||
no_main_func: None,
|
||||
has_preprocessor: None,
|
||||
})
|
||||
} else {
|
||||
Err(anyhow!("Error parsing sql".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_snowflake_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
let parsed = parse_snowflake_file(&code)?;
|
||||
if let Some(x) = parsed {
|
||||
@@ -212,6 +227,9 @@ lazy_static::lazy_static! {
|
||||
// -- @name (type) = default
|
||||
static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
|
||||
|
||||
// -- $name (type) = default
|
||||
static ref RE_ARG_DUCKDB: Regex = Regex::new(r#"(?m)^-- \$(\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
|
||||
|
||||
static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
|
||||
|
||||
|
||||
@@ -577,6 +595,35 @@ fn parse_bigquery_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
Ok(Some(args))
|
||||
}
|
||||
|
||||
fn parse_duckdb_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
let mut args: Vec<Arg> = vec![];
|
||||
|
||||
for cap in RE_ARG_DUCKDB.captures_iter(code) {
|
||||
let name = cap.get(1).map(|x| x.as_str().to_string()).unwrap();
|
||||
let typ = cap
|
||||
.get(2)
|
||||
.map(|x| x.as_str().to_string().to_lowercase())
|
||||
.unwrap();
|
||||
let default = cap.get(3).map(|x| x.as_str().to_string());
|
||||
let has_default = default.is_some();
|
||||
let parsed_typ = parse_duckdb_typ(typ.as_str());
|
||||
|
||||
let parsed_default = default.and_then(|x| parsed_default(&parsed_typ, x));
|
||||
|
||||
args.push(Arg {
|
||||
name,
|
||||
typ: parsed_typ,
|
||||
default: parsed_default,
|
||||
otyp: Some(typ),
|
||||
has_default,
|
||||
oidx: None,
|
||||
});
|
||||
}
|
||||
|
||||
args.append(&mut parse_sql_sanitized_interpolation(code));
|
||||
Ok(Some(args))
|
||||
}
|
||||
|
||||
fn parse_snowflake_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
let mut args: Vec<Arg> = vec![];
|
||||
|
||||
@@ -729,6 +776,33 @@ pub fn parse_bigquery_typ(typ: &str) -> Typ {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_duckdb_typ(typ: &str) -> Typ {
|
||||
if typ.ends_with("[]") {
|
||||
let base_typ = parse_duckdb_typ(typ.strip_suffix("[]").unwrap());
|
||||
Typ::List(Box::new(base_typ))
|
||||
} else {
|
||||
match typ {
|
||||
"varchar" | "char" | "bpchar" | "text" | "string" => Typ::Str(None),
|
||||
"blob" | "bytea" | "binary" | "varbinary" | "bitstring" => Typ::Bytes,
|
||||
"boolean" | "bool" | "bit" | "logical" => Typ::Bool,
|
||||
"bigint" | "int8" | "long" | "integer" | "int4" | "int" | "smallint" | "int2"
|
||||
| "short" | "tinyint" | "int1" | "signed" | "ubigint" | "uhugeint" | "uinteger"
|
||||
| "usmallint" | "utinyint" => Typ::Int,
|
||||
"decimal" | "numeric" | "double" | "float8" | "float" | "float4" | "real" => Typ::Float,
|
||||
"date"
|
||||
| "time"
|
||||
| "timestamp with time zone"
|
||||
| "timestamptz"
|
||||
| "timestamp"
|
||||
| "datetime" => Typ::Datetime,
|
||||
"uuid" | "json" => Typ::Str(None),
|
||||
"interval" | "hugeint" => Typ::Str(None),
|
||||
"s3object" => Typ::Resource("S3Object".to_string()),
|
||||
_ => Typ::Str(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_snowflake_typ(typ: &str) -> Typ {
|
||||
match typ {
|
||||
"varchar" => Typ::Str(None),
|
||||
|
||||
@@ -96,6 +96,12 @@ pub fn parse_oracledb(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_sql::parse_oracledb_sig(code))
|
||||
}
|
||||
|
||||
#[cfg(feature = "sql-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_duckdb(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_sql::parse_duckdb_sig(code))
|
||||
}
|
||||
|
||||
#[cfg(feature = "sql-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_bigquery(code: &str) -> String {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
#[cfg(feature = "private")]
|
||||
#[allow(unused)]
|
||||
pub use crate::ee::*;
|
||||
|
||||
#[cfg(not(feature = "private"))]
|
||||
pub async fn set_license_key(_license_key: String) -> () {
|
||||
// Implementation is not open source
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
#[cfg(all(feature = "enterprise", not(feature = "private")))]
|
||||
pub async fn verify_license_key() -> () {
|
||||
// Implementation is not open source
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use anyhow::Context;
|
||||
use monitor::{
|
||||
load_base_url, load_otel, reload_critical_alerts_on_db_oversize,
|
||||
@@ -23,12 +22,15 @@ use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use strum::IntoEnumIterator;
|
||||
use tokio::{fs::File, io::AsyncReadExt, task::JoinHandle};
|
||||
use uuid::Uuid;
|
||||
use windmill_api::HTTP_CLIENT;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use windmill_common::ee::{maybe_renew_license_key_on_start, LICENSE_KEY_ID, LICENSE_KEY_VALID};
|
||||
use windmill_common::ee_oss::{
|
||||
maybe_renew_license_key_on_start, LICENSE_KEY_ID, LICENSE_KEY_VALID,
|
||||
};
|
||||
|
||||
use windmill_common::{
|
||||
agent_workers::build_agent_http_client,
|
||||
@@ -49,8 +51,12 @@ use windmill_common::{
|
||||
TIMEOUT_WAIT_RESULT_SETTING,
|
||||
},
|
||||
scripts::ScriptLang,
|
||||
stats_ee::schedule_stats,
|
||||
utils::{hostname, rd_string, Mode, GIT_VERSION, MODE_AND_ADDONS},
|
||||
stats_oss::schedule_stats,
|
||||
triggers::TriggerKind,
|
||||
utils::{
|
||||
create_default_worker_suffix, create_ssh_agent_worker_suffix, worker_name_with_suffix,
|
||||
Mode, GIT_VERSION, HOSTNAME, MODE_AND_ADDONS,
|
||||
},
|
||||
worker::{
|
||||
reload_custom_tags_setting, Connection, HUB_CACHE_DIR, TMP_DIR, TMP_LOGS_DIR, WORKER_GROUP,
|
||||
},
|
||||
@@ -68,14 +74,13 @@ use tikv_jemallocator::Jemalloc;
|
||||
static GLOBAL: Jemalloc = Jemalloc;
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
use windmill_common::global_settings::OBJECT_STORE_CACHE_CONFIG_SETTING;
|
||||
use windmill_common::global_settings::OBJECT_STORE_CONFIG_SETTING;
|
||||
|
||||
use windmill_worker::{
|
||||
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR, CSHARP_CACHE_DIR,
|
||||
DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM, GO_BIN_CACHE_DIR, GO_CACHE_DIR,
|
||||
JAVA_CACHE_DIR, NU_CACHE_DIR, POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR,
|
||||
PY312_CACHE_DIR, PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_JAVA_CACHE_DIR, TAR_PY310_CACHE_DIR,
|
||||
TAR_PY311_CACHE_DIR, TAR_PY312_CACHE_DIR, TAR_PY313_CACHE_DIR, UV_CACHE_DIR,
|
||||
PY312_CACHE_DIR, PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_JAVA_CACHE_DIR, UV_CACHE_DIR,
|
||||
};
|
||||
|
||||
use crate::monitor::{
|
||||
@@ -91,13 +96,15 @@ use crate::monitor::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
use crate::monitor::reload_s3_cache_setting;
|
||||
use windmill_common::s3_helpers::reload_object_store_setting;
|
||||
|
||||
const DEFAULT_NUM_WORKERS: usize = 1;
|
||||
const DEFAULT_PORT: u16 = 8000;
|
||||
const DEFAULT_SERVER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
|
||||
|
||||
mod ee;
|
||||
#[cfg(feature = "private")]
|
||||
pub mod ee;
|
||||
mod ee_oss;
|
||||
mod monitor;
|
||||
|
||||
pub fn setup_deno_runtime() -> anyhow::Result<()> {
|
||||
@@ -152,6 +159,7 @@ lazy_static::lazy_static! {
|
||||
.ok()
|
||||
.and_then(|x| x.parse::<u64>().ok())
|
||||
.unwrap_or(3600 * 12);
|
||||
|
||||
}
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
@@ -260,7 +268,7 @@ async fn windmill_main() -> anyhow::Result<()> {
|
||||
tracing::error!("Failed to install rustls crypto provider");
|
||||
}
|
||||
|
||||
let hostname = hostname();
|
||||
let hostname = HOSTNAME.to_owned();
|
||||
|
||||
let mode_and_addons = MODE_AND_ADDONS.clone();
|
||||
let mode = mode_and_addons.mode;
|
||||
@@ -339,7 +347,7 @@ async fn windmill_main() -> anyhow::Result<()> {
|
||||
"Creating http client for cluster using base internal url {}",
|
||||
std::env::var("BASE_INTERNAL_URL").unwrap_or_default()
|
||||
);
|
||||
let suffix = windmill_common::utils::worker_suffix(&hostname, &rd_string(5));
|
||||
let suffix = create_ssh_agent_worker_suffix(&hostname);
|
||||
(
|
||||
Connection::Http(build_agent_http_client(&suffix)),
|
||||
Some(suffix),
|
||||
@@ -551,7 +559,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
_ = indexer_rx.recv() => {
|
||||
tracing::info!("Received killpill, aborting index initialization");
|
||||
},
|
||||
res = windmill_indexer::completed_runs_ee::init_index(&db) => {
|
||||
res = windmill_indexer::completed_runs_oss::init_index(&db) => {
|
||||
let res = res?;
|
||||
reader = Some(res.0);
|
||||
writer = Some(res.1);
|
||||
@@ -573,7 +581,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
async {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Some(index_writer) = index_writer2 {
|
||||
windmill_indexer::completed_runs_ee::run_indexer(
|
||||
windmill_indexer::completed_runs_oss::run_indexer(
|
||||
db.clone(),
|
||||
index_writer,
|
||||
indexer_rx,
|
||||
@@ -595,7 +603,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
_ = indexer_rx.recv() => {
|
||||
tracing::info!("Received killpill, aborting index initialization");
|
||||
},
|
||||
res = windmill_indexer::service_logs_ee::init_index(&db, killpill_tx.clone()) => {
|
||||
res = windmill_indexer::service_logs_oss::init_index(&db, killpill_tx.clone()) => {
|
||||
let res = res?;
|
||||
reader = Some(res.0);
|
||||
writer = Some(res.1);
|
||||
@@ -617,7 +625,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
async {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Some(log_index_writer) = log_index_writer2 {
|
||||
windmill_indexer::service_logs_ee::run_indexer(
|
||||
windmill_indexer::service_logs_oss::run_indexer(
|
||||
db.clone(),
|
||||
log_index_writer,
|
||||
log_indexer_rx,
|
||||
@@ -674,19 +682,21 @@ Windmill Community Edition {GIT_VERSION}
|
||||
let base_internal_url = base_internal_rx.await?;
|
||||
if worker_mode {
|
||||
let mut workers = vec![];
|
||||
|
||||
for i in 0..num_workers {
|
||||
let suffix: String = if i == 0 && first_suffix.as_ref().is_some() {
|
||||
let suffix = if i == 0 && first_suffix.is_some() {
|
||||
first_suffix.as_ref().unwrap().clone()
|
||||
} else {
|
||||
windmill_common::utils::worker_suffix(&hostname, &rd_string(5))
|
||||
create_default_worker_suffix(&hostname)
|
||||
};
|
||||
|
||||
let worker_conn = WorkerConn {
|
||||
conn: if i == 0 || mode != Mode::Agent {
|
||||
conn.clone()
|
||||
} else {
|
||||
Connection::Http(build_agent_http_client(&suffix))
|
||||
},
|
||||
worker_name: windmill_common::utils::worker_name_with_suffix(
|
||||
worker_name: worker_name_with_suffix(
|
||||
mode == Mode::Agent,
|
||||
WORKER_GROUP.as_str(),
|
||||
&suffix,
|
||||
@@ -791,11 +801,37 @@ Windmill Community Edition {GIT_VERSION}
|
||||
let payload = n.payload();
|
||||
tracing::info!("Runnable version change detected: {}", payload);
|
||||
match payload.split(':').collect::<Vec<&str>>().as_slice() {
|
||||
[workspace_id, source_type, path] => {
|
||||
[workspace_id, source_type, path, kind] => {
|
||||
let key = (workspace_id.to_string(), path.to_string());
|
||||
match source_type {
|
||||
&"script" => {
|
||||
windmill_common::DEPLOYED_SCRIPT_HASH_CACHE.remove(&key);
|
||||
match kind {
|
||||
&"preprocessor" => {
|
||||
match sqlx::query_scalar!(
|
||||
"SELECT fv.id
|
||||
FROM flow f
|
||||
INNER JOIN flow_version fv ON fv.id = f.versions[array_upper(f.versions, 1)]
|
||||
WHERE fv.value->'preprocessor_module'->'value'->>'path' = $1 AND f.workspace_id = $2",
|
||||
path,
|
||||
workspace_id
|
||||
).fetch_all(&db).await {
|
||||
Ok(flow_versions) => {
|
||||
tracing::debug!("Workspace preprocessor {} changed, removing runnable format version cache for flow versions {:?}", path, flow_versions);
|
||||
for version in flow_versions {
|
||||
for trigger_kind in TriggerKind::iter() {
|
||||
let key = (windmill_common::triggers::HubOrWorkspaceId::WorkspaceId(workspace_id.to_string()), version, trigger_kind);
|
||||
windmill_common::triggers::RUNNABLE_FORMAT_VERSION_CACHE.remove(&key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error fetching flow paths: {e:#}");
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
&"flow" => {
|
||||
windmill_common::FLOW_VERSION_CACHE.remove(&key);
|
||||
@@ -825,6 +861,11 @@ Windmill Community Edition {GIT_VERSION}
|
||||
}
|
||||
};
|
||||
},
|
||||
"notify_token_invalidation" => {
|
||||
let token = n.payload();
|
||||
tracing::info!("Token invalidation detected for token: {}...", &token[..token.len().min(8)]);
|
||||
windmill_api::auth::invalidate_token_from_cache(token);
|
||||
},
|
||||
"notify_global_setting_change" => {
|
||||
tracing::info!("Global setting change detected: {}", n.payload());
|
||||
match n.payload() {
|
||||
@@ -857,7 +898,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
if let Err(e) = load_tag_per_workspace_workspaces(&db).await {
|
||||
tracing::error!("Error loading default tag per workspace workspaces: {e:#}");
|
||||
}
|
||||
}
|
||||
},
|
||||
SMTP_SETTING => {
|
||||
reload_smtp_config(&db).await;
|
||||
},
|
||||
@@ -880,9 +921,9 @@ Windmill Community Edition {GIT_VERSION}
|
||||
reload_job_default_timeout_setting(&conn).await
|
||||
},
|
||||
#[cfg(feature = "parquet")]
|
||||
OBJECT_STORE_CACHE_CONFIG_SETTING => {
|
||||
OBJECT_STORE_CONFIG_SETTING => {
|
||||
if !disable_s3_store {
|
||||
reload_s3_cache_setting(&db).await
|
||||
reload_object_store_setting(&db).await;
|
||||
}
|
||||
},
|
||||
SCIM_TOKEN_SETTING => {
|
||||
@@ -974,7 +1015,6 @@ Windmill Community Edition {GIT_VERSION}
|
||||
tracing::error!(error = %e, "Could not reload critical alert UI setting");
|
||||
}
|
||||
},
|
||||
|
||||
a @_ => {
|
||||
tracing::info!("Unrecognized Global Setting Change Payload: {:?}", a);
|
||||
}
|
||||
@@ -1026,7 +1066,9 @@ Windmill Community Edition {GIT_VERSION}
|
||||
}
|
||||
|
||||
if server_mode {
|
||||
tracing::info!("monitor task started");
|
||||
if !*windmill_common::QUIET_LOGS {
|
||||
tracing::info!("monitor task started");
|
||||
}
|
||||
}
|
||||
monitor_db(
|
||||
&conn,
|
||||
@@ -1038,7 +1080,9 @@ Windmill Community Edition {GIT_VERSION}
|
||||
)
|
||||
.await;
|
||||
if server_mode {
|
||||
tracing::info!("monitor task finished");
|
||||
if !*windmill_common::QUIET_LOGS {
|
||||
tracing::info!("monitor task finished");
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1059,7 +1103,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
tracing::info!("Reloading config after 12 hours");
|
||||
initial_load(&conn, tx.clone(), worker_mode, server_mode, #[cfg(feature = "parquet")] disable_s3_store).await;
|
||||
#[cfg(feature = "enterprise")]
|
||||
ee::verify_license_key().await;
|
||||
ee_oss::verify_license_key().await;
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1147,6 +1191,7 @@ async fn listen_pg(url: &str) -> Option<PgListener> {
|
||||
"notify_webhook_change",
|
||||
"notify_workspace_envs_change",
|
||||
"notify_runnable_version_change",
|
||||
"notify_token_invalidation",
|
||||
];
|
||||
|
||||
#[cfg(feature = "http_trigger")]
|
||||
@@ -1240,10 +1285,6 @@ pub async fn run_workers(
|
||||
PY311_CACHE_DIR,
|
||||
PY312_CACHE_DIR,
|
||||
PY313_CACHE_DIR,
|
||||
TAR_PY310_CACHE_DIR,
|
||||
TAR_PY311_CACHE_DIR,
|
||||
TAR_PY312_CACHE_DIR,
|
||||
TAR_PY313_CACHE_DIR,
|
||||
BUN_BUNDLE_CACHE_DIR,
|
||||
GO_CACHE_DIR,
|
||||
GO_BIN_CACHE_DIR,
|
||||
|
||||
@@ -29,16 +29,19 @@ use windmill_api::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use windmill_common::ee::low_disk_alerts;
|
||||
use windmill_common::ee_oss::low_disk_alerts;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use windmill_common::ee::{jobs_waiting_alerts, worker_groups_alerts};
|
||||
use windmill_common::ee_oss::{jobs_waiting_alerts, worker_groups_alerts};
|
||||
|
||||
use windmill_common::client::AuthedClient;
|
||||
#[cfg(feature = "oauth2")]
|
||||
use windmill_common::global_settings::OAUTH_SETTING;
|
||||
#[cfg(feature = "parquet")]
|
||||
use windmill_common::s3_helpers::reload_object_store_setting;
|
||||
use windmill_common::{
|
||||
agent_workers::DECODED_AGENT_TOKEN,
|
||||
auth::create_token_for_owner,
|
||||
ee::CriticalErrorChannel,
|
||||
ee_oss::CriticalErrorChannel,
|
||||
error,
|
||||
flow_status::{FlowStatus, FlowStatusModule},
|
||||
global_settings::{
|
||||
@@ -75,24 +78,18 @@ use windmill_common::{
|
||||
};
|
||||
use windmill_queue::{cancel_job, MiniPulledJob, SameWorkerPayload};
|
||||
use windmill_worker::{
|
||||
handle_job_error, AuthedClient, JobCompletedSender, SameWorkerSender, BUNFIG_INSTALL_SCOPES,
|
||||
handle_job_error, JobCompletedSender, SameWorkerSender, BUNFIG_INSTALL_SCOPES,
|
||||
INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT, KEEP_JOB_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN,
|
||||
NPM_CONFIG_REGISTRY, NUGET_CONFIG, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
use windmill_common::s3_helpers::{
|
||||
build_object_store_from_settings, build_s3_client_from_settings, S3Settings,
|
||||
OBJECT_STORE_CACHE_SETTINGS,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
use windmill_common::global_settings::OBJECT_STORE_CACHE_CONFIG_SETTING;
|
||||
use windmill_common::s3_helpers::ObjectStoreReload;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::ee::verify_license_key;
|
||||
use crate::ee_oss::verify_license_key;
|
||||
|
||||
use crate::ee::set_license_key;
|
||||
use crate::ee_oss::set_license_key;
|
||||
|
||||
#[cfg(feature = "prometheus")]
|
||||
lazy_static::lazy_static! {
|
||||
@@ -241,7 +238,23 @@ pub async fn initial_load(
|
||||
#[cfg(feature = "parquet")]
|
||||
if !disable_s3_store {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
reload_s3_cache_setting(db).await;
|
||||
let db2 = db.clone();
|
||||
match reload_object_store_setting(db).await {
|
||||
ObjectStoreReload::Later => {
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||
match reload_object_store_setting(&db2).await {
|
||||
ObjectStoreReload::Later => {
|
||||
tracing::error!("Giving up on loading object store setting");
|
||||
}
|
||||
ObjectStoreReload::Never => {
|
||||
tracing::info!("Object store setting successfully loaded");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
ObjectStoreReload::Never => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,7 +644,7 @@ async fn send_log_file_to_object_store(
|
||||
}
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
let s3_client = OBJECT_STORE_CACHE_SETTINGS.read().await.clone();
|
||||
let s3_client = windmill_common::s3_helpers::get_object_store().await;
|
||||
#[cfg(feature = "parquet")]
|
||||
if let Some(s3_client) = s3_client {
|
||||
let path = std::path::Path::new(TMP_WINDMILL_LOGS_SERVICE)
|
||||
@@ -917,10 +930,7 @@ async fn delete_log_files_from_disk_and_store(
|
||||
_s3_prefix: &str,
|
||||
) {
|
||||
#[cfg(feature = "parquet")]
|
||||
let os = windmill_common::s3_helpers::OBJECT_STORE_CACHE_SETTINGS
|
||||
.read()
|
||||
.await
|
||||
.clone();
|
||||
let os = windmill_common::s3_helpers::get_object_store().await;
|
||||
#[cfg(not(feature = "parquet"))]
|
||||
let os: Option<()> = None;
|
||||
|
||||
@@ -1101,61 +1111,6 @@ pub async fn reload_delete_logs_periodically_setting(conn: &Connection) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
pub async fn reload_s3_cache_setting(db: &DB) {
|
||||
use windmill_common::{
|
||||
ee::{get_license_plan, LicensePlan},
|
||||
s3_helpers::ObjectSettings,
|
||||
};
|
||||
|
||||
let s3_config = load_value_from_global_settings(db, OBJECT_STORE_CACHE_CONFIG_SETTING).await;
|
||||
if let Err(e) = s3_config {
|
||||
tracing::error!("Error reloading s3 cache config: {:?}", e)
|
||||
} else {
|
||||
if let Some(v) = s3_config.unwrap() {
|
||||
if matches!(get_license_plan().await, LicensePlan::Pro) {
|
||||
tracing::error!("S3 cache is not available for pro plan");
|
||||
return;
|
||||
}
|
||||
let mut s3_cache_settings = OBJECT_STORE_CACHE_SETTINGS.write().await;
|
||||
let setting = serde_json::from_value::<ObjectSettings>(v);
|
||||
if let Err(e) = setting {
|
||||
tracing::error!("Error parsing s3 cache config: {:?}", e)
|
||||
} else {
|
||||
let s3_client = build_object_store_from_settings(setting.unwrap()).await;
|
||||
if let Err(e) = s3_client {
|
||||
tracing::error!("Error building s3 client from settings: {:?}", e)
|
||||
} else {
|
||||
*s3_cache_settings = Some(s3_client.unwrap());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut s3_cache_settings = OBJECT_STORE_CACHE_SETTINGS.write().await;
|
||||
if std::env::var("S3_CACHE_BUCKET").is_ok() {
|
||||
if matches!(get_license_plan().await, LicensePlan::Pro) {
|
||||
tracing::error!("S3 cache is not available for pro plan");
|
||||
return;
|
||||
}
|
||||
*s3_cache_settings = build_s3_client_from_settings(S3Settings {
|
||||
bucket: None,
|
||||
region: None,
|
||||
access_key: None,
|
||||
secret_key: None,
|
||||
endpoint: None,
|
||||
store_logs: None,
|
||||
path_style: None,
|
||||
allow_http: None,
|
||||
port: None,
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
} else {
|
||||
*s3_cache_settings = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reload_job_default_timeout_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
conn,
|
||||
@@ -1369,7 +1324,6 @@ pub async fn monitor_db(
|
||||
initial_load: bool,
|
||||
_killpill_tx: KillpillSender,
|
||||
) {
|
||||
tracing::info!("Starting periodic monitor task");
|
||||
let zombie_jobs_f = async {
|
||||
if server_mode && !initial_load && !*DISABLE_ZOMBIE_JOBS_MONITORING {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
@@ -1467,7 +1421,6 @@ pub async fn monitor_db(
|
||||
apply_autoscaling_f,
|
||||
update_min_worker_version_f,
|
||||
);
|
||||
tracing::info!("Periodic monitor task completed");
|
||||
}
|
||||
|
||||
pub async fn expose_queue_metrics(db: &Pool<Postgres>) {
|
||||
@@ -1654,7 +1607,7 @@ pub async fn reload_base_url_setting(conn: &Connection) -> error::Result<()> {
|
||||
|
||||
if let Some(q) = q_oauth {
|
||||
if let Ok(v) = serde_json::from_value::<
|
||||
Option<HashMap<String, windmill_api::oauth2_ee::OAuthClient>>,
|
||||
Option<HashMap<String, windmill_api::oauth2_oss::OAuthClient>>,
|
||||
>(q.clone())
|
||||
{
|
||||
v
|
||||
@@ -1675,7 +1628,7 @@ pub async fn reload_base_url_setting(conn: &Connection) -> error::Result<()> {
|
||||
{
|
||||
if let Some(db) = conn.as_sql() {
|
||||
let mut l = windmill_api::OAUTH_CLIENTS.write().await;
|
||||
*l = windmill_api::oauth2_ee::build_oauth_clients(&base_url, oauths, db).await
|
||||
*l = windmill_api::oauth2_oss::build_oauth_clients(&base_url, oauths, db).await
|
||||
.map_err(|e| tracing::error!("Error building oauth clients (is the oauth.json mounted and in correct format? Use '{}' as minimal oauth.json): {}", "{}", e))
|
||||
.unwrap();
|
||||
}
|
||||
@@ -1959,12 +1912,12 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
|
||||
.await
|
||||
.expect("could not create job token");
|
||||
|
||||
let client = AuthedClient {
|
||||
base_internal_url: base_internal_url.to_string(),
|
||||
let client = AuthedClient::new(
|
||||
base_internal_url.to_string(),
|
||||
job.workspace_id.to_string(),
|
||||
token,
|
||||
workspace: job.workspace_id.to_string(),
|
||||
force_client: None,
|
||||
};
|
||||
None,
|
||||
);
|
||||
|
||||
let last_ping = job.last_ping.clone();
|
||||
let error_message = format!(
|
||||
@@ -1983,7 +1936,7 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
|
||||
None,
|
||||
error::Error::ExecutionErr(error_message),
|
||||
true,
|
||||
same_worker_tx_never_used,
|
||||
Some(&same_worker_tx_never_used),
|
||||
"",
|
||||
worker_name,
|
||||
send_result_never_used,
|
||||
|
||||
@@ -4,8 +4,8 @@ script_dirpath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
root_dirpath="$(cd "${script_dirpath}/.." && pwd)"
|
||||
|
||||
REVERT="NO"
|
||||
REVERT_PREVIOUS="NO"
|
||||
COPY="NO"
|
||||
MOVE_NEW_FILES="NO"
|
||||
EE_CODE_DIR="../windmill-ee-private/"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
@@ -16,13 +16,7 @@ while [[ $# -gt 0 ]]; do
|
||||
# this to work (commit hooks should prevent this from happening, as well as the fact
|
||||
# that we're using symlinks by default).
|
||||
REVERT="YES"
|
||||
shift
|
||||
;;
|
||||
--revert-previous)
|
||||
# This is a special case of --revert that will revert to the previous commit.
|
||||
REVERT="YES"
|
||||
REVERT_PREVIOUS="YES"
|
||||
echo "Reverting to previous commit"
|
||||
MOVE_NEW_FILES="YES"
|
||||
shift
|
||||
;;
|
||||
-c|--copy)
|
||||
@@ -33,6 +27,11 @@ while [[ $# -gt 0 ]]; do
|
||||
COPY="YES"
|
||||
shift # past argument
|
||||
;;
|
||||
-m|--move-new-files)
|
||||
# This moves all new EE files from the public repository to the private repository.
|
||||
MOVE_NEW_FILES="YES"
|
||||
shift # past argument
|
||||
;;
|
||||
-d|--dir)
|
||||
# Path to the local directory of the windmill-ee-private repository. By defaults, it
|
||||
# assumes it is cloned next to the Windmill OSS repo.
|
||||
@@ -70,29 +69,34 @@ if [ "$REVERT" == "YES" ]; then
|
||||
for ee_file in $(find ${EE_CODE_DIR} -name "*ee.rs"); do
|
||||
ce_file="${ee_file/${EE_CODE_DIR}/}"
|
||||
ce_file="${root_dirpath}/backend/${ce_file}"
|
||||
if [ "$REVERT_PREVIOUS" == "YES" ]; then
|
||||
git checkout HEAD@{3} ${ce_file} || true
|
||||
else
|
||||
git restore --staged ${ce_file} || true
|
||||
git restore ${ce_file} || true
|
||||
fi
|
||||
rm ${ce_file} || true
|
||||
done
|
||||
else
|
||||
elif [ "$MOVE_NEW_FILES" == "NO" ]; then
|
||||
# This replaces all files in current repo with alternative EE files in windmill-ee-private
|
||||
for ee_file in $(find "${EE_CODE_DIR}" -name "*ee.rs"); do
|
||||
ce_file="${ee_file/${EE_CODE_DIR}/}"
|
||||
ce_file="${root_dirpath}/backend/${ce_file}"
|
||||
if [[ -f "${ce_file}" ]]; then
|
||||
rm "${ce_file}"
|
||||
if [ "$COPY" == "YES" ]; then
|
||||
cp "${ee_file}" "${ce_file}"
|
||||
echo "File copied '${ee_file}' -->> '${ce_file}'"
|
||||
else
|
||||
ln -s "${ee_file}" "${ce_file}"
|
||||
echo "Symlink created '${ee_file}' -->> '${ce_file}'"
|
||||
fi
|
||||
ce_file="${ee_file/${EE_CODE_DIR}/}"
|
||||
ce_file="${root_dirpath}/backend/${ce_file}"
|
||||
if [ "$COPY" == "YES" ]; then
|
||||
cp "${ee_file}" "${ce_file}"
|
||||
echo "File copied '${ee_file}' -->> '${ce_file}'"
|
||||
else
|
||||
echo "File ${ce_file} is not a file, ignoring"
|
||||
ln -s "${ee_file}" "${ce_file}" || true
|
||||
echo "Symlink created '${ee_file}' -->> '${ce_file}'"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$MOVE_NEW_FILES" == "YES" ]; then
|
||||
for ce_file in $(find "${root_dirpath}"/backend/windmill-*/src/ -name "*ee.rs"); do
|
||||
backend_dirpath="${root_dirpath}/backend/"
|
||||
ee_file="${ce_file/${backend_dirpath}/}"
|
||||
ee_file="${EE_CODE_DIR}${ee_file}"
|
||||
if [ ! -f "${ee_file}" ]; then
|
||||
mv "${ce_file}" "${ee_file}"
|
||||
if [ ! "$REVERT" == "YES" ]; then
|
||||
ln -s "${ee_file}" "${ce_file}"
|
||||
fi
|
||||
echo "File moved '${ce_file}' -->> '${ee_file}'"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
20
backend/tests/fixtures/multipython.sql
vendored
Normal file
20
backend/tests/fixtures/multipython.sql
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES (
|
||||
'test-workspace',
|
||||
'test-user',
|
||||
'# py312
|
||||
',
|
||||
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
|
||||
'',
|
||||
'',
|
||||
'f/multipython/aliases', 2468135790, 'python3', '');
|
||||
|
||||
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES (
|
||||
'test-workspace',
|
||||
'test-user',
|
||||
'# py: >=3.9,!=3.12.2
|
||||
',
|
||||
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
|
||||
'',
|
||||
'',
|
||||
'f/multipython/script1', 2345678901, 'python3', '');
|
||||
|
||||
@@ -3969,8 +3969,7 @@ async fn assert_lockfile(
|
||||
#[cfg(feature = "python")]
|
||||
#[sqlx::test(fixtures("base", "lockfile_python"))]
|
||||
async fn test_requirements_python(db: Pool<Postgres>) {
|
||||
let content = r#"
|
||||
# py311
|
||||
let content = r#"# py: ==3.11.11
|
||||
# requirements:
|
||||
# tiny==0.1.3
|
||||
|
||||
@@ -3988,7 +3987,7 @@ def main():
|
||||
&db,
|
||||
content,
|
||||
ScriptLang::Python3,
|
||||
vec!["# py311", "tiny==0.1.3"],
|
||||
vec!["# py: 3.11.11", "tiny==0.1.3"],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -3997,8 +3996,7 @@ def main():
|
||||
#[sqlx::test(fixtures("base", "lockfile_python"))]
|
||||
async fn test_extra_requirements_python(db: Pool<Postgres>) {
|
||||
{
|
||||
let content = r#"
|
||||
# py311
|
||||
let content = r#"# py: ==3.11.11
|
||||
# extra_requirements:
|
||||
# tiny
|
||||
|
||||
@@ -4016,7 +4014,7 @@ def main():
|
||||
&db,
|
||||
content,
|
||||
ScriptLang::Python3,
|
||||
vec!["# py311", "bottle==0.13.2", "tiny==0.1.2"],
|
||||
vec!["# py: 3.11.11", "bottle==0.13.2", "tiny==0.1.2"],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -4025,8 +4023,7 @@ def main():
|
||||
#[cfg(feature = "python")]
|
||||
#[sqlx::test(fixtures("base", "lockfile_python"))]
|
||||
async fn test_extra_requirements_python2(db: Pool<Postgres>) {
|
||||
let content = r#"
|
||||
# py311
|
||||
let content = r#"# py: ==3.11.11
|
||||
# extra_requirements:
|
||||
# tiny==0.1.3
|
||||
|
||||
@@ -4040,7 +4037,7 @@ def main():
|
||||
&db,
|
||||
content,
|
||||
ScriptLang::Python3,
|
||||
vec!["# py311", "simplejson==3.20.1", "tiny==0.1.3"],
|
||||
vec!["# py: 3.11.11", "simplejson==3.20.1", "tiny==0.1.3"],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -4048,8 +4045,7 @@ def main():
|
||||
#[cfg(feature = "python")]
|
||||
#[sqlx::test(fixtures("base", "lockfile_python"))]
|
||||
async fn test_pins_python(db: Pool<Postgres>) {
|
||||
let content = r#"
|
||||
# py311
|
||||
let content = r#"# py: ==3.11.11
|
||||
# extra_requirements:
|
||||
# tiny==0.1.3
|
||||
# bottle==0.13.2
|
||||
@@ -4069,7 +4065,7 @@ def main():
|
||||
content,
|
||||
ScriptLang::Python3,
|
||||
vec![
|
||||
"# py311",
|
||||
"# py: 3.11.11",
|
||||
"bottle==0.13.2",
|
||||
"microdot==2.2.0",
|
||||
"simplejson==3.19.3",
|
||||
@@ -4078,6 +4074,39 @@ def main():
|
||||
)
|
||||
.await;
|
||||
}
|
||||
#[cfg(feature = "python")]
|
||||
#[sqlx::test(fixtures("base", "multipython"))]
|
||||
async fn test_multipython_python(db: Pool<Postgres>) {
|
||||
let content = r#"# py: <=3.12.2, >=3.12.0
|
||||
import f.multipython.script1
|
||||
import f.multipython.aliases
|
||||
"#
|
||||
.to_string();
|
||||
|
||||
assert_lockfile(&db, content, ScriptLang::Python3, vec!["# py: 3.12.1\n"]).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
#[sqlx::test(fixtures("base", "multipython"))]
|
||||
async fn test_inline_script_metadata_python(db: Pool<Postgres>) {
|
||||
let content = r#"# py_select_latest
|
||||
# /// script
|
||||
# requires-python = ">3.11,<3.12.3,!=3.12.2"
|
||||
# dependencies = [
|
||||
# "tiny==0.1.3",
|
||||
# ]
|
||||
# ///
|
||||
"#
|
||||
.to_string();
|
||||
|
||||
assert_lockfile(
|
||||
&db,
|
||||
content,
|
||||
ScriptLang::Python3,
|
||||
vec!["# py: 3.12.1", "tiny==0.1.3"],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
#[sqlx::test(fixtures("base", "result_format"))]
|
||||
async fn test_result_format(db: Pool<Postgres>) {
|
||||
let ordered_result_job_id = "1eecb96a-c8b0-4a3d-b1b6-087878c55e41";
|
||||
|
||||
@@ -10,7 +10,6 @@ if [[ "$(uname)" == "Darwin" ]]; then
|
||||
fi
|
||||
|
||||
cargo sqlx prepare --workspace -- --all-targets --all-features
|
||||
./substitute_ee_code.sh -r --dir ../windmill-ee-private
|
||||
|
||||
# Undo the samael changes on macOS
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
|
||||
@@ -10,6 +10,7 @@ path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
private = ["windmill-audit/private"]
|
||||
enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker/enterprise"]
|
||||
stripe = []
|
||||
agent_worker_server = []
|
||||
@@ -18,7 +19,7 @@ benchmark = []
|
||||
embedding = ["dep:tinyvector", "dep:hf-hub", "dep:tokenizers", "dep:candle-core", "dep:candle-transformers", "dep:candle-nn"]
|
||||
parquet = ["dep:datafusion", "dep:object_store", "dep:url", "windmill-common/parquet", "windmill-worker/parquet"]
|
||||
prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus", "windmill-worker/prometheus"]
|
||||
openidconnect = ["dep:openidconnect"]
|
||||
openidconnect = ["dep:openidconnect", "windmill-common/openidconnect"]
|
||||
tantivy = ["dep:windmill-indexer"]
|
||||
kafka = ["dep:rdkafka"]
|
||||
nats = ["dep:async-nats", "dep:nkeys"]
|
||||
@@ -36,9 +37,10 @@ deno_core = ["dep:deno_core", "dep:deno_error"]
|
||||
gcp_trigger = ["dep:thiserror", "dep:google-cloud-pubsub", "dep:google-cloud-googleapis", "dep:tonic"]
|
||||
cloud = ["windmill-common/cloud"]
|
||||
mcp = ["dep:rmcp"]
|
||||
python = []
|
||||
|
||||
[dependencies]
|
||||
rmcp = { git = "https://github.com/windmill-labs/rust-sdk", features = ["transport-sse-server"], optional = true }
|
||||
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", features=["transport-streamable-http-server", "transport-streamable-http-server-session", "transport-worker"], optional = true }
|
||||
windmill-queue.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-audit.workspace = true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user