Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9f10f0f
fix(migrate-auth-secret): exit cleanly when there are no 2FA records
ngenohkevin May 12, 2026
a714e0f
Merge pull request #4394 from ngenohkevin/fix/migrate-auth-secret-exi…
Siumauricio May 12, 2026
754774e
feat(compose): add import from base64 in create service dropdown
Siumauricio May 12, 2026
63e33a2
[autofix.ci] apply automated fixes
autofix-ci[bot] May 12, 2026
7a568aa
Merge pull request #4395 from Dokploy/feat/import-compose-from-base64
Siumauricio May 12, 2026
f8fcf68
Enhance version synchronization workflow to include SDK repository
Siumauricio May 12, 2026
558d809
feat(deployment): add readLogs procedure to fetch deployment logs
Siumauricio May 13, 2026
aff200f
feat(deployment): add server access validation for deployment actions
Siumauricio May 13, 2026
67278d8
feat(organization): prevent inviting users with owner role
Siumauricio May 13, 2026
1fdbe87
feat(user): implement session cleanup on user update
Siumauricio May 13, 2026
a50f958
feat(settings): add copy button to server IP in web server settings (…
Siumauricio May 13, 2026
8d88a34
fix: copy Dokploy server IP when clicking server badge (#4390)
vadamk May 13, 2026
ef0cf9b
fix: responsive layout (#4391)
nhridoy May 13, 2026
6e342ee
fix: automatically converting username to lowercase both in creation …
Baker May 13, 2026
4da75ea
feat: support external Redis configuration
satoukouga May 21, 2026
a6e8530
feat: add external Redis configuration and refactor related imports
satoukouga May 21, 2026
74dcfd9
feat: refactor Redis imports
satoukouga May 21, 2026
9b91b6c
feat: update Redis command and args structure for consistency across …
satoukouga May 21, 2026
7d958fd
feat: refactor Redis connection and initialization for external confi…
satoukouga May 22, 2026
fade860
feat: update redis-constants for improved configuration handling
satoukouga May 22, 2026
d85bc9c
feat: add support for external Redis configuration in initialization
satoukouga May 22, 2026
8afc45c
feat: improve Redis configuration handling and enhance error checking…
satoukouga May 25, 2026
d096823
feat: streamline Redis configuration and enhance error handling in setup
satoukouga May 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/dokploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ jobs:
needs: [combine-manifests]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -160,3 +162,80 @@ jobs:
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

sync-version:
needs: [generate-release]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Sync version to MCP repository
run: |
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/mcp.git /tmp/mcp-repo
cd /tmp/mcp-repo
jq --arg v "${{ needs.generate-release.outputs.version }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
npm install -g pnpm
pnpm install
pnpm run fetch-openapi
pnpm run generate
git config user.name "Dokploy Bot"
git config user.email "bot@dokploy.com"
git add -A
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.version }}" \
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
--allow-empty
git push
echo "✅ MCP repo synced to version ${{ needs.generate-release.outputs.version }}"
- name: Sync version to CLI repository
run: |
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/cli.git /tmp/cli-repo
cd /tmp/cli-repo
jq --arg v "${{ needs.generate-release.outputs.version }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
cp ${{ github.workspace }}/openapi.json ./openapi.json
npm install -g pnpm
pnpm install
pnpm run generate
git config user.name "Dokploy Bot"
git config user.email "bot@dokploy.com"
git add -A
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.version }}" \
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
--allow-empty
git push
echo "✅ CLI repo synced to version ${{ needs.generate-release.outputs.version }}"
- name: Sync version to SDK repository
run: |
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/sdk.git /tmp/sdk-repo
cd /tmp/sdk-repo
jq --arg v "${{ needs.generate-release.outputs.version }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
cp ${{ github.workspace }}/openapi.json ./openapi.json
npm install -g pnpm
pnpm install
pnpm run generate
git config user.name "Dokploy Bot"
git config user.email "bot@dokploy.com"
git add -A
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.version }}" \
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
--allow-empty
git push
echo "✅ SDK repo synced to version ${{ needs.generate-release.outputs.version }}"
83 changes: 0 additions & 83 deletions .github/workflows/sync-version.yml

This file was deleted.

113 changes: 113 additions & 0 deletions apps/dokploy/__test__/queues/redis-connection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import fs from "node:fs";

// Mock fs for readSecret tests
vi.mock("node:fs");

// Mock dockerode to verify service settings
const mockCreateService = vi.fn().mockResolvedValue({});
const mockGetService = vi.fn().mockReturnValue({
inspect: vi.fn().mockRejectedValue(new Error("Not found")),
update: vi.fn().mockResolvedValue({}),
});

vi.mock("dockerode", () => {
return {
default: vi.fn().mockImplementation(function() {
return {
createService: mockCreateService,
getService: mockGetService,
pull: vi.fn().mockResolvedValue({}),
};
}),
};
});

describe("redis-connection", () => {
afterEach(() => {
vi.resetModules();
vi.unstubAllEnvs();
vi.clearAllMocks();
});

it("should use REDIS_URL if provided", async () => {
vi.stubEnv("REDIS_URL", "redis://user:pass@remote-host:6379/1");

const { redisConfig } = await import("../../server/queues/redis-connection");

expect(redisConfig).toEqual({
url: "redis://user:pass@remote-host:6379/1",
});
}, 30000);

it("should use individual env vars if REDIS_URL is not provided", async () => {
vi.stubEnv("REDIS_HOST", "custom-host");
vi.stubEnv("REDIS_PORT", "1234");
vi.stubEnv("REDIS_DB_INDEX", "2");
vi.stubEnv("REDIS_PASSWORD", "secret");
vi.stubEnv("REDIS_USERNAME", "admin");

const { redisConfig } = await import("../../server/queues/redis-connection");

expect(redisConfig).toEqual({
host: "custom-host",
port: 1234,
db: 2,
password: "secret",
username: "admin",
});
});

it("should read password from REDIS_PASSWORD_FILE if provided", async () => {
vi.stubEnv("REDIS_PASSWORD_FILE", "/tmp/password.txt");
vi.mocked(fs.readFileSync).mockReturnValue("file-secret\n");

const { redisConfig } = await import("../../server/queues/redis-connection");

expect(redisConfig.password).toBe("file-secret");
expect(fs.readFileSync).toHaveBeenCalledWith("/tmp/password.txt", "utf8");
});

it("should fallback to defaults in development", async () => {
vi.stubEnv("NODE_ENV", "development");

const { redisConfig } = await import("../../server/queues/redis-connection");

expect(redisConfig).toEqual({
host: "127.0.0.1",
port: 6379,
db: 0,
});
});

it("should fallback to production defaults", async () => {
vi.stubEnv("NODE_ENV", "production");

const { redisConfig } = await import("../../server/queues/redis-connection");

expect(redisConfig).toEqual({
host: "dokploy-redis",
port: 6379,
db: 0,
});
});

it("should verify initializeRedis creates service with correct Command and Args when password is set", async () => {
vi.stubEnv("REDIS_PASSWORD", "test-pass");
vi.stubEnv("NODE_ENV", "production");

// We need to import initializeRedis AFTER stubbing the env
const { initializeRedis } = await import("@dokploy/server/setup/redis-setup");

await initializeRedis();

Comment thread
satoukouga marked this conversation as resolved.
Outdated
expect(mockCreateService).toHaveBeenCalledWith(expect.objectContaining({
TaskTemplate: expect.objectContaining({
ContainerSpec: expect.objectContaining({
Command: ["redis-server"],
Args: ["--requirepass", "test-pass"],
})
})
}));
}, 30000);
});
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function AnalyzeLogs({ logs, context }: Props) {
disabled={logs.length === 0}
title="Analyze logs with AI"
>
<Bot className="mr-2 h-4 w-4" />
<Bot className="mr-2 size-4" />
AI
</Button>
</PopoverTrigger>
Expand Down
25 changes: 15 additions & 10 deletions apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,13 @@ export const DockerLogsId: React.FC<Props> = ({
title={isPaused ? "Resume logs" : "Pause logs"}
>
{isPaused ? (
<Play className="mr-2 h-4 w-4" />
<Play className="size-4" />
) : (
<Pause className="mr-2 h-4 w-4" />
<Pause className="size-4" />
)}
{isPaused ? "Resume" : "Pause"}
<span className="hidden lg:ml-2 lg:inline">
{isPaused ? "Resume" : "Pause"}
</span>
</Button>
<Button
variant="outline"
Expand All @@ -362,29 +364,32 @@ export const DockerLogsId: React.FC<Props> = ({
title="Copy logs to clipboard"
>
{copied ? (
<Check className="mr-2 h-4 w-4" />
<Check className="size-4" />
) : (
<Copy className="mr-2 h-4 w-4" />
<Copy className="size-4" />
)}
Copy
<span className="hidden lg:ml-2 lg:inline">
{copied ? "Copied" : "Copy"}
</span>
</Button>
<Button
variant="outline"
size="sm"
className="h-9 sm:w-auto w-full"
onClick={handleDownload}
disabled={filteredLogs.length === 0 || !data?.Name}
title="Download logs as text file"
>
<DownloadIcon className="mr-2 h-4 w-4" />
Download logs
<DownloadIcon className="size-4" />
<span className="hidden lg:ml-2 lg:inline">Download logs</span>
</Button>
<AnalyzeLogs logs={filteredLogs} context="runtime" />
</div>
</div>
{isPaused && (
<AlertBlock type="warning">
<AlertBlock type="warning" className="items-center">
<div className="flex items-center gap-2">
<Pause className="h-4 w-4" />
<Pause className="size-4" />
<span>
Logs paused
{messageBuffer.length > 0 && (
Expand Down
Loading
Loading