3 Commits

Author SHA1 Message Date
07ee03b6be chore(version): bump version to 0.3.0
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 3s
Auto Changelog & Release / changelog-only (push) Has been skipped
Auto Changelog & Release / release (push) Successful in 8s
2025-05-28 14:26:02 +02:00
fb2a62d984 docs(readme): expand CLI option descriptions for clarity
- Add detailed explanations for each CLI option in README files
- Improve consistency and formatting for better readability
- Highlight supported features and usage comprehensively
2025-05-28 14:26:02 +02:00
113103f368 feat(cli): add options for user, home, and working directory
- Add `--run-as` option to specify user for system-wide timers
- Add `--home` option to set the HOME environment variable
- Add `--cwd` option to define the working directory
- Update tests to validate new options and behavior
2025-05-28 14:26:02 +02:00
7 changed files with 109 additions and 22 deletions

View File

@@ -12,13 +12,17 @@ Ein einfaches CLI-Tool zum schnellen Erzeugen von systemd `.service` und `.timer
- Unterstützt `--user` Timer (für `~/.config/systemd/user/`) - Unterstützt `--user` Timer (für `~/.config/systemd/user/`)
- Optionales Logging (`StandardOutput/StandardError`) - Optionales Logging (`StandardOutput/StandardError`)
- Unterstützt: - Unterstützt:
- `--calendar` - `--calendar`: Zeitplan für den Timer (systemd `OnCalendar`)
- `--exec` - `--exec`: Auszuführendes Kommando (`ExecStart`)
- `--after` - `--description`: Beschreibung für die Unit
- `--environment` - `--after`: `After=`-Abhängigkeiten in der Service-Unit
- `--output` - `--environment`: Beliebige `Environment=KEY=VALUE` Einträge
- `--dry-run` - `--output`: Zielverzeichnis für die generierten Unit-Dateien
- Getestet und typisiert mit Deno + Cliffy - `--run-as`: Setzt `User=` in der Service-Unit (nur systemweite Timer)
- `--home`: Setzt `Environment=HOME=…`
- `--cwd`: Arbeitsverzeichnis des Prozesses (`WorkingDirectory`)
- `--dry-run`: Gibt nur die generierten Inhalte aus, ohne sie zu schreiben
- Getestet und typisiert mit **Deno** + **Cliffy**
--- ---

View File

@@ -13,14 +13,17 @@ A simple CLI tool for quickly generating systemd `.service` and `.timer` units
* Supports `--user` timers (for `~/.config/systemd/user/`) * Supports `--user` timers (for `~/.config/systemd/user/`)
* Optional logging (`StandardOutput/StandardError`) * Optional logging (`StandardOutput/StandardError`)
* Supports: * Supports:
* `--calendar`: Timer schedule (systemd `OnCalendar`)
* `--calendar` * `--exec`: Command to execute (`ExecStart`)
* `--exec` * `--description`: Description for the unit
* `--after` * `--after`: `After=` dependencies in the service unit
* `--environment` * `--environment`: Arbitrary `Environment=KEY=VALUE` entries
* `--output` * `--output`: Target directory for the generated unit files
* `--dry-run` * `--run-as`: Sets `User=` in the service unit (only for system-level timers)
* Tested and typed with Deno + Cliffy * `--home`: Sets `Environment=HOME=…`
* `--cwd`: Working directory for the process (`WorkingDirectory`)
* `--dry-run`: Outputs unit content without writing to disk
* Tested and fully typed with **Deno** + **Cliffy**
--- ---

View File

@@ -1 +1 @@
0.2.3 0.3.0

View File

@@ -18,6 +18,18 @@ export const createCommand = new Command()
}) })
.option('--description <desc:string>', 'Beschreibung des Timers') .option('--description <desc:string>', 'Beschreibung des Timers')
.option('--user', 'Erstellt die Unit als User-Timer') .option('--user', 'Erstellt die Unit als User-Timer')
.option(
'--run-as <user:string>',
'Führe den systemweiten Timer als bestimmter Benutzer aus (setzt User= in der Service-Unit)',
)
.option(
'--home <path:string>',
'HOME-Variable für den Service setzen',
)
.option(
'--cwd <path:string>',
'Arbeitsverzeichnis (WorkingDirectory) für den Service-Prozess',
)
.option('--output <dir:string>', 'Zielverzeichnis der Unit-Dateien') .option('--output <dir:string>', 'Zielverzeichnis der Unit-Dateien')
.option( .option(
'--after <target:string>', '--after <target:string>',

View File

@@ -1,4 +1,5 @@
import { import {
assert,
assertStringIncludes, assertStringIncludes,
} from 'https://deno.land/std@0.224.0/assert/mod.ts'; } from 'https://deno.land/std@0.224.0/assert/mod.ts';
import { TimerOptions } from '../../types/mod.ts'; import { TimerOptions } from '../../types/mod.ts';
@@ -53,3 +54,63 @@ Deno.test('generateUnits berücksichtigt environment und logfile', () => {
assertStringIncludes(serviceUnit, 'StandardOutput=append:/var/log/job.log'); assertStringIncludes(serviceUnit, 'StandardOutput=append:/var/log/job.log');
assertStringIncludes(serviceUnit, 'StandardError=append:/var/log/job.log'); assertStringIncludes(serviceUnit, 'StandardError=append:/var/log/job.log');
}); });
Deno.test('generateUnits berücksichtigt runAs', () => {
const opts: TimerOptions = {
exec: '/bin/true',
calendar: 'daily',
runAs: 'myuser',
};
const { serviceUnit } = generateUnits('job', opts);
assertStringIncludes(serviceUnit, 'User=myuser');
});
Deno.test('generateUnits berücksichtigt home', () => {
const opts: TimerOptions = {
exec: '/bin/true',
calendar: 'daily',
home: '/home/myuser',
};
const { serviceUnit } = generateUnits('job', opts);
assertStringIncludes(serviceUnit, 'Environment=HOME=/home/myuser');
});
Deno.test('generateUnits berücksichtigt cwd', () => {
const opts: TimerOptions = {
exec: '/bin/true',
calendar: 'daily',
cwd: '/srv/app',
};
const { serviceUnit } = generateUnits('job', opts);
assertStringIncludes(serviceUnit, 'WorkingDirectory=/srv/app');
});
Deno.test('generateUnits verwendet default.target bei User-Timern', () => {
const opts: TimerOptions = {
exec: '/bin/true',
calendar: 'daily',
user: true,
};
const { timerUnit } = generateUnits('job', opts);
assertStringIncludes(timerUnit, 'WantedBy=default.target');
});
Deno.test('generateUnits ignoriert runAs bei --user', () => {
const opts = {
exec: '/bin/true',
calendar: 'daily',
user: true,
runAs: 'should-not-appear',
};
const { serviceUnit } = generateUnits('job', opts);
assert(
!serviceUnit.includes('User=should-not-appear'),
'User= sollte bei --user nicht enthalten sein',
);
});

View File

@@ -51,14 +51,18 @@ export function generateUnits(name: string, options: TimerOptions): {
`[Service]`, `[Service]`,
`Type=oneshot`, `Type=oneshot`,
`ExecStart=${options.exec}`, `ExecStart=${options.exec}`,
...(options.cwd ? [`WorkingDirectory=${options.cwd}`] : []),
...(options.environment?.map((e) => `Environment=${e}`) ?? []), ...(options.environment?.map((e) => `Environment=${e}`) ?? []),
...(options.home ? [`Environment=HOME=${options.home}`] : []),
...(options.logfile
? [
`StandardOutput=append:${options.logfile}`,
`StandardError=append:${options.logfile}`,
]
: []),
...(options.runAs && !options.user ? [`User=${options.runAs}`] : []),
]; ];
if (options.logfile) {
unitParts.push(`StandardOutput=append:${options.logfile}`);
unitParts.push(`StandardError=append:${options.logfile}`);
}
const serviceUnit = unitParts.join('\n'); const serviceUnit = unitParts.join('\n');
const timerParts = [ const timerParts = [
@@ -70,7 +74,7 @@ export function generateUnits(name: string, options: TimerOptions): {
`Persistent=true`, `Persistent=true`,
``, ``,
`[Install]`, `[Install]`,
`WantedBy=timers.target`, `WantedBy=${options.user ? 'default.target' : 'timers.target'}`,
]; ];
const timerUnit = timerParts.join('\n'); const timerUnit = timerParts.join('\n');

View File

@@ -4,6 +4,9 @@ export interface TimerOptions {
calendar: string; calendar: string;
description?: string; description?: string;
user?: boolean; user?: boolean;
runAs?: string;
home?: string;
cwd?: string;
output?: string; output?: string;
after?: string[]; after?: string[];
environment?: string[]; environment?: string[];