-
Notifications
You must be signed in to change notification settings - Fork 50.9k
feat(editor): Resolve $parameter[...] in UI-only context & add Docker build workflow
#18182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
avri-schneider
wants to merge
3
commits into
n8n-io:master
from
avri-schneider:feat/editor-resolve-parameter-ui-only
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@n8n/editor-ui': minor | ||
| --- | ||
|
|
||
| Resolve `$parameter[...]` expressions in the Node Details View when no execution data is available. Falls back to `activeNode.parameters` so values can be previewed without running a workflow. Includes unit tests. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,258 @@ | ||
| name: "Test & (optionally) Build Docker Image" | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [ master ] | ||
| types: [opened, synchronize, reopened, closed] | ||
| workflow_dispatch: | ||
| inputs: | ||
| build_type: | ||
| description: 'Type of build' | ||
| required: true | ||
| default: 'test' | ||
| type: choice | ||
| options: [ test, full ] | ||
| schedule: | ||
| - cron: "0 3 * * 0" # Weekly at 03:00 UTC | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: delete | ||
|
|
||
| jobs: | ||
| test: | ||
| if: github.event.action != 'closed' | ||
| name: Lint, Typecheck & Unit Tests | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 60 | ||
| env: | ||
| CI: true | ||
| PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # actions/[email protected] | ||
|
|
||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # pnpm/action-setup@v4 | ||
| with: | ||
| version: 10.12.1 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # actions/[email protected] | ||
| with: | ||
| node-version: '22.x' | ||
| cache: pnpm | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Lint | ||
| run: pnpm -w lint | ||
|
|
||
| - name: Typecheck | ||
| run: pnpm -w typecheck | ||
|
|
||
| - name: Show workspace packages | ||
| run: pnpm -w list --depth -1 | ||
|
|
||
| - name: Run editor-ui unit tests | ||
| run: pnpm -w test --filter n8n-editor-ui -- --run --reporter=dot | ||
|
|
||
| build-image: | ||
| name: Build & Push Docker Image | ||
| runs-on: ubuntu-latest | ||
| needs: test | ||
| if: > | ||
| (github.event_name != 'pull_request' || github.event.action != 'closed') && | ||
| (github.event_name == 'pull_request' || github.event.inputs.build_type == 'full') | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # actions/[email protected] | ||
|
|
||
| - name: Set up pnpm | ||
| uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # pnpm/action-setup@v4 | ||
| with: | ||
| version: 10.12.1 | ||
|
|
||
| - name: Set up Node.js | ||
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # actions/[email protected] | ||
| with: | ||
| node-version: '22.x' | ||
| cache: pnpm | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Build n8n | ||
| run: pnpm build:n8n | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # docker/[email protected] | ||
|
|
||
| - name: Log in to GitHub Container Registry | ||
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # docker/[email protected] | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Extract metadata (unique tags incl. PR/branch) | ||
| id: meta | ||
| uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # docker/[email protected] | ||
| with: | ||
| images: ghcr.io/${{ github.repository_owner }}/n8n | ||
| tags: | | ||
| type=raw,value=test-build | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
| type=ref,event=pr,prefix=pr- | ||
| type=ref,event=branch | ||
| type=sha,format=short,prefix={{branch}}- | ||
|
|
||
| - name: Compute primary test tag | ||
| id: picktag | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "pull_request" ]; then | ||
| echo "tag=pr-${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "tag=test-build" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - name: Build and push Docker image | ||
| uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # docker/[email protected] | ||
| with: | ||
| context: . | ||
| file: ./docker/images/n8n/Dockerfile | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| push: true | ||
| load: false | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
| provenance: false | ||
|
|
||
| - name: Smoke-test container (strict health check + logs) | ||
| shell: bash | ||
| run: | | ||
| set -Eeuo pipefail | ||
|
|
||
| IMAGE="ghcr.io/${{ github.repository_owner }}/n8n:${{ steps.picktag.outputs.tag }}" | ||
| CNAME="n8n-test-${GITHUB_RUN_ID}" | ||
|
|
||
| echo "::group::Pull image" | ||
| docker pull "$IMAGE" | ||
| echo "::endgroup::" | ||
|
|
||
| echo "::group::Sanity: version/help" | ||
| docker run --rm "$IMAGE" --version | ||
| docker run --rm "$IMAGE" --help >/dev/null | ||
| echo "::endgroup::" | ||
|
|
||
| echo "Starting $CNAME..." | ||
| docker run -d --name "$CNAME" -p 5678:5678 "$IMAGE" > /dev/null | ||
|
|
||
| # Always try to clean up; never fail the job because cleanup failed | ||
| cleanup() { docker rm -f "$CNAME" >/dev/null 2>&1 || true; } | ||
| trap cleanup EXIT | ||
|
|
||
| echo "Waiting up to 120s for /healthz..." | ||
| for i in {1..60}; do | ||
| if curl -fsS http://localhost:5678/healthz >/dev/null; then | ||
| echo "✅ Healthy after $((i*2))s" | ||
| break | ||
| fi | ||
| sleep 2 | ||
| done | ||
|
|
||
| # Hard fail if still not healthy; show logs to make it actionable | ||
| if ! curl -fsS http://localhost:5678/healthz >/dev/null; then | ||
| echo "❌ Health check failed. Recent logs:" | ||
| docker logs --tail 200 --timestamps "$CNAME" || true | ||
| echo "Inspect state:" | ||
| docker inspect "$CNAME" || true | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "✅ Container passed health check." | ||
|
|
||
|
|
||
| - name: Show image info and pull instructions | ||
| run: | | ||
| echo "🎉 Docker image successfully built and pushed!" | ||
| echo "" | ||
| echo "📦 Useful tags:" | ||
| echo " - ghcr.io/${{ github.repository_owner }}/n8n:${{ steps.picktag.outputs.tag }}" | ||
| echo " - ghcr.io/${{ github.repository_owner }}/n8n:test-build" | ||
| echo " - ghcr.io/${{ github.repository_owner }}/n8n:latest" | ||
| echo " - ghcr.io/${{ github.repository_owner }}/n8n:master-${{ github.sha }}" | ||
| echo "" | ||
| echo "🚀 Pull & run:" | ||
| echo " docker pull ghcr.io/${{ github.repository_owner }}/n8n:${{ steps.picktag.outputs.tag }}" | ||
| echo " docker run -p 5678:5678 ghcr.io/${{ github.repository_owner }}/n8n:${{ steps.picktag.outputs.tag }}" | ||
|
|
||
| cleanup-pr: | ||
| name: Cleanup PR Image | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'pull_request' && github.event.action == 'closed' | ||
| steps: | ||
| - name: Delete GHCR image tag for PR | ||
| env: | ||
| GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| TAG="pr-${{ github.event.pull_request.number }}" | ||
| IMAGE="${{ github.repository_owner }}/n8n" | ||
| echo "Fetching manifest digest for $IMAGE:$TAG from GHCR..." | ||
| DIGEST=$(curl -sI \ | ||
| -H "Accept: application/vnd.oci.image.manifest.v1+json" \ | ||
| -H "Authorization: Bearer $GHCR_TOKEN" \ | ||
| "https://ghcr.io/v2/${IMAGE}/manifests/${TAG}" \ | ||
| | grep -i 'docker-content-digest:' | awk '{print $2}' | tr -d $'\r') | ||
| if [ -z "$DIGEST" ] || [ "$DIGEST" = "null" ]; then | ||
| echo "❌ Could not find digest for tag $TAG. Tag may not exist." | ||
| exit 0 | ||
| fi | ||
| echo "Found digest: $DIGEST" | ||
| echo "Deleting $IMAGE@$DIGEST..." | ||
| curl -s -X DELETE \ | ||
| -H "Authorization: Bearer $GHCR_TOKEN" \ | ||
| "https://ghcr.io/v2/${IMAGE}/manifests/${DIGEST}" && \ | ||
| echo "✅ Deleted $IMAGE:$TAG successfully." | ||
|
|
||
| cleanup-orphans: | ||
| name: Scheduled Cleanup of Orphaned PR Images | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'schedule' | ||
| steps: | ||
| - name: List and delete orphaned PR tags from GHCR | ||
| env: | ||
| GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| IMAGE="${{ github.repository_owner }}/n8n" | ||
| echo "Fetching tags for $IMAGE..." | ||
| TAGS=$(curl -s \ | ||
| -H "Authorization: Bearer $GHCR_TOKEN" \ | ||
| "https://ghcr.io/v2/${IMAGE}/tags/list" | jq -r '.tags[]' | grep '^pr-' || true) | ||
| if [ -z "$TAGS" ]; then | ||
| echo "No orphaned pr-* tags found." | ||
| exit 0 | ||
| fi | ||
| echo "Found tags:" | ||
| echo "$TAGS" | ||
| for TAG in $TAGS; do | ||
| echo "Fetching digest for $TAG..." | ||
| DIGEST=$(curl -sI \ | ||
| -H "Accept: application/vnd.oci.image.manifest.v1+json" \ | ||
| -H "Authorization: Bearer $GHCR_TOKEN" \ | ||
| "https://ghcr.io/v2/${IMAGE}/manifests/${TAG}" \ | ||
| | grep -i 'docker-content-digest:' | awk '{print $2}' | tr -d $'\r') | ||
| if [ -n "$DIGEST" ] && [ "$DIGEST" != "null" ]; then | ||
| echo "Deleting $IMAGE@$DIGEST..." | ||
| curl -s -X DELETE \ | ||
| -H "Authorization: Bearer $GHCR_TOKEN" \ | ||
| "https://ghcr.io/v2/${IMAGE}/manifests/${DIGEST}" && \ | ||
| echo "✅ Deleted $IMAGE:$TAG" | ||
| else | ||
| echo "Skipping $TAG — digest not found." | ||
| fi | ||
| done | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.