Skip to content

refactor: config-driven rules engine#9

Merged
T0MASD merged 1 commit intomainfrom
config-driven-rules-engine
Mar 18, 2026
Merged

refactor: config-driven rules engine#9
T0MASD merged 1 commit intomainfrom
config-driven-rules-engine

Conversation

@T0MASD
Copy link
Owner

@T0MASD T0MASD commented Mar 18, 2026

Replaces hardcoded if/else label logic in getLabels() with a declarative RULES array and HANDLERS object pattern.

  • RULES: array of {header, contains/endswith, label, handler, fallback}
  • HANDLERS: named functions receiving (message, baseLabel) for dynamic sublabeling
  • Fallback rules only fire when no other rules matched
  • Added Makefile for containerized testing (node:20-alpine via Podman)
  • 19 new tests (38 total), all passing
  • Lint clean (0 errors)
  • Updated README with config-driven documentation
  • Fixed npm start: node app.js instead of node .

Closes #1

@T0MASD
Copy link
Owner Author

T0MASD commented Mar 18, 2026

@copilot PTLA

Copy link

Copilot AI commented Mar 18, 2026

@T0MASD I've opened a new pull request, #10, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

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

This PR refactors Ukko’s label assignment logic into a config-driven rules engine, and updates local/dev tooling, CI, docs, and tests to match the new approach.

Changes:

  • Introduce RULES + HANDLERS configuration in modules/ukko.js and update getLabels to evaluate rules generically.
  • Expand mocha coverage to validate the config-driven engine behavior and exports.
  • Update local run entrypoint (app.js + npm start), add a Makefile for common tasks, and adjust GitHub Actions workflow to use containerized Node environments.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
modules/ukko.js Adds RULES/HANDLERS config and rewrites label matching to use the rule engine.
test/ukko.test.js Adds tests targeting the config-driven engine and new exports.
app.js Prevents runUkko() from executing when imported (e.g., by tests).
README.md Updates run instructions and documents the new config-driven rules model.
package.json Updates start to run node app.js.
package-lock.json Updates lockfile to v3 format (npm 7+).
Makefile Adds install/test/lint/shell convenience targets (optionally via container engine).
.github/workflows/node.js.yml Switches CI to run in Node containers and invokes Makefile targets.

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

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +19 to +28
node-version: [18-alpine, 20-alpine, 22-alpine]

container:
image: node:${{ matrix.node-version }}

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
- run: npm run lint
- uses: actions/checkout@v4
- run: apk add --no-cache make
- run: make install
- run: make test
Makefile Outdated
Comment on lines +5 to +32
CONTAINER_ENGINE := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null)

.PHONY: shell test lint install clean

install:
ifdef CONTAINER_ENGINE
$(CONTAINER_ENGINE) run --rm -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) $(IMAGE) npm install
else
npm install
endif

test:
ifdef CONTAINER_ENGINE
$(CONTAINER_ENGINE) run --rm -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) $(IMAGE) npx mocha
else
npx mocha
endif

lint:
ifdef CONTAINER_ENGINE
$(CONTAINER_ENGINE) run --rm -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) $(IMAGE) npx eslint .
else
npx eslint .
endif

shell:
ifdef CONTAINER_ENGINE
$(CONTAINER_ENGINE) run --rm -it -v $(PWD):$(WORKDIR):Z -w $(WORKDIR) $(IMAGE) sh
Comment on lines +229 to +237
// This test requires an endswith rule to exist in RULES
// Find any endswith rule and test it
const endsWithRule = RULES.find(r => r.endswith)
if (endsWithRule) {
// construct a header value that ends with the suffix
const headers = { [endsWithRule.header]: `Test User <test${endsWithRule.endswith}` }
const message = new GmailMessage(headers)
const result = getLabels(message)
expect(result.length).to.be.greaterThan(0)
Comment on lines +256 to +272
// Find a fallback rule that matches on From
const fallbackRule = RULES.find(r => r.fallback && r.header === 'From')
if (fallbackRule) {
// construct headers that match both a non-fallback rule AND the fallback
const headers = {
From: 'Github <noreply@github.com>'
}
// only add fallback match if it wouldn't conflict
if (fallbackRule.contains && !headers.From.includes(fallbackRule.contains)) {
// skip — can't test this combination with github
} else {
const message = new GmailMessage(headers)
const result = getLabels(message)
// should have github label but not the fallback label
expect(result).to.include('github')
}
}
modules/ukko.js Outdated
Comment on lines +123 to +129
if (email && email.includes('@') && email.includes('.')) {
const fqdn = email.split('@')[1]
messageFromDomain = fqdn.split('.').reverse()[1]
}
const listIDshort = getReMatch('listid', message.getHeader('List-Id'))
let label = baseLabel + '/' + listIDshort
if (messageFromDomain !== 'mydomain') {
Replaces hardcoded if/else label logic in getLabels() with a
declarative RULES array and HANDLERS object pattern.

- RULES: array of {header, contains/endswith, label, handler, fallback}
- HANDLERS: named functions receiving (message, baseLabel) for dynamic sublabeling
- Fallback rules only fire when no other rules matched
- Added Makefile for containerized testing (node:20-alpine via Podman)
- 19 new tests (38 total), all passing
- Lint clean (0 errors)
- Updated README with config-driven documentation
- Fixed npm start: node app.js instead of node .

Closes #1
@T0MASD T0MASD force-pushed the config-driven-rules-engine branch from 23accde to ee1ce47 Compare March 18, 2026 11:45
@T0MASD
Copy link
Owner Author

T0MASD commented Mar 18, 2026

@copilot resolve addressed

Copy link

Copilot AI commented Mar 18, 2026

@T0MASD I've opened a new pull request, #11, to work on those changes. Once the pull request is ready, I'll request review from you.

@T0MASD T0MASD merged commit 307238e into main Mar 18, 2026
3 checks passed
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.

decouple app.js data from 'run filter tests'

3 participants