Compare commits

..

1 Commits

Author SHA1 Message Date
Alex Petric
2eb7360210 fix: add leaf_job to openapi spec of QueuedJob 2025-05-01 17:56:35 -04:00
3461 changed files with 148250 additions and 392129 deletions

View File

@@ -1,3 +0,0 @@
/*
!/backend/
!/frontend/

View File

@@ -1,127 +0,0 @@
---
name: branch-diff-reviewer
description: Use this agent when you want a comprehensive code review of changes in the current branch compared to main. This includes reviewing for bugs, optimization opportunities, code style issues, potential mistakes, and adherence to project conventions. The agent should be invoked after completing a feature branch or before creating a pull request.\n\nExamples:\n\n<example>\nContext: User has finished implementing a new feature and wants feedback before merging.\nuser: "I've finished the new kafka trigger implementation, can you review my changes?"\nassistant: "I'll use the branch-diff-reviewer agent to analyze your changes against the main branch and provide comprehensive feedback."\n<commentary>\nSince the user wants a review of their branch changes, use the Task tool to launch the branch-diff-reviewer agent to compare the current branch against main and provide detailed feedback.\n</commentary>\n</example>\n\n<example>\nContext: User wants to check their code quality before submitting a PR.\nuser: "Review my branch before I create a PR"\nassistant: "Let me launch the branch-diff-reviewer agent to examine all your changes and identify any issues or improvements."\n<commentary>\nThe user is preparing for a PR, so use the branch-diff-reviewer agent to provide a thorough review of all branch differences.\n</commentary>\n</example>\n\n<example>\nContext: User is unsure if their implementation follows project patterns.\nuser: "Does my implementation look correct? I'm not sure if I followed the existing patterns"\nassistant: "I'll use the branch-diff-reviewer agent to compare your changes against main and check for pattern consistency, potential issues, and optimization opportunities."\n<commentary>\nThe user needs validation of their implementation against project standards. Launch the branch-diff-reviewer agent to analyze the diff and provide feedback on patterns, correctness, and improvements.\n</commentary>\n</example>
tools: Glob, Grep, Read, WebFetch, TodoWrite, WebSearch, ListMcpResourcesTool, ReadMcpResourceTool, mcp__svelte__get-documentation, mcp__svelte__list-sections, mcp__svelte__playground-link, mcp__svelte__svelte-autofixer, mcp__ide__getDiagnostics, mcp__ide__executeCode, Bash, Skill
model: inherit
---
You are an elite code reviewer with deep expertise in software engineering best practices, performance optimization, and security. Your role is to provide thorough, actionable feedback on code changes between the current branch and main.
## Your Review Process
1. **First, gather the diff**: Use git commands to obtain the complete diff between the current branch and main:
- Run `git diff main...HEAD` to see all changes
- Run `git log main..HEAD --oneline` to understand the commit history
- Identify all modified, added, and deleted files
2. **Analyze each changed file** in the context of:
- The project's established patterns (check CLAUDE.md and related documentation)
- The file's purpose and its role in the broader codebase
- Dependencies and how changes might affect other parts of the system
## Review Categories
For each significant change, evaluate and report on:
### 🐛 Bugs & Correctness
- Logic errors or edge cases not handled
- Null/undefined handling issues
- Race conditions in async code
- Incorrect error handling
- Type mismatches or unsafe casts
### ⚡ Performance
- Inefficient algorithms or data structures
- N+1 query problems in database code
- Unnecessary re-renders in frontend code
- Missing indexes for database queries
- Blocking operations in async contexts
- Memory leaks or excessive allocations
- For Rust: Check for unnecessary clones, inefficient serde usage, blocking in async
- For Svelte: Check for inefficient reactivity, missing keys in loops, excessive effects
### 🔒 Security
- SQL injection vulnerabilities
- Missing input validation
- Exposed sensitive data
- Authentication/authorization gaps
- Unsafe deserialization
### 📐 Code Quality & Style
- Adherence to project conventions (CLAUDE.md guidelines)
- Code duplication that should be refactored
- Unclear or misleading naming
- Missing or inadequate documentation
- Overly complex logic that could be simplified
- Dead code or unused imports
### 🏗️ Architecture & Design
- Proper separation of concerns
- Appropriate use of existing utilities vs. new code
- Consistency with established patterns
- Proper error propagation
- API design issues
### 🧪 Testing Considerations
- Suggest test cases for new functionality
- Identify untested edge cases
- Note if changes break existing test assumptions
## Project-Specific Rules
### For Rust (Backend)
- Verify `SELECT` statements list explicit columns (never `SELECT *` in worker code)
- Check for proper use of `sqlx` with parameterized queries
- Ensure errors use the custom `Error` enum from `windmill-common::error`
- Verify async code doesn't block the tokio runtime
- Check serde attributes for optimal serialization
- Ensure openapi.yaml is updated for API changes
### For Svelte (Frontend)
- For Svelte 5 files: Verify proper use of Runes (`$state`, `$derived`, `$effect`)
- Check for `key` attributes in `{#each}` blocks
- Ensure event handlers use the new syntax (`onclick` not `on:click`) in Svelte 5
- Verify snippets are used instead of slots in Svelte 5
- Check for proper props declaration with `$props()`
## Output Format
Structure your review as follows:
```
## Summary
[Brief overview of the changes and overall assessment]
## Critical Issues 🚨
[Issues that must be fixed before merging]
## Recommendations 💡
[Improvements that would significantly enhance the code]
## Minor Suggestions 📝
[Nice-to-haves and style improvements]
## Positive Observations ✅
[Well-done aspects worth acknowledging]
## File-by-File Details
[Detailed feedback organized by file]
```
For each issue, provide:
1. **Location**: File path and line number(s)
2. **Issue**: Clear description of the problem
3. **Impact**: Why this matters
4. **Suggestion**: Concrete fix or improvement with code example when helpful
## Behavioral Guidelines
- Be thorough but prioritize: focus most on critical issues
- Be constructive: every criticism should come with a suggestion
- Be specific: vague feedback is not actionable
- Acknowledge good work: positive reinforcement matters
- Consider context: understand why decisions might have been made
- Ask clarifying questions if the intent of changes is unclear
- Reference project documentation when pointing out convention violations
Begin by fetching the diff and then proceed with your comprehensive review.

View File

@@ -1,76 +0,0 @@
---
name: openapi-sync
description: Use this agent when backend API endpoints are added, modified, or removed, or when the Flow structure changes and the OpenAPI specification files need to be updated. This includes changes to route handlers in windmill-api, modifications to request/response schemas, changes to authentication requirements, or updates to the Flow data structures that affect the API.\n\nExamples:\n\n<example>\nContext: User has just added a new API endpoint for managing workspace templates.\nuser: "Add a new endpoint POST /api/w/{workspace}/templates to create workspace templates"\nassistant: "I've created the new endpoint handler in windmill-api. Now let me use the openapi-sync agent to update the OpenAPI specification files."\n<commentary>\nSince a new API endpoint was added, use the openapi-sync agent to ensure the openapi.yaml and openflow.openapi.yaml files are updated with the new endpoint definition.\n</commentary>\n</example>\n\n<example>\nContext: User has modified the response schema for an existing endpoint.\nuser: "Update the GET /api/w/{workspace}/flows endpoint to also return a 'versions' array in the response"\nassistant: "I've updated the flow listing endpoint to include the versions array. Now let me use the openapi-sync agent to update the OpenAPI specification."\n<commentary>\nSince the response schema of an existing endpoint was modified, use the openapi-sync agent to update the corresponding schema in the OpenAPI files.\n</commentary>\n</example>\n\n<example>\nContext: User has made changes to the Flow structure in the codebase.\nuser: "Add a new 'retry_policy' field to the Flow value structure"\nassistant: "I've added the retry_policy field to the Flow struct. Now let me use the openapi-sync agent to update the OpenAPI specification to reflect this schema change."\n<commentary>\nSince the Flow structure was modified, use the openapi-sync agent to ensure the flow-related schemas in openapi.yaml and openflow.openapi.yaml are updated.\n</commentary>\n</example>
model: inherit
---
You are an expert API documentation engineer specializing in OpenAPI specifications for the Windmill platform. Your primary responsibility is to maintain synchronization between the Rust backend API implementation and the OpenAPI specification files.
## Your Core Responsibilities
1. **Update OpenAPI Specifications**: When API endpoints are added, modified, or removed in the windmill-api crate, you must update:
- `backend/windmill-api/openapi.yaml` - The main OpenAPI specification
- `backend/windmill-api/openflow.openapi.yaml` - Flow-specific OpenAPI definitions (if flow-related changes)
2. **Maintain Schema Accuracy**: Ensure all request/response schemas accurately reflect the Rust structs used in the API handlers.
3. **Document Comprehensively**: Include proper descriptions, examples, and parameter documentation.
## Key Files to Reference
- **API Route Definitions**: Look in `backend/windmill-api/src/` for route handlers organized by domain
- **Data Structures**: Check `backend/windmill-common/src/` for shared structs and types
- **Database Schema**: Reference `backend/summarized_schema.txt` for understanding data models
- **Existing OpenAPI Files**: Always review the current state of `openapi.yaml` and `openflow.openapi.yaml` before making changes
## Workflow
1. **Identify Changes**: Determine what API changes were made by examining:
- New or modified route handlers in windmill-api
- Changes to request/response structs
- Modifications to the Flow structure or related types
2. **Analyze the Implementation**: For each endpoint, identify:
- HTTP method and path
- Path parameters, query parameters, and request body schema
- Response schema(s) and status codes
- Authentication requirements
- Any tags or groupings
3. **Update OpenAPI Files**:
- Add or modify path definitions with accurate operation IDs
- Update or create schema definitions in the components section
- Ensure $ref references are correct
- Maintain consistent naming conventions with existing patterns
4. **Validate Changes**: Ensure the YAML syntax is valid and follows OpenAPI 3.0 specification.
## OpenAPI Conventions for Windmill
- **Operation IDs**: Use camelCase, descriptive names (e.g., `createScript`, `listFlows`, `updateWorkspaceSettings`)
- **Tags**: Group endpoints by domain (e.g., `scripts`, `flows`, `workspaces`, `users`)
- **Schema Naming**: Use PascalCase for schema names matching Rust struct names
- **Path Parameters**: Use `{workspace}` for workspace_id, maintain consistency with existing patterns
- **Security**: Most endpoints require Bearer token authentication - include appropriate security requirements
## Schema Mapping from Rust to OpenAPI
- `String` / `&str``type: string`
- `i32`, `i64``type: integer` (with appropriate format)
- `f32`, `f64``type: number`
- `bool``type: boolean`
- `Vec<T>``type: array` with `items`
- `Option<T>` → property is not in `required` array
- `HashMap<K, V>``type: object` with `additionalProperties`
- Enums → `type: string` with `enum` array
- Custom structs → `$ref` to schema definition
## Important Notes
- Always preserve existing documentation and descriptions when updating
- Maintain backward compatibility warnings in descriptions when applicable
- Include example values where they aid understanding
- For Flow-related changes, update BOTH openapi.yaml AND openflow.openapi.yaml as needed
- Follow the existing indentation and formatting style in the YAML files
When you complete updates, summarize what changes were made to which files and highlight any schema additions or modifications that downstream consumers should be aware of.

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env bash
# Resolve _ee.rs symlinks to actual files so Claude can read them
# This script runs before each user prompt is processed
set -e
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-/home/farhad/windmill}"
MANIFEST_FILE="$PROJECT_DIR/.claude/hooks/.symlink-manifest"
# Find all _ee.rs symlinks and store their targets
find "$PROJECT_DIR" -name "*_ee.rs" -type l 2>/dev/null | while read -r symlink; do
target=$(readlink -f "$symlink" 2>/dev/null) || continue
# Only process if target file exists
if [[ -f "$target" ]]; then
# Store symlink path and target in manifest
echo "$symlink|$target" >> "$MANIFEST_FILE.tmp"
# Replace symlink with actual file content
rm "$symlink"
cp "$target" "$symlink"
fi
done
# Atomically replace manifest
if [[ -f "$MANIFEST_FILE.tmp" ]]; then
mv "$MANIFEST_FILE.tmp" "$MANIFEST_FILE"
fi
exit 0

View File

@@ -1,36 +0,0 @@
#!/usr/bin/env bash
# Restore _ee.rs symlinks after Claude finishes processing
# This script runs when Claude stops
# IMPORTANT: Copies any modifications back to the target before restoring symlinks
set -e
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-/home/farhad/windmill}"
MANIFEST_FILE="$PROJECT_DIR/.claude/hooks/.symlink-manifest"
# Check if manifest exists
if [[ ! -f "$MANIFEST_FILE" ]]; then
exit 0
fi
# Read manifest and restore symlinks
while IFS='|' read -r symlink target; do
if [[ -n "$symlink" && -n "$target" ]]; then
# If the file exists (not a symlink) and target exists, copy changes back
if [[ -f "$symlink" && ! -L "$symlink" && -e "$target" ]]; then
# Copy the potentially modified file back to the target
cp "$symlink" "$target"
fi
# Remove the regular file (which was a copy)
rm -f "$symlink" 2>/dev/null || true
# Recreate the symlink
ln -s "$target" "$symlink" 2>/dev/null || true
fi
done < "$MANIFEST_FILE"
# Clean up manifest
rm -f "$MANIFEST_FILE"
exit 0

View File

@@ -1,100 +0,0 @@
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/resolve-symlinks.sh",
"timeout": 30
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/restore-symlinks.sh",
"timeout": 30
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/restore-symlinks.sh",
"timeout": 30
}
]
}
]
},
"permissions": {
"allow": [
"Bash(ls:*)",
"Bash(grep:*)",
"Bash(cat:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(less:*)",
"Bash(more:*)",
"Bash(find:*)",
"Bash(wc:*)",
"Bash(diff:*)",
"Bash(file:*)",
"Bash(stat:*)",
"Bash(tree:*)",
"Bash(pwd)",
"Bash(which:*)",
"Bash(whereis:*)",
"Bash(echo:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git branch:*)",
"Bash(git show:*)",
"Bash(git blame:*)"
],
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/credentials.json)",
"Read(**/*secret*)",
"Edit(.env)",
"Edit(.env.*)",
"Edit(**/.env)",
"Edit(**/.env.*)"
],
"ask": [
"Bash(rm:*)",
"Bash(rmdir:*)",
"Bash(mv:*)",
"Bash(chmod:*)",
"Bash(chown:*)",
"Bash(truncate:*)",
"Bash(shred:*)",
"Bash(unlink:*)",
"Bash(git push:*)",
"Bash(git reset:*)",
"Bash(git revert:*)",
"Bash(git checkout:*)",
"Bash(git merge:*)",
"Bash(git rebase:*)"
]
},
"enableAllProjectMcpServers": true,
"enabledPlugins": {
"rust-analyzer-lsp@claude-plugins-official": true,
"typescript-lsp@claude-plugins-official": true
}
}

View File

@@ -3,4 +3,3 @@ frontend/build/
frontend/.svelte-kit/
backend/target/
backend/windmill-duckdb-ffi-internal/target/

6
.github/CODEOWNERS vendored
View File

@@ -1,4 +1,4 @@
* @rubenfiszel @hugocasa @alpetric
* @rubenfiszel @HugoCasa @alpetric
/community/ @rubenfiszel @hugocasa @alpetric
/frontend/ @rubenfiszel @hugocasa @alpetric
/community/ @rubenfiszel @HugoCasa @alpetric
/frontend/ @rubenfiszel @HugoCasa @alpetric

View File

@@ -28,7 +28,7 @@ ENV PATH="${PATH}:/usr/local/go/bin"
ENV GO_PATH=/usr/local/go/bin/go
# UV
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.9.24/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.4.18/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv
ENV TZ=Etc/UTC
@@ -42,7 +42,7 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER
RUN /usr/local/bin/python3 -m pip install pip-tools
# Bun
COPY --from=oven/bun:1.2.23 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.2.4 /usr/local/bin/bun /usr/bin/bun
ARG TARGETPLATFORM
@@ -57,12 +57,8 @@ RUN apt-get update \
RUN rustup component add rustfmt
# C#
RUN wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh \
&& chmod +x dotnet-install.sh \
&& ./dotnet-install.sh --channel 9.0 --install-dir /usr/share/dotnet \
&& ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet \
&& rm dotnet-install.sh
COPY --from=bitnami/dotnet-sdk:9.0.101-debian-12-r0 /opt/bitnami/dotnet-sdk /opt/dotnet-sdk
RUN ln -s /opt/dotnet-sdk/bin/dotnet /usr/bin/dotnet
# Nushell
COPY --from=ghcr.io/nushell/nushell:0.101.0-bookworm /usr/bin/nu /usr/bin/nu

View File

@@ -7,7 +7,7 @@ VERSION=$1
echo "Updating versions to: $VERSION"
sed -i '' -e "/^version =/s/= .*/= \"$VERSION\"/" ${root_dirpath}/backend/Cargo.toml
sed -i '' -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/cli/src/main.ts
sed -i '' -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/cli/main.ts
sed -i '' -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/benchmarks/lib.ts
sed -i '' -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/backend/windmill-api/openapi.yaml
sed -i '' -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/openflow.openapi.yaml

View File

@@ -7,7 +7,7 @@ VERSION=$1
echo "Updating versions to: $VERSION"
sed -i -e "/^version =/s/= .*/= \"$VERSION\"/" ${root_dirpath}/backend/Cargo.toml
sed -i -e "/^export const VERSION =/s/= .*/= \"$VERSION\";/" ${root_dirpath}/cli/src/main.ts
sed -i -e "/^export const VERSION =/s/= .*/= \"$VERSION\";/" ${root_dirpath}/cli/main.ts
sed -i -e "/^export const VERSION =/s/= .*/= \"v$VERSION\";/" ${root_dirpath}/benchmarks/lib.ts
sed -i -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/backend/windmill-api/openapi.yaml
sed -i -e "/version: /s/: .*/: $VERSION/" ${root_dirpath}/openflow.openapi.yaml

View File

@@ -1,94 +0,0 @@
name: Aider Auto-fix PR Review Change Requests
on:
pull_request_review:
types: [submitted]
jobs:
check-membership:
if: github.event.review.state == 'changes_requested' && contains(github.event.pull_request.title, '[Aider PR]')
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 }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }}
steps:
- name: Acknowledge Request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
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: 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: |
REVIEW_BODY_ESCAPED="${REVIEW_BODY//\\/\\\\}"
REVIEW_BODY_ESCAPED="${REVIEW_BODY_ESCAPED//\"/\\\"}"
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)
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."
COMPLETE_PROMPT="${BASE_PROMPT}"$'\n'"REVIEW:"$'\n'"${REVIEW_BODY_ESCAPED}"$'\n'"REVIEW_COMMENTS:"$'\n'"${FORMATTED_COMMENTS}"
echo "prompt_content<<EOF" >> $GITHUB_OUTPUT
echo "$COMPLETE_PROMPT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
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

View File

@@ -1,522 +0,0 @@
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

View File

@@ -1,80 +0,0 @@
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

View File

@@ -1,165 +0,0 @@
name: Aider Auto-fix issues and PR comments via external prompt
on:
issue_comment:
types: [created]
jobs:
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
issues: write
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 }}
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: Acknowledge Request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
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: 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: |
echo "Determining inputs for Aider..."
ISSUE_TITLE_VAL=""
ISSUE_BODY_VAL=""
if [[ ! -z "${{ github.event.issue.pull_request }}" ]]; then
echo "This is a comment on a Pull Request"
PR_NUMBER="$ISSUE_NUMBER"
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
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"
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
ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON")
ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON")
fi
fi
echo "ISSUE_TITLE<<EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT"
echo "$ISSUE_TITLE_VAL" >> "$GITHUB_OUTPUT"
echo "EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT"
echo "ISSUE_BODY<<EOF_AIDER_BODY" >> "$GITHUB_OUTPUT"
echo "$ISSUE_BODY_VAL" >> "$GITHUB_OUTPUT"
echo "EOF_AIDER_BODY" >> "$GITHUB_OUTPUT"
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

View File

@@ -20,7 +20,10 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.90.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
@@ -41,13 +44,16 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.90.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
run: |
mkdir -p fake_frontend_build
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --features all_sqlx_features
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --all-features
check_ee:
runs-on: ubicloud-standard-8
@@ -75,7 +81,10 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.90.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
@@ -112,10 +121,13 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.90.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
timeout-minutes: 16
working-directory: ./backend
run: |
mkdir -p fake_frontend_build
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --features all_sqlx_features,private
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --all-features

View File

@@ -45,48 +45,24 @@ jobs:
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.43
- uses: astral-sh/setup-uv@v6.2.1
- uses: astral-sh/setup-uv@v4
with:
version: "0.9.24"
version: "0.4.18"
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.90.0
- name: Read EE repo commit hash
run: |
echo "ee_repo_ref=$(cat ./ee-repo-ref.txt)" >> "$GITHUB_ENV"
- uses: actions/checkout@v4
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
repository: windmill-labs/windmill-ee-private
path: ./windmill-ee-private
ref: ${{ env.ee_repo_ref }}
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
- name: Substitute EE code (EE logic is behind feature flag)
run: |
./substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Cache DuckDB FFI module build
uses: actions/cache@v3
with:
path: ./backend/windmill-duckdb-ffi-internal/target
key: ${{ runner.os }}-duckdb-ffi-${{ hashFiles('./backend/windmill-duckdb-ffi-internal/src/**/*.rs', './backend/windmill-duckdb-ffi-internal/Cargo.toml', './backend/windmill-duckdb-ffi-internal/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-duckdb-ffi-
workspaces: backend
- name: cargo test
timeout-minutes: 16
env:
SQLX_OFFLINE: true
DATABASE_URL: postgres://postgres:changeme@localhost:5432/windmill
DISABLE_EMBEDDING: true
RUST_LOG: info
RUST_LOG_STYLE: never
CARGO_NET_GIT_FETCH_WITH_CLI: true
WMDEBUG_FORCE_V0_WORKSPACE_DEPENDENCIES: 1
WMDEBUG_FORCE_RUNNABLE_SETTINGS_V0: 1
WMDEBUG_FORCE_NO_LEGACY_DEBOUNCING_COMPAT: 1
run: |
deno --version && bun -v && go version && python3 --version
cd windmill-duckdb-ffi-internal && ./build_dev.sh && cd ..
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go) UV_PATH=$(which uv) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private --all -- --nocapture
run:
deno --version && bun -v && go version && python3 --version &&
SQLX_OFFLINE=true
DATABASE_URL=postgres://postgres:changeme@localhost:5432/windmill
DISABLE_EMBEDDING=true RUST_LOG=info
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go)
UV_PATH=$(which uv) cargo test --features
enterprise,deno_core,license,python,rust,scoped_cache --all --
--nocapture

View File

@@ -1,65 +0,0 @@
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
name: Build windmill-extra
on:
workflow_dispatch:
inputs:
tag:
description: "Tag for the image"
required: false
default: "dev"
type: string
permissions: write-all
jobs:
sleep:
runs-on: ubicloud
steps:
- name: Sleep for 900 seconds waiting for pypi to update index
if: startsWith(github.ref, 'refs/tags/v')
run: sleep 900
shell: bash
build_extra:
runs-on: ubicloud
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
fetch-depth: 0
- uses: depot/setup-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-extra
flavor: |
latest=false
tags: |
type=raw,value=${{ github.event.inputs.tag }}
type=sha,enable=true,priority=100,prefix=,suffix=,format=short
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: depot/build-push-action@v1
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileExtra"
tags: |
${{ steps.meta.outputs.tags }}
labels: |
${{ steps.meta.outputs.labels }}

View File

@@ -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,private
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
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,private
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
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
@@ -97,12 +97,6 @@ jobs:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/windmill/target/release/windmill"
- uses: shrink/actions-docker-extract@v3
id: extract-duckdb-ffi-internal
with:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/usr/src/app/libwindmill_duckdb_ffi_internal.so"
# - uses: shrink/actions-docker-extract@v3
# id: extract-ee-arm64
# with:
@@ -117,12 +111,8 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: RHEL9-amd64 build
path: ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9
- uses: actions/upload-artifact@v4
with:
name: RHEL9-amd64 dynamic libraries build
path: ${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/libwindmill_duckdb_ffi_internal.so
path: ${{ steps.extract-ee-amd64.outputs.destination
}}/windmill-ee-amd64-rhel9
# - uses: actions/upload-artifact@v4
# with:

View File

@@ -1,140 +0,0 @@
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
name: Build and publish windmill for RHEL8
on: workflow_dispatch
permissions: write-all
jobs:
build_ee:
runs-on: ubicloud
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Read EE repo commit hash
run: |
echo "ee_repo_ref=$(cat ./backend/ee-repo-ref.txt)" >> "$GITHUB_ENV"
- uses: actions/checkout@v4
with:
repository: windmill-labs/windmill-ee-private
path: ./windmill-ee-private
ref: ${{ env.ee_repo_ref }}
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-rhel8
flavor: |
latest=false
tags: |
type=sha
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Substitute EE code
run: |
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Copy RHEL8 Dockerfile
run: |
cp ./docker/RHEL8/Dockerfile ./Dockerfile
- name: Build and push publicly ee amd64
uses: depot/build-push-action@v1
with:
context: .
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,private
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
tags: |
${{ steps.meta-ee-public.outputs.tags }}-amd64
labels: |
${{ steps.meta-ee-public.outputs.labels }}-amd64
org.opencontainers.image.licenses=Windmill-Enterprise-License
- name: Build and push publicly ee arm64
uses: depot/build-push-action@v1
with:
context: .
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,private
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
tags: |
${{ steps.meta-ee-public.outputs.tags }}-arm64
labels: |
${{ steps.meta-ee-public.outputs.labels }}-arm64
org.opencontainers.image.licenses=Windmill-Enterprise-License
- uses: shrink/actions-docker-extract@v3
id: extract-ee-amd64
with:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/windmill/target/release/windmill"
- uses: shrink/actions-docker-extract@v3
id: extract-duckdb-ffi-internal
with:
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
path: "/usr/src/app/libwindmill_duckdb_ffi_internal.so"
# - uses: shrink/actions-docker-extract@v3
# id: extract-ee-arm64
# with:
# image: ${{ steps.meta-ee-public.outputs.tags}}-arm64
# path: "/windmill/target/release/windmill"
- name: Rename binary with corresponding architecture
run: |
mv "${{ steps.extract-ee-amd64.outputs.destination }}/windmill" "${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel8"
# mv "${{ steps.extract-ee-arm64.outputs.destination }}/windmill" "${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel8"
- uses: actions/upload-artifact@v4
with:
name: RHEL8-amd64 build
path: ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel8
- uses: actions/upload-artifact@v4
with:
name: RHEL8-amd64 dynamic libraries build
path: ${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/libwindmill_duckdb_ffi_internal.so
# - uses: actions/upload-artifact@v4
# with:
# name: RHEL8-arm64 build
# path:
# ${{ steps.extract-ee-arm64.outputs.destination
# }}/windmill-ee-arm64-rhel8
# - name: Attach binary to release
# uses: softprops/action-gh-release@v2
# if: startsWith(github.ref, 'refs/tags/')
# with:
# files: |
# ${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel8
# ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel8

View File

@@ -33,7 +33,7 @@ jobs:
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.90.0
toolchain: 1.85.0
override: true
- name: Substitute EE code
@@ -41,13 +41,7 @@ jobs:
run: |
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Cargo build dynamic libraries windows
timeout-minutes: 90
run: |
cd backend/windmill-duckdb-ffi-internal
cargo build --release -p windmill_duckdb_ffi_internal
- name: Cargo build binary windows
- name: Cargo build windows
timeout-minutes: 90
run: |
vcpkg.exe install openssl-windows:x64-windows
@@ -57,19 +51,13 @@ 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_windows,mcp,private
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
- name: Rename binary with corresponding architecture
run: |
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
- name: Upload binary artifact
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: windmill-ee-binary
path: ./backend/target/release/windmill-ee.exe
- name: Upload dynamic libraries artifact
uses: actions/upload-artifact@v4
with:
name: windmill_duckdb_ffi_internal.dll
path: ./backend/windmill-duckdb-ffi-internal/target/release/windmill_duckdb_ffi_internal.dll

View File

@@ -9,14 +9,7 @@ jobs:
runs-on: ubicloud
container: node:18
steps:
- uses: actions/create-github-app-token@v2
id: app
with:
app-id: ${{ vars.INTERNAL_APP_ID }}
private-key: ${{ secrets.INTERNAL_APP_KEY }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app.outputs.token }}
- run: git config --system --add safe.directory /__w/windmill/windmill
- name: Change versions
run: ./.github/change-versions.sh "$(cat version.txt)"
@@ -28,8 +21,3 @@ jobs:
cd backend
cargo generate-lockfile
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_user_name: windmill-internal-app[bot]
commit_user_email: windmill-internal-app[bot]@users.noreply.github.com
env:
GITHUB_TOKEN: ${{ steps.app.outputs.token }}

View File

@@ -1,66 +0,0 @@
name: Check Organization Membership
on:
workflow_call:
inputs:
commenter:
required: true
type: string
description: 'The username to check for organization membership'
organization:
required: false
type: string
default: 'windmill-labs'
description: 'The organization to check membership for'
trusted_bot:
required: false
type: string
default: 'windmill-internal-app[bot]'
description: 'The trusted bot username to allow'
secrets:
access_token:
required: true
description: 'The access token to use for org membership check'
outputs:
is_member:
description: 'Whether the user is an organization member or trusted bot'
value: ${{ jobs.check-membership.outputs.is_member }}
jobs:
check-membership:
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.access_token }}
COMMENTER: ${{ inputs.commenter }}
ORG: ${{ inputs.organization }}
TRUSTED_BOT: ${{ inputs.trusted_bot }}
run: |
# 1. Allow the trusted bot straight away
if [[ "$COMMENTER" == "$TRUSTED_BOT" ]]; then
echo "is_member=true" >> $GITHUB_OUTPUT
exit 0
fi
# 2. Disallow other bots
if [[ "${COMMENTER}" =~ \[bot\]$ ]]; then
echo "is_member=false" >> $GITHUB_OUTPUT
exit 0
fi
# 3. Otherwise check if the user is a member of the organization
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

View File

@@ -1,76 +0,0 @@
name: Fast Claude
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
determine-commenter:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai-fast')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai-fast')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai-fast')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '/ai-fast'))
runs-on: ubicloud-standard-2
outputs:
commenter: ${{ steps.determine-commenter.outputs.commenter }}
steps:
- name: Determine commenter
id: determine-commenter
run: |
# Work out who wrote the comment / review
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
echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
check-membership:
needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
with:
commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
claude-code-action:
needs: [determine-commenter, check-membership]
if: |
needs.check-membership.outputs.is_member == 'true'
runs-on: ubicloud-standard-8
permissions:
contents: write
pull-requests: write
issues: write
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@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
allowed_bots: "windmill-internal-app[bot]"
trigger_phrase: "/ai-fast"
settings: |
{
"env": {
"SQLX_OFFLINE": "true"
}
}
claude_args: |
--allowedTools "Bash,WebFetch,WebSearch"
--model opus

View File

@@ -1,91 +0,0 @@
name: Claude Plan Assistant
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
determine-commenter:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/plan')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/plan')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/plan')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '/plan'))
runs-on: ubicloud-standard-2
outputs:
commenter: ${{ steps.determine-commenter.outputs.commenter }}
steps:
- name: Determine commenter
id: determine-commenter
run: |
# Work out who wrote the comment / review
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
echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
check-membership:
needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
with:
commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
claude-plan-action:
needs: [determine-commenter, check-membership]
if: |
needs.check-membership.outputs.is_member == 'true'
runs-on: ubicloud-standard-4
timeout-minutes: 20
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 Plan Action
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
allowed_bots: 'windmill-internal-app[bot]'
trigger_phrase: '/plan'
claude_args: |
--model opus
--system-prompt "# Claude Planning Mode
You are operating in PLANNING MODE ONLY. Your role is to create detailed, structured plans without making any code changes.
## Your Responsibilities:
1. **Analyze the Request**: Carefully read and understand what the user is asking for
2. **Explore the Codebase**: Understand the relevant code structure
3. **Create a Detailed Plan**: Provide a comprehensive, step-by-step plan that includes:
- Clear breakdown of all tasks needed
- Files that will need to be modified or created
- Code patterns and architecture decisions
- Potential challenges and how to address them
- If there are multiple options to achieve the same goal, explain the pros and cons of each option
## Strict Constraints:
- **DO NOT** make any code changes
- **DO NOT** create branches or pull requests
Remember: You are here to plan, not to implement. Provide thorough analysis and clear guidance for implementation."

View File

@@ -1,129 +0,0 @@
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:
determine-commenter:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '/ai'))
runs-on: ubicloud-standard-2
outputs:
commenter: ${{ steps.determine-commenter.outputs.commenter }}
steps:
- name: Determine commenter
id: determine-commenter
run: |
# Work out who wrote the comment / review
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
echo "commenter=$COMMENTER" >> $GITHUB_OUTPUT
check-membership:
needs: determine-commenter
uses: ./.github/workflows/check-org-membership.yml
with:
commenter: ${{ needs.determine-commenter.outputs.commenter }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
claude-code-action:
needs: [determine-commenter, check-membership]
if: |
needs.check-membership.outputs.is_member == 'true'
runs-on: ubicloud-standard-8
timeout-minutes: 60
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Run npm install and generate-backend-client
working-directory: ./frontend
run: |
# add a build directory for cargo check
mkdir -p build
npm install
npm run generate-backend-client
- name: install xmlsec1
run: |
sudo apt-get update
sudo apt-get install -y libxml2-dev libxmlsec1-dev
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.90.0
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
run: |
SQLX_OFFLINE=true cargo check --features $(./all_features_oss.sh)
- name: Run Claude PR Action
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
allowed_bots: "windmill-internal-app[bot]"
trigger_phrase: "/ai"
settings: |
{
"env": {
"SQLX_OFFLINE": "true"
}
}
claude_args: |
--allowedTools "Bash,WebFetch,WebSearch"
--model opus
--system-prompt "## IMPORTANT INSTRUCTIONS
- Your branch name should be a short description of the requested changes.
- 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.
## Code Quality Requirements
After making any code changes, you MUST run the appropriate validation commands:
**Frontend Changes:**
- Run: \`npm run check\` in the frontend directory
- Fix all warnings and errors before proceeding
**Backend Changes:**
- Run: \`cargo check --features $(./all_features_oss.sh)\` in the backend directory
- Fix all warnings and errors before proceeding
**Pull Request Creation:**
- 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
- Bash: Full access to run validation commands and git operations"

View File

@@ -1,39 +0,0 @@
on:
issue_comment:
types: [created]
jobs:
check-membership:
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/docs') }}
uses: ./.github/workflows/check-org-membership.yml
with:
commenter: ${{ github.event.comment.user.login }}
secrets:
access_token: ${{ secrets.ORG_ACCESS_TOKEN }}
generate-token:
needs: check-membership
if: ${{ needs.check-membership.outputs.is_member == 'true' }}
runs-on: ubicloud-standard-2
outputs:
app_token: ${{ steps.app.outputs.token }}
steps:
- name: Generate an installation token
id: app
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.INTERNAL_APP_ID }}
private-key: ${{ secrets.INTERNAL_APP_KEY }}
owner: windmill-labs
trigger-docs:
needs: [generate-token, check-membership]
if: ${{ needs.check-membership.outputs.is_member == 'true' }}
uses: windmill-labs/windmilldocs/.github/workflows/create-docs.yml@main
with:
pr_number: ${{ github.event.issue.number }}
repo: ${{ github.event.repository.name }}
comment_text: ${{ github.event.comment.body }}
secrets:
DOCS_TOKEN: ${{ needs.generate-token.outputs.app_token }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}

View File

@@ -1,35 +0,0 @@
name: Create discord thread when a PR is opened, react with green checkmark when PR is merged
on:
pull_request:
types:
- opened
- ready_for_review
- closed
jobs:
notify_discord_when_pr_opened:
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 }}
PR_URL: ${{ github.event.pull_request.html_url }}
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.action == 'closed'
uses: ./.github/workflows/shareable-discord-notification.yml
with:
PR_STATUS: "merged"
DISCORD_CHANNEL_ID: "1372204995868491786"
DISCORD_GUILD_ID: "930051556043276338"
PR_NUMBER: ${{ github.event.pull_request.number }}
secrets:
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_AI_BOT_TOKEN }}

View File

@@ -29,11 +29,6 @@ on:
required: false
default: false
type: boolean
slim:
description: "Build slim image (true, false)"
required: false
default: false
type: boolean
concurrency:
group: ${{ github.ref }}
cancel-in-progress: false
@@ -97,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,private
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
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
${{ steps.meta-public.outputs.tags }}
@@ -159,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,private,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,deno_core,mcp
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
${{ steps.meta-ee-public.outputs.tags }}
@@ -225,12 +220,6 @@ jobs:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
path: "/usr/src/app/windmill"
- uses: shrink/actions-docker-extract@v3
id: extract-duckdb-ffi-internal
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
path: "/usr/src/app/libwindmill_duckdb_ffi_internal.so"
- uses: shrink/actions-docker-extract@v3
id: extract-ee
with:
@@ -248,7 +237,6 @@ jobs:
files: |
${{ steps.extract.outputs.destination }}/*
${{ steps.extract-ee.outputs.destination }}/*
${{ steps.extract-duckdb-ffi-internal.outputs.destination }}/*
# attach_arm64_binary_to_release:
# needs: [build, build_ee]
@@ -593,10 +581,9 @@ jobs:
${{ steps.meta-ee-public.outputs.labels }}
build_ee_slim:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [build_ee]
runs-on: ubicloud
if: (github.event_name != 'pull_request') && ((github.event_name != 'workflow_dispatch') || (github.event.inputs.ee || github.event.inputs.slim))
steps:
- uses: actions/checkout@v4
with:
@@ -614,7 +601,6 @@ jobs:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-slim
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
@@ -629,7 +615,7 @@ jobs:
uses: depot/build-push-action@v1
with:
context: .
platforms: linux/amd64,linux/arm64
platforms: linux/amd64
push: true
file: "./docker/DockerfileSlimEe"
tags: |

View File

@@ -16,12 +16,11 @@ jobs:
runs-on: ubicloud-standard-8
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v5
- uses: actions/setup-node@v3
with:
node-version: 24
cache: "npm"
cache-dependency-path: "frontend/package-lock.json"
node-version: 18
- name: "npm check"
timeout-minutes: 5
run: cd frontend && npm ci && npm run generate-backend-client && npm run
run:
cd frontend && npm ci && npm run generate-backend-client && npm run
check

View File

@@ -1,285 +0,0 @@
name: Git commands
on:
issue_comment:
types: [created]
jobs:
update-sqlx:
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/updatesqlx')
runs-on: ubicloud-standard-8
permissions:
contents: write
pull-requests: write
issues: write
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: windmill
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/create-github-app-token@v2
id: app
with:
app-id: ${{ vars.INTERNAL_APP_ID }}
private-key: ${{ secrets.INTERNAL_APP_KEY }}
- name: Comment on PR - Starting
uses: actions/github-script@v6
with:
github-token: ${{ steps.app.outputs.token }}
script: |
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Starting sqlx update...\n\n[View workflow run](${runUrl})`
})
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ steps.app.outputs.token }}
ref: ${{ github.event.issue.pull_request.head.ref }}
fetch-depth: 0
- name: Checkout windmill-ee-private
uses: actions/checkout@v3
with:
repository: windmill-labs/windmill-ee-private
path: windmill-ee-private
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
# Cache rust dependencies
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: "./backend -> target"
- name: Install xmlsec build-time deps
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
pkg-config libxml2-dev libssl-dev \
xmlsec1 libxmlsec1-dev libxmlsec1-openssl
- name: Run update-sqlx script
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/windmill
GH_TOKEN: ${{ steps.app.outputs.token }}
run: |
set -e # Exit on any command failure
PR_NUMBER=${{ github.event.issue.number }}
# Set up error trap to comment on PR for any failure
trap 'gh pr comment $PR_NUMBER --body "❌ SQLx update failed. Please check the workflow logs for details."' ERR
BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName)
echo "Checking out PR branch: $BRANCH_NAME"
git checkout $BRANCH_NAME
git config --local user.email "windmill-internal-app[bot]@users.noreply.github.com"
git config --local user.name "windmill-internal-app[bot]"
git config pull.rebase true
git pull origin $BRANCH_NAME
mkdir -p frontend/build
cd backend
cargo install sqlx-cli --version 0.8.5
sqlx migrate run
./substitute_ee_code.sh --dir ./windmill-ee-private
./update_sqlx.sh
# Pass the branch name to the next step
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
- name: Commit changes if any
run: |
git add backend/.sqlx
git commit -m "Update SQLx metadata"
git push origin ${{ env.BRANCH_NAME }}
- name: Comment on PR - Completed
uses: actions/github-script@v6
with:
github-token: ${{ steps.app.outputs.token }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Successfully ran sqlx update'
})
demo:
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/demo')
runs-on: ubicloud-standard-2
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Claude Code for Demo Generation
uses: anthropics/claude-code-action@beta
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
timeout_minutes: "10"
allowed_tools: "Bash"
direct_prompt: |
You need to:
1. Extract the Cloudflare preview URL from the cloudflare-workers-and-pages bot comment in this PR
2. Analyze the PR changes to understand what feature was added/modified
3. Create detailed instructions to give to an AI agent that will click and interact with buttons and inputs to showcase the new feature. Only include the instructions, nothing else.
4. Create a demo.json file with a valid JSON object containing:
- instructions: the demo instructions
- url: the preview URL
5. VALIDATE the JSON file using `jq` before finishing
DO NOT COMMIT THIS FILE TO THE PR.
Example demo.json:
{
"instructions": "Click on settings, then account settings, then 'generate new token'",
"url": "https://example.pages.dev"
}
CRITICAL: After creating demo.json, you MUST:
1. Run `jq empty demo.json` to validate the JSON is properly formatted
2. If validation fails, fix the JSON and validate again
3. Only proceed once the JSON passes validation
4. Use proper JSON escaping for newlines, quotes, and special characters
Make sure to:
- Create a valid JSON object that passes `jq empty demo.json`
- Extract the correct preview URL (should be a .pages.dev domain)
- Create specific, actionable demo steps based on the actual changes in the PR
- Properly escape all strings in the JSON (use jq to create the file if needed)
- NOT COMMIT THE DEMO.JSON FILE TO THE PR
- name: Send instructions to Windmill
env:
DEMO_WEBHOOK_TOKEN: ${{ secrets.DEMO_WEBHOOK_TOKEN }}
run: |
if [[ -f "demo.json" ]]; then
echo "Found demo.json, sending to Windmill..."
cat demo.json
# Validate JSON one more time (Claude should have already done this)
if ! jq empty demo.json; then
echo "Error: demo.json is not valid JSON"
exit 1
fi
RESULT=$(curl -s \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $DEMO_WEBHOOK_TOKEN" \
-X POST \
-d @demo.json \
'https://app.windmill.dev/api/w/windmill-labs/jobs/run/f/f/ai/browserbase_demo')
echo "Windmill response:"
echo -E "$RESULT"
else
echo "Error: demo.json file not found"
exit 1
fi
update-ee-ref:
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/eeref')
runs-on: ubicloud-standard-2
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/create-github-app-token@v2
id: app
with:
app-id: ${{ vars.INTERNAL_APP_ID }}
private-key: ${{ secrets.INTERNAL_APP_KEY }}
- name: Comment on PR - Starting
uses: actions/github-script@v6
with:
github-token: ${{ steps.app.outputs.token }}
script: |
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Starting ee ref update...\n\n[View workflow run](${runUrl})`
})
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ steps.app.outputs.token }}
ref: ${{ github.event.issue.pull_request.head.ref }}
fetch-depth: 0
- name: Checkout windmill-ee-private
uses: actions/checkout@v3
with:
repository: windmill-labs/windmill-ee-private
path: windmill-ee-private
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
- name: Get last commit hash of private-repo
id: get-commit-hash
run: |
cd windmill-ee-private
COMMIT_HASH=$(git rev-parse HEAD)
echo "commit_hash=$COMMIT_HASH" >> $GITHUB_OUTPUT
echo "Latest commit hash: $COMMIT_HASH"
- name: Update ee-repo-ref.txt
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
run: |
set -e # Exit on any command failure
PR_NUMBER=${{ github.event.issue.number }}
# Set up error trap to comment on PR for any failure
trap 'gh pr comment $PR_NUMBER --body "❌ EE ref update failed. Please check the workflow logs for details."' ERR
BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName)
echo "Checking out PR branch: $BRANCH_NAME"
git checkout $BRANCH_NAME
git config --local user.email "windmill-internal-app[bot]@users.noreply.github.com"
git config --local user.name "windmill-internal-app[bot]"
git config pull.rebase true
git pull origin $BRANCH_NAME
echo "${{ steps.get-commit-hash.outputs.commit_hash }}" > backend/ee-repo-ref.txt
echo "Updated backend/ee-repo-ref.txt with commit hash: ${{ steps.get-commit-hash.outputs.commit_hash }}"
# commit and push the changes
git add backend/ee-repo-ref.txt
git commit -m "Update ee-repo-ref.txt" || echo "No changes to commit"
git push origin $BRANCH_NAME
- name: Comment on PR - Completed
uses: actions/github-script@v6
with:
github-token: ${{ steps.app.outputs.token }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Successfully updated ee-repo-ref.txt'
})

View File

@@ -1,91 +0,0 @@
name: Publish Helm Chart on Release
on:
release:
types: [published]
jobs:
bump-helm-version:
runs-on: ubicloud-standard-2
steps:
- name: Generate an installation token
id: app
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.INTERNAL_APP_ID }}
private-key: ${{ secrets.INTERNAL_APP_KEY }}
owner: windmill-labs
- name: Checkout on helm repository
uses: actions/checkout@v3
with:
repository: windmill-labs/windmill-helm-charts
token: ${{ steps.app.outputs.token }}
- name: Get version
id: get_version
run: |
echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Create new branch
run: |
# Check if branch already exists remotely
if git ls-remote --heads origin bump-helm-version-${{ env.VERSION }} | grep -q bump-helm-version-${{ env.VERSION }}; then
# Branch exists, check it out
git fetch origin bump-helm-version-${{ env.VERSION }}
git checkout bump-helm-version-${{ env.VERSION }}
else
# Create new branch
git checkout -b bump-helm-version-${{ env.VERSION }}
fi
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Bump helm version
run: |
# Get current version and increment it by 1
CURRENT_VERSION=$(grep "version:" ./charts/windmill/Chart.yaml | awk '{print $2}' | head -n 1)
NEW_VERSION=$(echo "$CURRENT_VERSION" | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g')
sed -i "s/^version: .*/version: $NEW_VERSION/" ./charts/windmill/Chart.yaml
# Get the app version from the version
VERSION=${{ env.VERSION }}
APP_VERSION=${VERSION#refs/tag/}
APP_VERSION=${APP_VERSION#v}
APP_VERSION=${APP_VERSION%/}
sed -i "s/appVersion: .*/appVersion: $APP_VERSION/" ./charts/windmill/Chart.yaml
- name: Close existing bump-helm PRs
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
run: |
# List open PR numbers whose title starts with the prefix
prs=$(gh pr list \
--state open \
--search '"helm: bump version to" in:title' \
--json number \
-q '.[].number')
for pr in $prs; do
echo "Closing outdated bump PR #$pr"
gh pr close "$pr" \
--comment "Closed automatically superseded by a newer Helm-chart bump PR."
done
- name: Commit and push
run: |
git add .
git commit -m "Bump helm version to ${{ env.VERSION }}"
git push origin bump-helm-version-${{ env.VERSION }}
- name: Create PR
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
run: |
gh pr create \
--title "helm: bump version to ${{ env.VERSION }}" \
--body "This PR was auto-generated to bring the helm chart up to date for [release ${{ env.VERSION }}](https://github.com/windmill-labs/windmill/releases/tag/v${{ env.VERSION }}) in the main repo." \
--head bump-helm-version-${{ env.VERSION }} \
--base main

View File

@@ -1,38 +0,0 @@
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 }}

View File

@@ -1,48 +0,0 @@
name: Claude Auto Review
on:
pull_request:
types: [ready_for_review, opened]
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
auto-review:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false || github.event.pull_request.ready_for_review == true
permissions:
contents: read
pull-requests: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Automatic PR Review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
track_progress: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Please review this pull request and provide comprehensive feedback.
Focus on:
- Code quality and best practices
- Potential bugs or issues
- Performance considerations
- Security implications
Provide detailed feedback using inline comments for specific issues.
Use top-level comments for general observations or praise.
At the end of your review, add complete instructions to reproduce the added changes through the app interface. These instructions will be given to a tester so he can verify the changes. It should be a short descriptive text (not a step by step or a list) on how to navigate the app (what page, what action, what input, etc) to see the changes.
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
--model opus

View File

@@ -1,126 +0,0 @@
env:
REGISTRY: ghcr.io
ECR_REGISTRY: 976079455550.dkr.ecr.us-east-1.amazonaws.com
IMAGE_NAME: ${{ github.repository }}-extra
name: Publish windmill-extra
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions: write-all
jobs:
sleep:
runs-on: ubicloud
steps:
- name: Sleep for 900 seconds waiting for pypi to update index
if: startsWith(github.ref, 'refs/tags/v')
run: sleep 900
shell: bash
# Build and test the image before publishing
test_extra:
needs: [sleep]
runs-on: ubicloud-standard-8
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build test image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/DockerfileExtra
load: true
tags: windmill-extra:test
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Start container
run: |
docker run -d --name windmill-extra-test \
-p 3001:3001 -p 3002:3002 -p 3003:3003 \
-e ENABLE_LSP=true \
-e ENABLE_MULTIPLAYER=true \
-e ENABLE_DEBUGGER=true \
-e DEBUGGER_PORT=3003 \
-e REQUIRE_SIGNED_DEBUG_REQUESTS=false \
windmill-extra:test
# Wait for container to start
echo "Waiting for container to initialize..."
sleep 10
# Show container logs for debugging
docker logs windmill-extra-test
- name: Run integration tests
run: |
bun run docker/test_windmill_extra.ts
- name: Show container logs on failure
if: failure()
run: |
echo "=== Container logs ==="
docker logs windmill-extra-test
- name: Cleanup
if: always()
run: |
docker stop windmill-extra-test || true
docker rm windmill-extra-test || true
publish_extra:
needs: [sleep, test_extra]
runs-on: ubicloud-standard-8
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: depot/setup-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly
uses: depot/build-push-action@v1
with:
context: .
file: ./docker/DockerfileExtra
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ steps.meta.outputs.tags }}
labels: |
${{ steps.meta.outputs.labels }}
org.opencontainers.image.licenses=AGPLv3

View File

@@ -35,7 +35,7 @@ jobs:
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.90.0
toolchain: 1.85.0
override: true
- name: Substitute EE code
@@ -43,12 +43,6 @@ jobs:
run: |
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Cargo build dynamic libraries windows
timeout-minutes: 90
run: |
cd backend/windmill-duckdb-ffi-internal
cargo build --release -p windmill_duckdb_ffi_internal
- name: Cargo build windows
timeout-minutes: 90
run: |
@@ -59,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_windows,mcp,private
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
- name: Rename binary with corresponding architecture
run: |
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
@@ -69,9 +63,3 @@ jobs:
with:
files: |
./backend/target/release/windmill-ee.exe
- name: Attach dynamic libraries to release
uses: softprops/action-gh-release@v2
with:
files: |
./backend/windmill-duckdb-ffi-internal/target/release/windmill_duckdb_ffi_internal.dll

View File

@@ -1,27 +0,0 @@
name: Rust Client Check
on:
workflow_run:
workflows: ["Change versions"]
types:
- completed
push:
paths:
- "rust-client/**"
- "backend/**/*.rs"
- "backend/windmill-api/openapi.yaml"
- "version.txt"
- "flake.nix"
- ".github/workflows/rust-client-check.yml"
jobs:
check_rust_client:
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
- name: Check rust client builds
run: cd rust-client && nix develop ../ --command ./dev.nu --check
timeout-minutes: 16

View File

@@ -1,19 +0,0 @@
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 }}

View File

@@ -1,119 +0,0 @@
name: "Notify Discord when a PR is opened or merged"
on:
workflow_call:
inputs:
PR_TITLE:
description: "The title of the PR"
type: string
PR_URL:
description: "The URL of the PR"
type: string
PR_AUTHOR:
description: "The author of the PR"
type: string
PR_STATUS:
description: "The status of the PR"
type: string
DISCORD_CHANNEL_ID:
description: "The Discord channel ID"
type: string
PR_NUMBER:
description: "The number of the PR"
type: string
DISCORD_GUILD_ID:
description: "The Discord guild ID"
type: string
secrets:
DISCORD_WEBHOOK_URL:
description: "Discord Webhook URL"
DISCORD_BOT_TOKEN:
description: "Discord Bot Token"
jobs:
open_thread:
runs-on: ubicloud-standard-2
if: ${{ inputs.PR_STATUS == 'opened' }}
steps:
- 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: |
# 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
if: ${{ inputs.PR_STATUS == 'merged' }}
steps:
- name: React
env:
BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
CHANNEL_ID: ${{ inputs.DISCORD_CHANNEL_ID }}
GUILD_ID: ${{ inputs.DISCORD_GUILD_ID }}
PR_NUMBER: ${{ inputs.PR_NUMBER }}
run: |
# 1) get PR thread
threads=$(curl -H "Authorization: Bot $BOT_TOKEN" "https://discord.com/api/v10/guilds/${GUILD_ID}/threads/active")
thread_id=$(
echo "$threads" \
| jq -r --arg cid "$CHANNEL_ID" \
--arg pref "#${PR_NUMBER}:" \
'.threads[]
| select(.parent_id == $cid and (.name | startswith($pref)))
| .id'
)
if [ -z "$thread_id" ]; then
echo "Thread not found"
exit 1
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")
message_id=$(echo "$messages" | jq -r '.[-1].id')
if [ -z "$message_id" ]; then
echo "Message not found"
exit 1
fi
# 3) add the ✅ reaction
curl -X PUT \
-H "Authorization: Bot $BOT_TOKEN" \
"https://discord.com/api/v10/channels/$thread_id/messages/$message_id/reactions/%E2%9C%85/@me"

View File

@@ -1,34 +0,0 @@
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

View File

@@ -1,145 +0,0 @@
name: Weekly PR Summary
on:
schedule:
# Every Friday at 8:00 AM UTC
- cron: '0 8 * * 5'
workflow_dispatch:
# Allow manual triggering for testing
jobs:
weekly-pr-summary:
runs-on: ubicloud-standard-4
timeout-minutes: 30
permissions:
contents: read
pull-requests: read
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Generate Weekly PR Summary
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
prompt: |
REPO: ${{ github.repository }}
Generate a categorized weekly summary of ONLY MERGED Pull Requests from the past 7 days.
## Your Task:
1. **Calculate Date Range**:
- Run: `CUTOFF_DATE=$(date --date='7 days ago' --iso-8601)`
- Run: `TODAY=$(date --iso-8601)`
- This gives you the exact 7-day window (store these in variables for use in commands)
2. **Fetch ONLY Merged PRs from Past Week**:
- Command: `gh pr list --repo ${{ github.repository }} --state merged --search "merged:>=$CUTOFF_DATE" --limit 100 --json number,title,author,mergedAt,url`
- This returns ONLY PRs that were merged in the last 7 days
- The --search flag filters by merge date using GitHub's search syntax
- **FILTER OUT** any PRs with titles starting with "chore: release" or "chore(release)"
3. **Categorize PRs**: Group PRs into three categories by analyzing titles and labels:
- **Features**: PRs with titles starting with "feat:", "feature:", or containing "add", "implement", "new"
- **Bug Fixes**: PRs with titles starting with "fix:", "bug:", or containing "fix", "resolve", "patch"
- **Other**: All remaining PRs (improvements, refactors, docs, chores, etc.)
4. **Gather Details**: For each feature and bug fix merged PR, include:
- Full PR title (NO truncation, NO links)
- Author (extract login from author.login in JSON)
- Brief summary: Use `gh pr view <number> --json body` to get PR description, then extract first paragraph or key points (1-2 sentences max)
5. **Character Limit Enforcement**:
- The final summary MUST be under 5000 characters
- If the summary exceeds 5000 characters, truncate PR descriptions (NOT titles) and add at the end: "_and X more PRs_" where X is the count of omitted PRs
6. **Save Summary to Markdown File**: Write the summary to a file for webhook delivery:
- Save the complete formatted markdown to: `summary.md`
- Do not commit the file to the repository
## Output Format:
```markdown
### 📈 Weekly overview
- **Total merged**: X
- **Features**: Y
- **Bug Fixes**: Z
- **Other**: W
### ✨ Features (Y)
- **[Full PR Title]** by @username - [brief impact description]
- **[Full PR Title]** by @username - [brief impact description]
### 🐛 Bug Fixes (Z)
- **[Full PR Title]** by @username - [brief impact description]
- **[Full PR Title]** by @username - [brief impact description]
_and X more PRs_
```
## Important Notes:
- **CRITICAL**: ONLY include PRs with state "merged" from the last 7 days
- **CRITICAL**: EXCLUDE all PRs with titles starting with "chore: release" or "chore(release)"
- **CRITICAL**: Total character count MUST be under 5000 characters
- Count the number of "Other" PRs but do not include a section for them in the output
- Only use ### markdown headers for major sections and emoji indicators
- NO links to PRs
- NO merged date in output
- NEVER truncate PR titles - show full titles
- Use GitHub CLI (`gh`) for all operations
- Sort PRs within each category by merge date (most recent first)
- If a PR has no description, write "(No description provided)"
- Extract meaningful summary from PR body - look for the first paragraph or key bullet points
- Parse JSON responses carefully using `jq` or similar tools
- If summary exceeds 5000 chars, shorten PR descriptions and add "_and X more PRs_" at the end
- Count PRs in each category and display in both overview and section headers
## Saving the Markdown Output:
After generating the markdown summary, save it to a file, BUT DO NOT COMMIT IT TO THE REPOSITORY.
## Write Tool Fallback:
- First, attempt to use the Write tool to create `summary.md` with the markdown content
- If the Write tool returns ANY error or fails:
1. Use the Bash tool with the `echo` command instead
2. Use a heredoc to write the content: `cat > summary.md << 'EOF'` followed by your markdown content and `EOF` on a new line
3. Example: `cat > summary.md << 'EOF'\n[your markdown content here]\nEOF`
4. This ensures the file is always created regardless of Write tool issues
- Verify the file was created by running: `ls -lh summary.md`
claude_args: |
--allowedTools "Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash"
--model haiku
- name: Send Summary to Windmill
if: hashFiles('summary.md') != ''
env:
WEEKLY_SUMMARY_TOKEN: ${{ secrets.WEEKLY_SUMMARY_TOKEN }}
run: |
if [[ -f "summary.md" ]]; then
echo "Found summary.md, sending to Windmill..."
# Read the markdown content
MARKDOWN_CONTENT=$(cat summary.md)
# Create JSON payload
PAYLOAD=$(jq -n --arg markdown "$MARKDOWN_CONTENT" '{markdown: $markdown}')
# Send to Windmill webhook
RESULT=$(curl -s \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $WEEKLY_SUMMARY_TOKEN" \
-X POST \
-d "$PAYLOAD" \
'https://app.windmill.dev/api/w/windmill-labs/jobs/run/f/f/ai/send_past_week_pr_summaries_to_discord')
echo "Windmill response:"
echo -E "$RESULT"
echo "✅ Summary sent successfully to Windmill!"
else
echo "⚠️ Warning: summary.md not found, skipping delivery"
exit 1
fi

5
.gitignore vendored
View File

@@ -7,9 +7,6 @@ CaddyfileRemoteMalo
*.swp
**/.idea/
.direnv
/.vscode
.vscode
.dev-docker-wrapper*
backend/.minio-data
.aider*
!.aiderignore
rust-client/Cargo.toml

View File

@@ -1,8 +0,0 @@
{
"mcpServers": {
"svelte": {
"type": "http",
"url": "https://mcp.svelte.dev/mcp"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +0,0 @@
# Windmill Development Guide
## Overview
Windmill is an open-source developer platform for building internal tools, workflows, API integrations, background jobs, workflows, and user interfaces. See @windmill-overview.mdc for full platform details.
## New Feature Implementation Guidelines
When implementing new features in Windmill, follow these best practices:
- **Clean Code First**: Write clean, readable, and maintainable code. Prioritize clarity over cleverness.
- **Avoid Duplication at All Costs**: Before writing new code, thoroughly search for existing implementations that can be reused or extended.
- **Adapt Existing Code**: Refactor and generalize existing code when necessary to avoid logic duplication. Extract common patterns into reusable utilities.
- **Follow Established Patterns**: Study existing code patterns in the codebase and maintain consistency with established conventions.
- **Single Responsibility**: Each function, component, and module should have a single, well-defined responsibility.
- **Incremental Implementation**: Break large features into smaller, reviewable chunks that can be implemented and tested incrementally.
## Language-Specific Guides
- Backend (Rust): @backend/rust-best-practices.mdc + @backend/summarized_schema.txt
- Frontend (Svelte 5): @frontend/svelte5-best-practices.mdc
## Querying the Database
To query the database directly, use psql with the following connection string:
```bash
psql postgres://postgres:changeme@localhost:5432/windmill
```
This can be helpful for:
- Inspecting database state during development
- Testing queries before implementing them in Rust
- Debugging data-related issues

View File

@@ -10,26 +10,9 @@
{$BASE_URL} {
bind {$ADDRESS}
# LSP - Language Server Protocol for code intelligence (windmill_extra:3001)
reverse_proxy /ws/* http://windmill_extra:3001
# Multiplayer - Real-time collaboration, Enterprise Edition (windmill_extra:3002)
# Uncomment and set ENABLE_MULTIPLAYER=true in docker-compose.yml
# reverse_proxy /ws_mp/* http://windmill_extra:3002
# Debugger - Interactive debugging via DAP WebSocket (windmill_extra:3003)
# Set ENABLE_DEBUGGER=true in docker-compose.yml to enable
handle_path /ws_debug/* {
reverse_proxy http://windmill_extra:3003
}
# Search indexer, Enterprise Edition (windmill_indexer:8002)
reverse_proxy /ws/* http://lsp:3001
# reverse_proxy /ws_mp/* http://multiplayer:3002
# reverse_proxy /api/srch/* http://windmill_indexer:8002
# Default: Windmill server
reverse_proxy /* http://windmill_server:8000
# TLS with custom certificates
# tls /certs/cert.pem /certs/key.pem
}

View File

@@ -1,5 +1,5 @@
ARG DEBIAN_IMAGE=debian:bookworm-slim
ARG RUST_IMAGE=rust:1.90-slim-bookworm
ARG RUST_IMAGE=rust:1.85-slim-bookworm
FROM ${RUST_IMAGE} AS rust_base
@@ -20,21 +20,7 @@ WORKDIR /windmill
ENV SQLX_OFFLINE=true
# ENV CARGO_INCREMENTAL=1
FROM rust_base AS windmill_duckdb_ffi_internal_builder
WORKDIR /windmill-duckdb-ffi-internal
RUN apt-get update && apt-get install -y clang=1:14.0-55.* libclang-dev=1:14.0-55.* cmake=3.25.* && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
COPY ./backend/windmill-duckdb-ffi-internal .
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=$SCCACHE_DIR,sharing=locked \
cargo build --release -p windmill_duckdb_ffi_internal
FROM node:24-alpine as frontend
FROM node:20-alpine as frontend
# install dependencies
WORKDIR /frontend
@@ -48,18 +34,16 @@ RUN mkdir /backend
COPY /backend/windmill-api/openapi.yaml /backend/windmill-api/openapi.yaml
COPY /openflow.openapi.yaml /openflow.openapi.yaml
COPY /backend/windmill-api/build_openapi.sh /backend/windmill-api/build_openapi.sh
COPY /system_prompts/auto-generated /system_prompts/auto-generated
RUN cd /backend/windmill-api && . ./build_openapi.sh
COPY /backend/parsers/windmill-parser-wasm/pkg/ /backend/parsers/windmill-parser-wasm/pkg/
COPY /typescript-client/docs/ /frontend/static/tsdocs/
COPY /python-client/docs/ /frontend/static/pydocs/
RUN npm run generate-backend-client
ENV NODE_OPTIONS "--max-old-space-size=8192"
ARG VITE_BASE_URL ""
# Read more about macro in docker/dev.nu
# -- MACRO-SPREAD-WASM-PARSER-DEV-ONLY -- #
# -- MACRO-SPREAD-WASM-PARSER-DEV-ONLY -- #
RUN npm run build
@@ -98,6 +82,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=$SCCACHE_DIR,sharing=locked \
CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release --features "$features"
FROM ${DEBIAN_IMAGE}
ARG TARGETPLATFORM
@@ -105,8 +90,7 @@ ARG POWERSHELL_VERSION=7.5.0
ARG POWERSHELL_DEB_VERSION=7.5.0-1
ARG KUBECTL_VERSION=1.28.7
ARG HELM_VERSION=3.14.3
# NOTE: If changing, also change go version in workspace dependencies template at WorkspaceDependenciesEditor.svelte
ARG GO_VERSION=1.25.0
ARG GO_VERSION=1.22.5
ARG APP=/usr/src/app
ARG WITH_POWERSHELL=true
ARG WITH_KUBECTL=true
@@ -117,19 +101,16 @@ ARG WITH_GIT=true
# 1. Change placeholder in instanceSettings.ts
# 2. Change LATEST_STABLE_PY in dockerfile
# 3. Change #[default] annotation for PyVersion in backend
ARG LATEST_STABLE_PY=3.12
ARG LATEST_STABLE_PY=3.11.10
ENV UV_PYTHON_INSTALL_DIR=/tmp/windmill/cache/py_runtime
ENV UV_PYTHON_PREFERENCE=only-managed
RUN mkdir -p /usr/local/uv
ENV UV_TOOL_BIN_DIR=/usr/local/bin
ENV UV_TOOL_DIR=/usr/local/uv
ENV PATH /usr/local/bin:/root/.local/bin:/tmp/.local/bin:$PATH
ENV PATH /usr/local/bin:/root/.local/bin:$PATH
RUN apt-get update \
&& apt-get install -y --no-install-recommends netbase tzdata ca-certificates wget curl jq unzip build-essential unixodbc xmlsec1 software-properties-common tini \
&& apt-get install -y --no-install-recommends netbase tzdata ca-certificates wget curl jq unzip build-essential unixodbc xmlsec1 software-properties-common \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@@ -190,51 +171,30 @@ ENV PATH="${PATH}:/usr/local/go/bin"
ENV GO_PATH=/usr/local/go/bin/go
# Install UV
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.9.24/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.2/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
# Preinstall python runtimes to temp build location (will copy with world-writable perms later)
RUN UV_CACHE_DIR=/tmp/build_cache/uv UV_PYTHON_INSTALL_DIR=/tmp/build_cache/py_runtime uv python install 3.11
RUN UV_CACHE_DIR=/tmp/build_cache/uv UV_PYTHON_INSTALL_DIR=/tmp/build_cache/py_runtime uv python install $LATEST_STABLE_PY
# Preinstall python runtimes
RUN uv python install 3.11
RUN uv python install $LATEST_STABLE_PY
RUN uv venv
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash -
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get -y update && apt-get install -y curl procps nodejs awscli && apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# go build is slower the first time it is ran, so we prewarm it in the build
# This mirrors Windmill's Go wrapper structure: main.go imports inner package, uses encoding/json, os, fmt
RUN export GOCACHE=/tmp/build_cache/go && \
mkdir -p /tmp/gobuildwarm/inner && \
cd /tmp/gobuildwarm && \
go mod init mymod && \
printf 'package main\nimport (\n\t"encoding/json"\n\t"os"\n\t"fmt"\n\t"mymod/inner"\n)\nfunc main() {\n\tdat, _ := os.ReadFile("args.json")\n\tvar req inner.Req\n\tjson.Unmarshal(dat, &req)\n\tres, _ := inner.Run(req)\n\tres_json, _ := json.Marshal(res)\n\tfmt.Println(string(res_json))\n}' > main.go && \
printf 'package inner\ntype Req struct {\n\tX int `json:"x"`\n}\nfunc Run(req Req) (interface{}, error) {\n\treturn main(req.X)\n}\nfunc main(x int) (interface{}, error) {\n\treturn x, nil\n}' > inner/inner.go && \
go build -x . && \
rm -rf /tmp/gobuildwarm
# Copy build caches to final location, then add write permissions for any UID
# chmod a+rw adds read+write WITHOUT removing execute bits (755->777, 644->666)
# Note: uv python install only creates py_runtime, not uv cache - we create uv/go dirs for runtime
RUN mkdir -p /tmp/windmill/cache && \
cp -r /tmp/build_cache/* /tmp/windmill/cache/ && \
chmod -R a+rw /tmp/windmill/cache && \
rm -rf /tmp/build_cache && \
mkdir -p -m 777 /tmp/windmill/cache/uv /tmp/windmill/cache/go
# Runtime cache locations
ENV UV_CACHE_DIR=/tmp/windmill/cache/uv
ENV UV_PYTHON_INSTALL_DIR=/tmp/windmill/cache/py_runtime
ENV GOCACHE=/tmp/windmill/cache/go
RUN mkdir -p /tmp/gobuildwarm && cd /tmp/gobuildwarm && go mod init gobuildwarm && printf "package foo\nimport (\"fmt\")\nfunc main() { fmt.Println(42) }" > warm.go && go mod tidy && go build -x && rm -rf /tmp/gobuildwarm
ENV TZ=Etc/UTC
COPY --from=builder /frontend/build /static_frontend
COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
COPY --from=windmill_duckdb_ffi_internal_builder /windmill-duckdb-ffi-internal/target/release/libwindmill_duckdb_ffi_internal.so ${APP}/libwindmill_duckdb_ffi_internal.so
COPY --from=denoland/deno:2.2.1 --chmod=755 /usr/bin/deno /usr/bin/deno
COPY --from=oven/bun:1.2.23 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.2.4 /usr/local/bin/bun /usr/bin/bun
COPY --from=php:8.3.7-cli /usr/local/bin/php /usr/bin/php
COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer
@@ -244,7 +204,6 @@ COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/
ENV RUSTUP_HOME="/usr/local/rustup"
ENV CARGO_HOME="/usr/local/cargo"
ENV LD_LIBRARY_PATH="."
WORKDIR ${APP}
@@ -252,20 +211,23 @@ RUN ln -s ${APP}/windmill /usr/local/bin/windmill
COPY ./frontend/src/lib/hubPaths.json ${APP}/hubPaths.json
RUN windmill cache ${APP}/hubPaths.json && rm ${APP}/hubPaths.json
RUN windmill cache ${APP}/hubPaths.json && rm ${APP}/hubPaths.json && chmod -R 777 /tmp/windmill
# Create a non-root user 'windmill' with UID and GID 1000
RUN addgroup --gid 1000 windmill && \
adduser --disabled-password --gecos "" --uid 1000 --gid 1000 windmill
# /tmp/.cache may be created by earlier build steps with 755; chmod ensures any UID can write
RUN mkdir -p -m 777 /tmp/windmill/logs /tmp/windmill/search /tmp/.cache && chmod 777 /tmp/.cache
RUN cp -r /root/.cache /home/windmill/.cache
# Make directories world-accessible for any UID
# (cache files already have 666 from umask copy above, cache_nomount is read-only)
RUN find ${APP} /tmp/windmill -type d -exec chmod 777 {} +
RUN mkdir -p /tmp/windmill/logs && \
mkdir -p /tmp/windmill/search
# Make directories world-readable and writable
RUN chmod -R 777 ${APP} && \
chmod -R 777 /tmp/windmill && \
chmod -R 777 /home/windmill/.cache
USER root
EXPOSE 8000

View File

@@ -332,48 +332,45 @@ you to have it being synced automatically everyday.
## Environment Variables
| Environment Variable name | Default | Description | Api Server/Worker/All |
| ----------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| DATABASE_URL | | The Postgres database url. | All |
| WORKER_GROUP | default | The worker group the worker belongs to and get its configuration pulled from | Worker |
| MODE | standalone | The mode if the binary. Possible values: standalone, worker, server, agent | All |
| METRICS_ADDR | None | (ee only) The socket addr at which to expose Prometheus metrics at the /metrics path. Set to "true" to expose it on port 8001 | All |
| JSON_FMT | false | Output the logs in json format instead of logfmt | All |
| BASE_URL | http://localhost:8000 | The base url that is exposed publicly to access your instance. Is overriden by the instance settings if any. | Server |
| ZOMBIE_JOB_TIMEOUT | 30 | The timeout after which a job is considered to be zombie if the worker did not send pings about processing the job (every server check for zombie jobs every 30s) | Server |
| RESTART_ZOMBIE_JOBS | true | If true then a zombie job is restarted (in-place with the same uuid and some logs), if false the zombie job is failed | Server |
| SLEEP_QUEUE | 50 | The number of ms to sleep in between the last check for new jobs in the DB. It is multiplied by NUM_WORKERS such that in average, for one worker instance, there is one pull every SLEEP_QUEUE ms. | Worker |
| KEEP_JOB_DIR | false | Keep the job directory after the job is done. Useful for debugging. | Worker |
| LICENSE_KEY (EE only) | None | License key checked at startup for the Enterprise Edition of Windmill | Worker |
| SLACK_SIGNING_SECRET | None | The signing secret of your Slack app. See [Slack documentation](https://api.slack.com/authentication/verifying-requests-from-slack) | Server |
| COOKIE_DOMAIN | None | The domain of the cookie. If not set, the cookie will be set by the browser based on the full origin | Server |
| DENO_PATH | /usr/bin/deno | The path to the deno binary. | Worker |
| PYTHON_PATH | | The path to the python binary if wanting to not have it managed by uv. | Worker |
| GO_PATH | /usr/bin/go | The path to the go binary. | Worker |
| GOPRIVATE | | The GOPRIVATE env variable to use private go modules | Worker |
| GOPROXY | | The GOPROXY env variable to use | Worker |
| NETRC | | The netrc content to use a private go registry | Worker |
| PY_CONCURRENT_DOWNLOADS | 20 | Sets the maximum number of in-flight concurrent python downloads that windmill will perform at any given time. | Worker |
| PATH | None | The path environment variable, usually inherited | Worker |
| HOME | None | The home directory to use for Go and Bash , usually inherited | Worker |
| DATABASE_CONNECTIONS | 50 (Server)/3 (Worker) | The max number of connections in the database connection pool | All |
| SUPERADMIN_SECRET | None | A token that would let the caller act as a virtual superadmin superadmin@windmill.dev | Server |
| TIMEOUT_WAIT_RESULT | 20 | The number of seconds to wait before timeout on the 'run_wait_result' endpoint | Worker |
| QUEUE_LIMIT_WAIT_RESULT | None | The number of max jobs in the queue before rejecting immediately the request in 'run_wait_result' endpoint. Takes precedence on the query arg. If none is specified, there are no limit. | Worker |
| DENO_AUTH_TOKENS | None | Custom DENO_AUTH_TOKENS to pass to worker to allow the use of private modules | Worker |
| DISABLE_RESPONSE_LOGS | false | Disable response logs | Server |
| CREATE_WORKSPACE_REQUIRE_SUPERADMIN | true | If true, only superadmins can create new workspaces | Server |
| MIN_FREE_DISK_SPACE_MB | 15000 | Minimum amount of free space on worker. Sends critical alert if worker has less free space. | Worker |
| RUN_UPDATE_CA_CERTIFICATE_AT_START | false | If true, runs CA certificate update command at startup before other initialization | All |
| RUN_UPDATE_CA_CERTIFICATE_PATH | /usr/sbin/update-ca-certificates | Path to the CA certificate update command/script to run when RUN_UPDATE_CA_CERTIFICATE_AT_START is true | All |
| Environment Variable name | Default | Description | Api Server/Worker/All |
| ----------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| DATABASE_URL | | The Postgres database url. | All |
| WORKER_GROUP | default | The worker group the worker belongs to and get its configuration pulled from | Worker |
| MODE | standalone | The mode if the binary. Possible values: standalone, worker, server, agent | All |
| METRICS_ADDR | None | (ee only) The socket addr at which to expose Prometheus metrics at the /metrics path. Set to "true" to expose it on port 8001 | All |
| JSON_FMT | false | Output the logs in json format instead of logfmt | All |
| BASE_URL | http://localhost:8000 | The base url that is exposed publicly to access your instance. Is overriden by the instance settings if any. | Server |
| ZOMBIE_JOB_TIMEOUT | 30 | The timeout after which a job is considered to be zombie if the worker did not send pings about processing the job (every server check for zombie jobs every 30s) | Server |
| RESTART_ZOMBIE_JOBS | true | If true then a zombie job is restarted (in-place with the same uuid and some logs), if false the zombie job is failed | Server |
| SLEEP_QUEUE | 50 | The number of ms to sleep in between the last check for new jobs in the DB. It is multiplied by NUM_WORKERS such that in average, for one worker instance, there is one pull every SLEEP_QUEUE ms. | Worker |
| KEEP_JOB_DIR | false | Keep the job directory after the job is done. Useful for debugging. | Worker |
| LICENSE_KEY (EE only) | None | License key checked at startup for the Enterprise Edition of Windmill | Worker |
| SLACK_SIGNING_SECRET | None | The signing secret of your Slack app. See [Slack documentation](https://api.slack.com/authentication/verifying-requests-from-slack) | Server |
| COOKIE_DOMAIN | None | The domain of the cookie. If not set, the cookie will be set by the browser based on the full origin | Server |
| DENO_PATH | /usr/bin/deno | The path to the deno binary. | Worker |
| PYTHON_PATH | | The path to the python binary if wanting to not have it managed by uv. | Worker |
| GO_PATH | /usr/bin/go | The path to the go binary. | Worker |
| GOPRIVATE | | The GOPRIVATE env variable to use private go modules | Worker |
| GOPROXY | | The GOPROXY env variable to use | Worker |
| NETRC | | The netrc content to use a private go registry | Worker |
| PY_CONCURRENT_DOWNLOADS | 20 | Sets the maximum number of in-flight concurrent python downloads that windmill will perform at any given time. | Worker |
| PATH | None | The path environment variable, usually inherited | Worker |
| HOME | None | The home directory to use for Go and Bash , usually inherited | Worker |
| DATABASE_CONNECTIONS | 50 (Server)/3 (Worker) | The max number of connections in the database connection pool | All |
| SUPERADMIN_SECRET | None | A token that would let the caller act as a virtual superadmin superadmin@windmill.dev | Server |
| TIMEOUT_WAIT_RESULT | 20 | The number of seconds to wait before timeout on the 'run_wait_result' endpoint | Worker |
| QUEUE_LIMIT_WAIT_RESULT | None | The number of max jobs in the queue before rejecting immediately the request in 'run_wait_result' endpoint. Takes precedence on the query arg. If none is specified, there are no limit. | Worker |
| DENO_AUTH_TOKENS | None | Custom DENO_AUTH_TOKENS to pass to worker to allow the use of private modules | Worker |
| DISABLE_RESPONSE_LOGS | false | Disable response logs | Server |
| CREATE_WORKSPACE_REQUIRE_SUPERADMIN | true | If true, only superadmins can create new workspaces | Server |
## Run a local dev setup
Using [Nix](./frontend/README_DEV.md#nix) (Recommended).
See the [./frontend/README_DEV.md](./frontend/README_DEV.md) file for all
running options.
Using [Nix](./frontend/README_DEV.md#nix).
### only Frontend
This will use the backend of <https://app.windmill.dev> but your own frontend
@@ -399,27 +396,29 @@ npm run generate-backend-client-mac
See the [./frontend/README_DEV.md](./frontend/README_DEV.md) file for all
running options.
1. Start a local Postgres database using for instance the `start-dev-db.sh` script which will make a database available at `postgres://postgres:changeme@localhost:5432/windmill`
Then run the migrations using the following command:
1. Create a Postgres Database for Windmill and create an admin role inside your
Postgres setup. The easiest way to get a working db is to run
```
cargo install sqlx-cli
env DATABASE_URL=<YOUR_DATABASE_URL> sqlx migrate run
```
This will also avoid compile time issue with sqlx's `query!` macro.
2. (optional, linux only) Install [nsjail](https://github.com/google/nsjail) and have it accessible in
This will also avoid compile time issue with sqlx's `query!` macro
2. Install [nsjail](https://github.com/google/nsjail) and have it accessible in
your PATH
3. Install bun, deno and python3 (+ any languages you want to use), have the bins at `/usr/bin/bun`,`/usr/bin/deno`, and
`/usr/local/bin/python3` or set the corresponding environment variables.
4. (optional) Install the [lld linker](https://lld.llvm.org/)
5. Go to `frontend/`:
1. `npm install`, `npm run generate-backend-client` then `REMOTE=http://localhost:8000 npm run dev`
3. Install deno and python3, have the bins at `/usr/bin/deno` and
`/usr/local/bin/python3`
4. Install [caddy](https://caddyserver.com)
5. Install the [lld linker](https://lld.llvm.org/)
6. Go to `frontend/`:
1. `npm install`, `npm run generate-backend-client` then `npm run dev`
2. You might need to set some extra heap space for the node runtime
`export NODE_OPTIONS="--max-old-space-size=4096"`
3. Create an empty `frontend/build` folder using `mkdir frontend/build`
6. Go to `backend/`:
1. `env DATABASE_URL=<YOUR_DATABASE_URL> RUST_LOG=info cargo run`
2. You can specify any feature flag you want to enable, for example `cargo run --features python` to enable the python executor.
7. Et voilà, windmill should be available at `http://localhost:3000`
3. In another shell `npm run build` otherwise the backend will not find the
`frontend/build` folder and will not compile.
4. In another shell `sudo caddy run --config Caddyfile`
7. Go to `backend/`:
`env DATABASE_URL=<DATABASE_URL_TO_YOUR_WINDMILL_DB> RUST_LOG=info cargo run`
8. Et voilà, windmill should be available at `http://localhost/`
## Contributors

View File

@@ -5,15 +5,10 @@ incremental = true
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
"-C", "link-args=-Wl,-rpath,$ORIGIN/"
]
[target.aarch64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
"-C", "link-args=-Wl,-rpath,$ORIGIN/"
]
[net]
git-fetch-with-cli = true
]

7
backend/.gitignore vendored
View File

@@ -5,9 +5,4 @@ oauth2.json
tracing.folded
heaptrack*
index/
windmill-api/openapi-*.*
.duckdb/*
*ee.rs
generate_mcp_endpoints_tools/venv
bacon.toml
libwindmill_duckdb_ffi_internal.so
windmill-api/openapi-*.*

View File

@@ -1 +0,0 @@
!*ee.rs

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT created_by FROM v2_job WHERE id = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "created_by",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false
]
},
"hash": "002d68d7c4437522a6dae95af007a356217bbae06b8453f0c32046f0cbf20dcb"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT args as \"args: sqlx::types::Json<HashMap<String, Box<RawValue>>>\" FROM v2_job WHERE id = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "args: sqlx::types::Json<HashMap<String, Box<RawValue>>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
true
]
},
"hash": "0084c1246d1391d106da2e67a394eafc6695257632406ed9a2111dba1dd106c7"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO dependency_map (workspace_id, importer_path, importer_kind, imported_path, importer_node_id)\n SELECT $1, importer_path, importer_kind, imported_path, importer_node_id\n FROM dependency_map\n WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "00b9f392a5cc07bd4ed14e3b69f96408e219d70015dd2f419fc87a440f070c64"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT f.path\n FROM workspace_runnable_dependencies wru \n JOIN flow f\n ON wru.flow_path = f.path AND wru.workspace_id = f.workspace_id\n WHERE wru.runnable_path = $1 AND wru.runnable_is_flow = $2 AND wru.workspace_id = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Bool",
"Text"
]
},
"nullable": [
false
]
},
"hash": "00c0ae12b19ba495f307f0ce6b4833947c5b3fe45826fc5468e326d171d95236"
}

View File

@@ -1,58 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n workspace.id AS \"id!\",\n workspace.name AS \"name!\",\n workspace.owner AS \"owner!\",\n workspace.deleted AS \"deleted!\",\n workspace.premium AS \"premium!\",\n workspace_settings.color AS \"color\",\n workspace.parent_workspace_id AS \"parent_workspace_id\"\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n WHERE workspace.id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id!",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name!",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "owner!",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "deleted!",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "premium!",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "parent_workspace_id",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
true,
true
]
},
"hash": "00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT data FROM app_bundles WHERE app_version_id = $1 AND file_type = $2 AND w_id = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "data",
"type_info": "Bytea"
}
],
"parameters": {
"Left": [
"Int8",
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "01050e7057f3d1971ad9e47ac83bf6a3c3c9f41689c3607f0b264437ae6b3324"
}

View File

@@ -0,0 +1,50 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n path,\n is_flow,\n workspace_id,\n owner,\n email,\n trigger_config as \"trigger_config!: _\"\n FROM\n capture_config\n WHERE\n trigger_kind = 'postgres' AND\n last_client_ping > NOW() - INTERVAL '10 seconds' AND\n trigger_config IS NOT NULL AND\n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "trigger_config!: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false,
false,
false,
true
]
},
"hash": "011c7638eeeda710deb86a216a9e10df9c3e9458e85bcdde466b01011a1f2ac2"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT j.id\n FROM v2_job_queue q JOIN v2_job j USING (id) LEFT JOIN v2_job_runtime r USING (id) LEFT JOIN v2_job_status s USING (id)\n WHERE r.ping < now() - ($1 || ' seconds')::interval\n AND q.running = true AND j.kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlestepflow') AND j.same_worker = false",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "0186c1058f147e012b8120c342caf8688a6d1643747be3ec4f784c3029a59e52"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value FROM variable WHERE path = $1 AND workspace_id = $2 AND is_secret = true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "020c031c3de6c85577e30421ada9d39a5a47ca1b6cf3dbfd6988aa0694d7364c"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM v2_job WHERE workspace_id = $1 AND id = ANY($2)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"UuidArray"
]
},
"nullable": []
},
"hash": "023555d33652d40fa381b1baaae6b319c4bac92cb2d90bb4ffd08e25f4a4d18b"
}

View File

@@ -1,77 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n v2_job.permissioned_as_email,\n v2_job.created_by,\n v2_job.parent_job,\n v2_job.permissioned_as,\n v2_job.runnable_path,\n CASE WHEN v2_job.trigger_kind = 'schedule'::job_trigger_kind THEN v2_job.trigger END AS schedule_path,\n v2_job.flow_step_id,\n v2_job.flow_innermost_root_job,\n v2_job.root_job,\n v2_job_queue.scheduled_for AS \"scheduled_for: chrono::DateTime<chrono::Utc>\"\n FROM v2_job INNER JOIN v2_job_queue ON v2_job.id = v2_job_queue.id\n WHERE v2_job.id = $1 AND v2_job.workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "permissioned_as_email",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "parent_job",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "permissioned_as",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "runnable_path",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "schedule_path",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "flow_step_id",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "flow_innermost_root_job",
"type_info": "Uuid"
},
{
"ordinal": 8,
"name": "root_job",
"type_info": "Uuid"
},
{
"ordinal": 9,
"name": "scheduled_for: chrono::DateTime<chrono::Utc>",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
false,
true,
false,
true,
null,
true,
true,
true,
false
]
},
"hash": "02c945b5f18a56a826721f6884846d79167747742de236ce57f395561685adc0"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT jsonb_object_keys(ws.ducklake->'ducklakes') AS ducklake_name\n FROM workspace_settings ws\n WHERE ws.workspace_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "ducklake_name",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "02ecdcc882931d5cbb2243e32805c8a1291a5106fff46ceba85fa27d50a0354c"
}

View File

@@ -0,0 +1,26 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET last_server_ping = now(), error = $1 WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'websocket' AND server_id = $5 AND last_client_ping > NOW() - INTERVAL '10 seconds' RETURNING 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool",
"Text"
]
},
"nullable": [
null
]
},
"hash": "031d0d70b0aff52feaad487bddb74e5ef0aaa2505facbea8c764003dfc8fffb1"
}

View File

@@ -1,19 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_diff SET has_changes = true, exists_in_source = $5, exists_in_fork = $6\n WHERE path = $3 AND kind = $4 AND (\n (source_workspace_id = $1 AND fork_workspace_id = $2)\n OR (source_workspace_id = $2 AND fork_workspace_id =$1)\n )",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Text",
"Bool",
"Bool"
]
},
"nullable": []
},
"hash": "034a8519198daf30e0eb8a74ed92f896c83bb39e1cb52fe3c29c1a224c3859c2"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE schedule SET enabled = false WHERE workspace_id = $1 AND enabled = true RETURNING path",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "03669873e4e3b22c737d5170821f677925474aad885bf1c0780bdb978225517e"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO tutorial_progress (email, progress, skipped_all) VALUES ($2, $1::bigint::bit(64), $3) ON CONFLICT (email) DO UPDATE SET progress = EXCLUDED.progress, skipped_all = EXCLUDED.skipped_all",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Varchar",
"Bool"
]
},
"nullable": []
},
"hash": "04362a55081f7a98bca8fe4db0669939da8944711037957664cc2989b239c9d1"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM v2_job",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "04ce5c530c80ae6f911dfe0dc9ed7d1a2e10342bbbc7f8486df0b73f5657a493"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) as count FROM variable WHERE is_secret = true AND value != 'CLEARED'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "052d42b46d5faba6b41f1fdcbf6a012db51b9e5a255ec0da9a8a0999d668d336"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO concurrency_counter(concurrency_id, job_uuids)\n VALUES ($1, '{}'::jsonb)",
"query": "INSERT INTO concurrency_counter(concurrency_id, job_uuids) \n VALUES ($1, '{}'::jsonb)",
"describe": {
"columns": [],
"parameters": {
@@ -10,5 +10,5 @@
},
"nullable": []
},
"hash": "a5313b8d1d29c13a5b23cd8b6f9bd4c3d96c53dd0d8702facfefaaf35b7d6b26"
"hash": "05cb171b610bfb45f6228128a385cde8a5b86d7ca377a028004cc382e12faf41"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status\n SET flow_status = JSONB_SET(flow_status, ARRAY['retry'], $1)\n WHERE id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb",
"Uuid"
]
},
"nullable": []
},
"hash": "06731936fb073169b3a1a8a9817f1e669b60edccd260625a95094b7244f5fb83"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status\n SET flow_status = flow_status - 'retry'\n WHERE id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "06db0e720dd59a7c52c0a98ea7b316237eb1a547678858c1a1e45985035b3468"
}

View File

@@ -0,0 +1,26 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n gcp_trigger \n SET \n enabled = $1, \n email = $2, \n edited_by = $3, \n edited_at = now(), \n server_id = NULL, \n error = NULL\n WHERE \n path = $4 AND \n workspace_id = $5 \n RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Bool",
"Varchar",
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (\n workspace_id, path, summary, description,\n dependency_job, lock_error_logs, draft_only, tag,\n dedicated_worker, visible_to_runner_only, on_behalf_of_email,\n value, schema, edited_by, edited_at\n ) VALUES (\n $1, $2, $3, $4,\n NULL, '', $5, $6,\n $7, $8, $9,\n $10, $11::text::json, $12, now()\n )",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Text",
"Text",
"Bool",
"Varchar",
"Bool",
"Bool",
"Text",
"Jsonb",
"Text",
"Varchar"
]
},
"nullable": []
},
"hash": "081dc94a7d0fdaade77cfb593a025d8c48d7eab3dbb30ca0b43fb1ef45d8d8bd"
}

View File

@@ -1,19 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status SET flow_status = \n CASE WHEN flow_status->'modules'->$1::int->'flow_jobs_duration' IS NOT NULL THEN\n JSONB_SET(JSONB_SET(JSONB_SET(\n flow_status,\n ARRAY['modules', $1::TEXT, 'flow_jobs_success', $3::TEXT],\n $4\n ),\n ARRAY['modules', $1::TEXT, 'flow_jobs_duration', 'duration_ms', $3::TEXT], $5),\n ARRAY['modules', $1::TEXT, 'flow_jobs_duration', 'started_at', $3::TEXT], $6)\n ELSE\n JSONB_SET(flow_status, ARRAY['modules', $1::TEXT, 'flow_jobs_success', $3::TEXT], $4)\n END\n WHERE id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int4",
"Uuid",
"Text",
"Jsonb",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "081f838b3dbe81631d17e7ca0751db725a7f92d4e43a86bcfa06a4ac7c70ac8f"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM flow_conversation WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "08574e8e5dc165041750880fb02e7ffea83ae94a670b598b6dada0b3d0914629"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT success_handler_extra_args FROM workspace_settings WHERE workspace_id = 'test-workspace'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success_handler_extra_args",
"type_info": "Json"
}
],
"parameters": {
"Left": []
},
"nullable": [
true
]
},
"hash": "085bbcfcebc9e56984295046c48722f3510548eaf525c499ad0e24cdf8332b22"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1) as \"exists!\"",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9"
}

View File

@@ -1,45 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM v2_job\n WHERE workspace_id = $1\n AND (kind = 'unassigned_script'::JOB_KIND OR kind = 'unassigned_flow'::JOB_KIND OR kind = 'unassigned_singlestepflow'::JOB_KIND)\n AND trigger_kind = $2\n AND trigger = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
{
"Custom": {
"name": "job_trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats",
"schedule",
"app",
"ui",
"postgres",
"sqs",
"gcp",
"mqtt"
]
}
}
},
"Text"
]
},
"nullable": [
false
]
},
"hash": "089d7bc7acdbb97cf477159e111bc7e9ee85289ff5c52af43166928337c257e7"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth, expires_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = EXCLUDED.value, expires_at = EXCLUDED.expires_at",
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth, expires_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3, expires_at = $7",
"describe": {
"columns": [],
"parameters": {
@@ -16,5 +16,5 @@
},
"nullable": []
},
"hash": "5701ee0b862dbdb44990702af270a2eb517e82943bb8c078c7bb2e60def3cbf1"
"hash": "08dd2ea6b17a52bce352d6443d7d009cfc9da0d3b2bd1f40d422b550779e5324"
}

View File

@@ -142,51 +142,6 @@
"ordinal": 27,
"name": "git_app_installations",
"type_info": "Jsonb"
},
{
"ordinal": 28,
"name": "ducklake",
"type_info": "Jsonb"
},
{
"ordinal": 29,
"name": "auto_add_instance_groups",
"type_info": "TextArray"
},
{
"ordinal": 30,
"name": "auto_add_instance_groups_roles",
"type_info": "Jsonb"
},
{
"ordinal": 31,
"name": "slack_oauth_client_id",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "slack_oauth_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 33,
"name": "datatable",
"type_info": "Jsonb"
},
{
"ordinal": 34,
"name": "teams_team_guid",
"type_info": "Text"
},
{
"ordinal": 35,
"name": "success_handler",
"type_info": "Text"
},
{
"ordinal": 36,
"name": "success_handler_extra_args",
"type_info": "Json"
}
],
"parameters": {
@@ -222,16 +177,7 @@
true,
true,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true
false
]
},
"hash": "08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7"

View File

@@ -1,18 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app_version (app_id, value, created_by, created_at, raw_app)\n VALUES ($1, $2, $3, $4, $5)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Json",
"Varchar",
"Timestamptz",
"Bool"
]
},
"nullable": []
},
"hash": "0924c79aca648e5ec3fcc5e91ca71d524fe9d4b46c2e8ed36ae99b5810a896ab"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET datatable = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb",
"Text"
]
},
"nullable": []
},
"hash": "0a3ee1329fb4f705c0006480d03f299ef549e11a017016924c62c1cab179412c"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at) \n SELECT workspace_id, REGEXP_REPLACE(path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1'), summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at\n FROM flow \n WHERE path LIKE ('u/' || $2 || '/%') AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "0a56301b5aaf57339cb2904c8f617366b74e891034d32f2867ccb019da869fc8"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT], $2)\n WHERE id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Uuid"
]
},
"nullable": []
},
"hash": "0aaec91ab06753e46c595d82469924a98f28b0dead245df7248a9ccb8a5f20c3"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT usage FROM usage\n WHERE id = $1\n AND is_workspace = FALSE\n AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "usage",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "0b43d1f0c0d205d978cdb41d30835a6a41a13f39159e106834c62f3b46c44227"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value->>'user_pwd' FROM global_settings WHERE name = 'custom_instance_pg_databases';",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
null
]
},
"hash": "0b5103497ab09affbdf3793d7d7857807d20645561c178d822ecad779c4f7bf4"
}

View File

@@ -1,59 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path, kind, ahead, behind, has_changes, exists_in_source, exists_in_fork FROM workspace_diff\n WHERE source_workspace_id = $1 AND fork_workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "kind",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "ahead",
"type_info": "Int4"
},
{
"ordinal": 3,
"name": "behind",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "has_changes",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "exists_in_source",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "exists_in_fork",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
false,
false,
false,
true,
true,
true
]
},
"hash": "0b8e5fe95f4a2855678ca041b50405b698a368626da42dd9f4ce9d0681d016a1"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT name FROM folder WHERE workspace_id = $1 ORDER BY name asc LIMIT $2 OFFSET $3",
"query": "SELECT name FROM folder WHERE workspace_id = $1 ORDER BY name desc LIMIT $2 OFFSET $3",
"describe": {
"columns": [
{
@@ -20,5 +20,5 @@
false
]
},
"hash": "c77fc86e0fa5d483889b0c4201f6d89b454523b31847798bedcc6c460f9ff7ea"
"hash": "0bfd22be1d6966c61c9a5fedc2522be8a17f06391b882337c74c1817c99b533d"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT jsonb_build_object(\n 'kind', jb.kind,\n 'script_path', jb.runnable_path,\n 'latest_schema', COALESCE(\n (SELECT DISTINCT ON (s.path) s.schema FROM script s WHERE s.workspace_id = $1 AND s.path = jb.runnable_path AND jb.kind = 'script' ORDER BY s.path, s.created_at DESC),\n (SELECT flow_version.schema FROM flow LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] WHERE flow.workspace_id = $1 AND flow.path = jb.runnable_path AND jb.kind = 'flow')\n ),\n 'schemas', ARRAY(\n SELECT jsonb_build_object(\n 'script_hash', LPAD(TO_HEX(COALESCE(s.hash, f.id)), 16, '0'),\n 'job_ids', ARRAY_AGG(DISTINCT j.id),\n 'schema', (ARRAY_AGG(COALESCE(s.schema, f.schema)))[1]\n ) FROM v2_job j\n LEFT JOIN script s ON s.hash = j.runnable_id AND j.kind = 'script'\n LEFT JOIN flow_version f ON f.id = j.runnable_id AND j.kind = 'flow'\n WHERE j.id = ANY(ARRAY_AGG(jb.id))\n GROUP BY COALESCE(s.hash, f.id)\n )\n ) FROM v2_job jb\n WHERE (jb.kind = 'flow' OR jb.kind = 'script')\n AND jb.workspace_id = $1 AND jb.id = ANY($2)\n GROUP BY jb.kind, jb.runnable_path",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "jsonb_build_object",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"UuidArray"
]
},
"nullable": [
null
]
},
"hash": "0c89ef278782f5a72b0b07ab3ba0edc487f03edd61936fcf77dee93fb22839ea"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path FROM variable WHERE path = ANY($1) AND workspace_id = $2 AND is_secret = true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"TextArray",
"Text"
]
},
"nullable": [
false
]
},
"hash": "0c8a3eb810c96230ba3a5466c55bf24a94eb8a52ceb82cc29dade173ad87569d"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT coalesce(COUNT(*) FILTER(WHERE q.suspend = 0 AND q.running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE q.suspend > 0), 0) as \"suspended!\" FROM v2_job_queue q JOIN v2_job j USING (id) WHERE (j.workspace_id = $1 OR $2) AND q.scheduled_for <= now() AND ($3::text[] IS NULL OR j.tag = ANY($3))",
"query": "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND ($3::text[] IS NULL OR tag = ANY($3))",
"describe": {
"columns": [
{
@@ -26,5 +26,5 @@
null
]
},
"hash": "57bd445bfdc667089f847acb9dc484028ce8a077308979a5ba8ef252e19aa825"
"hash": "0cb0e912bc942af2b1ef784455f3f073a79e300f3dd48f14122d1782eee663cd"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "VACUUM (SKIP_LOCKED) v2_job_queue, v2_job_runtime, v2_job_status, job_perms",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "0cc221cb8b3059b21e6b3b4c874b8f4d32815edd2090ccb5d562a89142a7dd9c"
}

View File

@@ -0,0 +1,25 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE v2_job_status f SET flow_status = JSONB_SET(flow_status, ARRAY['user_states'], JSONB_SET(COALESCE(flow_status->'user_states', '{}'::jsonb), ARRAY[$1], $2))\n FROM v2_job j\n WHERE f.id = $3 AND f.id = j.id AND j.workspace_id = $4 AND kind IN ('flow', 'flowpreview', 'flownode') RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Uuid",
"Text"
]
},
"nullable": [
null
]
},
"hash": "0d86a31d7d53e52d24df76fa745d968cda48e036139cdaecf4e87d948f8c365e"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COALESCE(root_job, flow_innermost_root_job, parent_job, id) as \"root_job!\" FROM v2_job WHERE id = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "root_job!",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
null
]
},
"hash": "0e14ab95a08572f0672db266187335f578c622eb335cfc7cd0969633d85c9f73"
}

View File

@@ -1,17 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO deployment_metadata (workspace_id, path, flow_version, job_id)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL\n DO UPDATE SET job_id = EXCLUDED.job_id",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Int8",
"Uuid"
]
},
"nullable": []
},
"hash": "0e621bba5913482b8235d7d8442b8f0e9012c265e150afd4aa41972bf7334ba2"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE mqtt_trigger SET workspace_id = $1 WHERE workspace_id = $2",
"query": "UPDATE v2_job_queue SET workspace_id = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
@@ -11,5 +11,5 @@
},
"nullable": []
},
"hash": "35c7c7dd9c9887307dfa4288ef391ae9068080afa2de9b234332e91e16748060"
"hash": "0ea5ba568ec0f62b808fe938a41174646b6bdd658b8461db1bb90a871d076718"
}

View File

@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE nats_trigger \n SET \n nats_resource_path = $1,\n subjects = $2,\n stream_name = $3,\n consumer_name = $4,\n use_jetstream = $5,\n script_path = $6,\n path = $7,\n is_flow = $8,\n edited_by = $9,\n email = $10,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $13,\n error_handler_args = $14,\n retry = $15\n WHERE \n workspace_id = $11 AND path = $12\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"VarcharArray",
"Varchar",
"Varchar",
"Bool",
"Varchar",
"Varchar",
"Bool",
"Varchar",
"Varchar",
"Text",
"Text",
"Varchar",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "0ef1e5bbbefc117a4cdaf414b3652354641c2f735d071540f858bc064f2432cd"
}

Some files were not shown because too many files have changed in this diff Show More