Skip to content

Comments

feat(github): add tag pattern filtering for deployments#3726

Open
Alm0stEthical wants to merge 4 commits intoDokploy:canaryfrom
Alm0stEthical:feat/tag-pattern-filtering
Open

feat(github): add tag pattern filtering for deployments#3726
Alm0stEthical wants to merge 4 commits intoDokploy:canaryfrom
Alm0stEthical:feat/tag-pattern-filtering

Conversation

@Alm0stEthical
Copy link
Contributor

@Alm0stEthical Alm0stEthical commented Feb 17, 2026

What is this PR about?

Please describe in a short paragraph what this PR is about.

Checklist

Before submitting this PR, please make sure that:

  • You created a dedicated branch based on the canary branch.
  • You have read the suggestions in the CONTRIBUTING.md file https://github.com/Dokploy/dokploy/blob/canary/CONTRIBUTING.md#pull-request
  • You have tested this PR in your local instance. If you have not tested it yet, please do so before submitting. This helps avoid wasting maintainers' time reviewing code that has not been verified by you.

Issues related (if applicable)

closes #123

Screenshots (if applicable)

Greptile Summary

Added tag pattern filtering for GitHub deployments, allowing users to configure glob patterns to control which tags trigger deployments. When triggerType is set to "tag", users can specify patterns like v*, release-*, or v[0-9].* to filter which tags should trigger deployments. The implementation is backwards compatible - leaving patterns empty deploys on any tag.

  • Added tagPatterns column to both application and compose tables
  • Implemented pattern matching using micromatch library in GitHub webhook handler
  • Created reusable TagPatternsField component with tag selection and custom pattern input
  • Added getGithubTags API endpoint to fetch available tags from GitHub repositories
  • Updated deployment tracking to count only apps that match tag patterns
  • Updated test fixtures to include new tagPatterns field

Confidence Score: 3/5

  • Safe to merge after addressing the authorization logic inconsistency
  • The implementation is well-structured with good backwards compatibility, but contains an authorization logic inconsistency in the new getGithubTags endpoint that differs from existing patterns in the same file. The pattern matching logic appears sound and properly handles errors. The database migration and schema changes are correct.
  • apps/dokploy/server/api/routers/github.ts requires attention for authorization logic consistency

Last reviewed commit: be9d90a

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

AHTOOOXA and others added 4 commits February 6, 2026 10:48
Add ability to filter which tags trigger deployments using glob patterns.
Users can now specify patterns like "v*", "release-*" to selectively deploy.

Changes:
- Add tagPatterns field to application and compose schemas
- Add getGithubTags API endpoint to fetch repository tags
- Implement pattern matching in webhook handler using micromatch
- Add Tag Patterns multi-select UI with creatable input
- Backwards compatible: empty patterns = deploy on any tag

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…d safety improvements

- Extract TagPatternsField into a shared component to fix React hooks anti-pattern
  (useState was being called inside render callback which violates Rules of Hooks)
- Remove ~270 lines of duplicate code between application and compose providers
- Add tagPatterns field to test fixtures (drop.test.ts, traefik.test.ts)
- Add try-catch around micromatch.isMatch() for defensive error handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1) UI: Trim and ignore empty input when adding a tag pattern in TagPatternsField to avoid creating blank patterns.

2) API (pages/api/deploy/github.ts): Introduce deployedAppsCount and deployedComposeCount counters, increment them when scheduling/dispatching deployments, and compute totalApps from these counters. Update the empty-result message to indicate no matching apps or patterns.

3) Server (server/api/routers/github.ts): Fix authorization logic to require both matching organizationId and userId for the GitHub provider; the previous conditional used incorrect boolean logic that could allow unauthorized access.
Copilot AI review requested due to automatic review settings February 17, 2026 00:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds tag-based deployment filtering for GitHub providers by allowing apps/compose services to specify glob patterns that must match a pushed tag before deploying. This extends both backend schema/API and the dashboard UI to configure and fetch tags.

Changes:

  • Add tagPatterns to application and compose schemas + DB migration.
  • Add GitHub tags listing endpoint (getGithubTags) for UI assistance.
  • Apply micromatch filtering in the GitHub webhook tag-deploy path; add UI field for selecting/entering patterns.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/server/src/utils/providers/github.ts Adds getGithubTags helper that paginates repos.listTags.
packages/server/src/db/schema/github.ts Introduces apiFindGithubTags input schema for the tags endpoint.
packages/server/src/db/schema/compose.ts Adds tagPatterns column to compose table schema.
packages/server/src/db/schema/application.ts Adds tagPatterns column to application table schema + includes it in GitHub provider save schema.
apps/dokploy/server/api/routers/github.ts Adds getGithubTags protected TRPC procedure.
apps/dokploy/server/api/routers/application.ts Persists tagPatterns when saving GitHub provider settings.
apps/dokploy/pages/api/deploy/github.ts Filters tag-triggered deployments by tagPatterns using micromatch.
apps/dokploy/package.json Dependency ordering changes (no functional change intended).
apps/dokploy/drizzle/meta/_journal.json Adds migration journal entry for 0139.
apps/dokploy/drizzle/meta/0139_snapshot.json New drizzle snapshot reflecting tagPatterns columns.
apps/dokploy/drizzle/meta/0134_snapshot.json Updates existing historical snapshot (needs correction).
apps/dokploy/drizzle/0139_volatile_doomsday.sql Adds tagPatterns columns via SQL migration.
apps/dokploy/components/dashboard/shared/tag-patterns-field.tsx New UI component to manage tag patterns/tags selection.
apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx Adds tag-patterns field + tag fetching when trigger type is tag.
apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx Adds tag-patterns field + tag fetching when trigger type is tag.
apps/dokploy/test/traefik/traefik.test.ts Updates test fixture to include tagPatterns.
apps/dokploy/test/drop/drop.test.ts Updates test fixture to include tagPatterns.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +60 to +64
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && inputValue.trim()) {
e.preventDefault();
handleSelect(inputValue.trim());
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleKeyDown references React.KeyboardEvent, but this file doesn’t import the React namespace. With the automatic JSX runtime, React isn’t in scope, so this will fail type-checking. Import the needed type from react (e.g., KeyboardEvent) or add a import type React from "react" and use that consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +70 to +84
getGithubTags: protectedProcedure
.input(apiFindGithubTags)
.query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId || "");
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId ||
githubProvider.gitProvider.userId !== ctx.session.userId
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this github provider",
});
}
return await getGithubTags(input);
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

githubId is optional in apiFindGithubTags, but this procedure calls findGithubById(input.githubId || "") before delegating to getGithubTags. If githubId is missing/empty, findGithubById throws NOT_FOUND and the endpoint won’t return the intended empty list behavior. Either make githubId required in the input schema (min(1)) or short-circuit here (e.g., return []) before calling findGithubById.

Copilot uses AI. Check for mistakes.
Comment on lines +1071 to +1077
"tagPatterns": {
"name": "tagPatterns",
"type": "text[]",
"primaryKey": false,
"notNull": false,
"default": "'{}'"
},
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This older snapshot (0134_snapshot.json) is being modified to include the new tagPatterns column. Drizzle snapshots are meant to represent the schema at the time of that migration; updating historical snapshots can break migration history and cause drift/conflicts in future schema diff generation. Revert changes to 0134_snapshot.json that introduce tagPatterns and keep this change isolated to the new 0139 migration/snapshot.

Suggested change
"tagPatterns": {
"name": "tagPatterns",
"type": "text[]",
"primaryKey": false,
"notNull": false,
"default": "'{}'"
},

Copilot uses AI. Check for mistakes.
"primaryKey": false,
"notNull": false,
"default": "'0.15.4'"
"default": "'0.2.2'"
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0134_snapshot.json changes the railpackVersion default to 0.2.2, but the actual schema still defines railpackVersion default as 0.15.4 (see packages/server/src/db/schema/application.ts). This inconsistency will cause schema drift and potentially generate spurious migrations. Update the snapshot to match the schema (or update the schema/migration intentionally, but then it should be part of this PR’s explicit scope).

Suggested change
"default": "'0.2.2'"
"default": "'0.15.4'"

Copilot uses AI. Check for mistakes.
Comment on lines +123 to +146
// Pattern matching with backwards compatibility
if (app.tagPatterns && app.tagPatterns.length > 0) {
try {
const matchesPattern = micromatch.isMatch(tagName, app.tagPatterns);
if (!matchesPattern) {
console.log(
`[GitHub Webhook] Tag "${tagName}" does not match patterns [${app.tagPatterns.join(", ")}] for application "${app.name}", skipping deployment`,
);
continue;
}
console.log(
`[GitHub Webhook] Tag "${tagName}" matches patterns for application "${app.name}", proceeding with deployment`,
);
} catch (error) {
console.error(
`[GitHub Webhook] Invalid tag pattern for application "${app.name}": ${error}. Skipping deployment.`,
);
continue;
}
} else {
console.log(
`[GitHub Webhook] No tag patterns configured for application "${app.name}", deploying on any tag`,
);
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new tag-pattern filtering changes deployment behavior for tag pushes (including the invalid-pattern fallback). There are existing Vitest tests around GitHub deploy webhook parsing helpers, but no coverage for this new match/skip logic. Add unit tests covering: deploy when patterns match, skip when they don’t, and skip safely when an invalid glob is configured.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

17 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +74 to +78
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId ||
githubProvider.gitProvider.userId !== ctx.session.userId
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authorization logic uses || (OR) but getGithubBranches above uses && (AND) on line 58-60

Suggested change
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId ||
githubProvider.gitProvider.userId !== ctx.session.userId
) {
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId &&
githubProvider.gitProvider.userId === ctx.session.userId
) {

Comment on lines +74 to +78
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId ||
githubProvider.gitProvider.userId !== ctx.session.userId
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authorization logic differs from existing endpoints (getGithubBranches, getGithubRepositories, etc.) which use && operator on line 58-60. make consistent with the existing pattern throughout this file, or update all other endpoints to use this new pattern

Suggested change
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId ||
githubProvider.gitProvider.userId !== ctx.session.userId
) {
if (
githubProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId &&
githubProvider.gitProvider.userId === ctx.session.userId
) {
//TODO: Remove this line when the cloud version is ready

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@@ -0,0 +1,2 @@
ALTER TABLE "application" ADD COLUMN "tagPatterns" text[] DEFAULT '{}';--> statement-breakpoint
ALTER TABLE "compose" ADD COLUMN "tagPatterns" text[] DEFAULT '{}'; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing newline at end of file

Suggested change
ALTER TABLE "compose" ADD COLUMN "tagPatterns" text[] DEFAULT '{}';
ALTER TABLE "compose" ADD COLUMN "tagPatterns" text[] DEFAULT '{}';

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants