9 Commits

Author SHA1 Message Date
7b5b855774 chore(changelog): update changelog for v0.2.0
All checks were successful
Upload Assets / upload-assets (arm64, linux) (release) Successful in 15s
Upload Assets / upload-assets (amd64, linux) (release) Successful in 17s
2025-05-22 08:31:49 +00:00
6fc6207da8 chore(version): update to 0.2.0
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 4s
Auto Changelog & Release / changelog-only (push) Has been skipped
Auto Changelog & Release / release (push) Successful in 32s
2025-05-22 10:21:55 +02:00
264b43c9a6 feat(scripts): add installation script for systemd-timer binary
- Introduces a Bash script to install the systemd-timer binary
- Detects OS and architecture to download the appropriate binary
- Verifies the binary using SHA256 checksum for security
- Supports installation with or without sudo privileges
2025-05-22 10:21:24 +02:00
118e4e5a86 feat(workflows): add matrix build and SHA256 generation for releases
- Introduce matrix strategy for building and uploading binaries
  for multiple architectures (amd64, arm64).
- Generate SHA256 checksum files for release binaries.
- Upload both binaries and their corresponding SHA256 files
  as release assets for better integrity verification.
2025-05-22 10:20:07 +02:00
01898a3a8e feat(tasks): add build tasks for amd64 and arm64 targets
- Introduces separate build tasks for amd64 and arm64 architectures
- Enables cross-compilation for better platform support
2025-05-22 10:19:02 +02:00
1a1ad66ab6 chore(changelog): update unreleased changelog 2025-05-21 07:51:29 +00:00
bd71b8ee14 fix(utils): handle file write failures with rollback
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 3s
Auto Changelog & Release / release (push) Has been skipped
Auto Changelog & Release / changelog-only (push) Successful in 5s
- Add error handling and rollback logic for unit file writes
- Prevent partial file writes by removing created files on failure
- Update tests to reflect new return type and error handling
2025-05-21 09:51:16 +02:00
a76417ce1d chore(changelog): update unreleased changelog 2025-05-21 07:21:11 +00:00
a288dbc140 docs(readme): add project time badge
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 4s
Auto Changelog & Release / release (push) Has been skipped
Auto Changelog & Release / changelog-only (push) Successful in 8s
2025-05-21 09:20:54 +02:00
9 changed files with 122 additions and 36 deletions

View File

@@ -1,38 +1,27 @@
# ========================
# 📦 Upload Assets Template
# ========================
# Dieser Workflow wird automatisch ausgelöst, wenn ein Release
# in Gitea veröffentlicht wurde (event: release.published).
#
# Er dient dem Zweck, Release-Artefakte (wie z. B. Binary-Dateien,
# Changelogs oder Build-Zips) nachträglich mit dem Release zu verknüpfen.
#
# Voraussetzung: Zwei Shell-Skripte liegen im Projekt:
# - .gitea/scripts/get-release-id.sh → ermittelt Release-ID per Tag
# - .gitea/scripts/upload-asset.sh → lädt Datei als Release-Asset hoch
#
# --------------------------------------
name: Upload Assets
on:
release:
types: [published] # Nur bei Veröffentlichung eines Releases (nicht bei Entwürfen)
types: [published]
jobs:
upload-assets:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: linux
arch: amd64
- target: linux
arch: arm64
steps:
# 📥 Checke den Stand des Repos aus, exakt auf dem veröffentlichten Tag
# So ist garantiert, dass die Artefakte dem Zustand des Releases entsprechen.
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }} # z. B. "v1.2.3"
fetch-depth: 0 # vollständige Git-Historie (für z. B. git-cliff, logs etc.)
ref: ${{ github.event.release.tag_name }}
fetch-depth: 0
# 🆔 Hole die Release-ID basierend auf dem Tag
# Die ID wird als Umgebungsvariable RELEASE_ID über $GITHUB_ENV verfügbar gemacht.
- name: Get Release ID from tag
run: .gitea/scripts/get-release-id.sh "${{ github.event.release.tag_name }}"
@@ -40,8 +29,16 @@ jobs:
with:
deno-version: v2.x
- name: Build application
run: deno task build
- name: Build ${{ matrix.target }}-${{ matrix.arch }}
run: deno task build:${{ matrix.arch }}
- name: Upload CHANGELOG.md as RELEASE-NOTES.md
run: .gitea/scripts/upload-asset.sh ./dist/systemd-timer systemd-timer
- name: Generate SHA256 for ${{ matrix.target }}-${{ matrix.arch }}
run: |
FILE="./dist/systemd-timer-${{ matrix.target }}-${{ matrix.arch }}"
sha256sum "$FILE" > "$FILE.sha256"
- name: Upload binary for ${{ matrix.target }}-${{ matrix.arch }}
run: .gitea/scripts/upload-asset.sh ./dist/systemd-timer-${{ matrix.target }}-${{ matrix.arch }} systemd-timer-${{ matrix.target }}-${{ matrix.arch }}
- name: Upload SHA256 for ${{ matrix.target }}-${{ matrix.arch }}
run: .gitea/scripts/upload-asset.sh ./dist/systemd-timer-${{ matrix.target }}-${{ matrix.arch }}.sha256 systemd-timer-${{ matrix.target }}-${{ matrix.arch }}.sha256

View File

@@ -2,6 +2,22 @@
All notable changes to this project will be documented in this file.
## [0.2.0](https://git.0xmax42.io/maxp/systemd-timer/compare/v0.1.0..v0.2.0) - 2025-05-22
### 🚀 Features
- *(scripts)* Add installation script for systemd-timer binary - ([264b43c](https://git.0xmax42.io/maxp/systemd-timer/commit/264b43c9a667d344e27cca4ac2f17d7a4a25bffc))
- *(workflows)* Add matrix build and SHA256 generation for releases - ([118e4e5](https://git.0xmax42.io/maxp/systemd-timer/commit/118e4e5a867a42c0d79efcc3b2a4db188affedec))
- *(tasks)* Add build tasks for amd64 and arm64 targets - ([01898a3](https://git.0xmax42.io/maxp/systemd-timer/commit/01898a3a8e094dfbbf981ab6f1cf38d52f60ef5d))
### 🐛 Bug Fixes
- *(utils)* Handle file write failures with rollback - ([bd71b8e](https://git.0xmax42.io/maxp/systemd-timer/commit/bd71b8ee14a1856f1adaaaea198c8467b1a00d24))
### 📚 Documentation
- *(readme)* Add project time badge - ([a288dbc](https://git.0xmax42.io/maxp/systemd-timer/commit/a288dbc140fefbc46745f70cdcd71148802fdabf))
## [0.1.0] - 2025-05-21
### 🚀 Features

View File

@@ -1,5 +1,7 @@
# systemd-timer
![Project time](https://waka.0xmax42.io/api/badge/0XMax42/interval:today/project:systemd-timer?label=Project%20time)
Ein einfaches CLI-Tool zum schnellen Erzeugen von systemd `.service` und `.timer` Units – als Ersatz oder moderne Ergänzung zu klassischen `cron`-Jobs.
---

View File

@@ -1 +1 @@
0.1.0
0.2.0

View File

@@ -2,7 +2,8 @@
"tasks": {
"start": "deno run -A src/mod.ts",
"test": "deno test -A --coverage **/__tests__/*.test.ts",
"build": "deno compile --include=VERSION --allow-env --allow-write --output dist/systemd-timer src/mod.ts"
"build:amd64": "deno compile --target x86_64-unknown-linux-gnu --include=VERSION --allow-env --allow-write --output dist/systemd-timer-linux-amd64 src/mod.ts",
"build:arm64": "deno compile --target aarch64-unknown-linux-gnu --include=VERSION --allow-env --allow-write --output dist/systemd-timer-linux-arm64 src/mod.ts"
},
"compilerOptions": {},
"fmt": {

48
scripts/install.sh Normal file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
# === Konfiguration ===
REPO_URL="https://git.0xmax42.io/maxp/systemd-timer/releases/download/latest"
BINARY_NAME="systemd-timer"
INSTALL_PATH="/usr/local/bin"
# === Systemarchitektur erkennen ===
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ARCH="amd64" ;;
aarch64 | arm64) ARCH="arm64" ;;
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
esac
OS=$(uname -s)
case "$OS" in
Linux) OS="linux" ;;
*) echo "Unsupported OS: $OS" >&2; exit 1 ;;
esac
# === Download-URL zusammensetzen ===
BINARY_FILE="${BINARY_NAME}-${OS}-${ARCH}"
DOWNLOAD_URL="${REPO_URL}/${BINARY_FILE}"
echo "📦 Installing ${BINARY_NAME} for ${OS}/${ARCH}..."
echo "🌐 Downloading from: ${DOWNLOAD_URL}"
# === Binary herunterladen ===
TMP_FILE=$(mktemp)
curl -fsSL "${DOWNLOAD_URL}" -o "${TMP_FILE}"
chmod +x "${TMP_FILE}"
# === Optional: SHA256-Check ===
curl -fsSL "${DOWNLOAD_URL}.sha256" -o "${TMP_FILE}.sha256"
echo "$(cat ${TMP_FILE}.sha256) ${TMP_FILE}" | sha256sum -c -
# === Installation ===
echo "🚀 Installing to ${INSTALL_PATH}/${BINARY_NAME}"
if [ -w "$INSTALL_PATH" ]; then
install -m 755 "${TMP_FILE}" "${INSTALL_PATH}/${BINARY_NAME}"
else
sudo install -m 755 "${TMP_FILE}" "${INSTALL_PATH}/${BINARY_NAME}"
fi
echo "✅ Installation complete: $(command -v ${BINARY_NAME})"
"${BINARY_NAME}" --version || true

View File

@@ -12,14 +12,20 @@ export async function generateUnitFiles(options: TimerOptions): Promise<void> {
console.log(`\n===== ${name}.timer =====`);
console.log(timerUnit);
} else {
const { servicePath, timerPath } = await writeUnitFiles(
const result = await writeUnitFiles(
name,
serviceUnit,
timerUnit,
options,
);
console.log(`Service unit written to: ${servicePath}`);
console.log(`Timer unit written to: ${timerPath}`);
if (result) {
const { servicePath, timerPath } = result;
console.log(`Service Unit geschrieben in: ${servicePath}`);
console.log(`Timer Unit geschrieben in: ${timerPath}`);
} else {
return;
}
console.log(`\nℹ️ Hinweis:`);

View File

@@ -24,7 +24,7 @@ Deno.test('writeUnitFiles schreibt .service und .timer korrekt', async () => {
serviceContent,
timerContent,
options as TimerOptions,
);
) as { servicePath: string; timerPath: string };
// Überprüfe Pfade
assertEquals(servicePath, join(tmp, 'test-backup.service'));

View File

@@ -1,4 +1,4 @@
import { ensureDir } from 'https://deno.land/std@0.224.0/fs/mod.ts';
import { ensureDir, exists } from 'https://deno.land/std@0.224.0/fs/mod.ts';
import { join } from 'https://deno.land/std@0.224.0/path/mod.ts';
import { TimerOptions } from '../types/mod.ts';
@@ -7,7 +7,7 @@ export async function writeUnitFiles(
serviceContent: string,
timerContent: string,
options: TimerOptions,
): Promise<{ servicePath: string; timerPath: string }> {
): Promise<{ servicePath: string; timerPath: string } | undefined> {
const basePath = resolveUnitTargetPath(options);
await ensureDir(basePath);
@@ -15,8 +15,24 @@ export async function writeUnitFiles(
const servicePath = join(basePath, `${name}.service`);
const timerPath = join(basePath, `${name}.timer`);
await Deno.writeTextFile(servicePath, serviceContent);
await Deno.writeTextFile(timerPath, timerContent);
try {
await Deno.writeTextFile(servicePath, serviceContent);
await Deno.writeTextFile(timerPath, timerContent);
} catch (error) {
// Rollback: Remove any files that were written
try {
if (await exists(servicePath)) {
await Deno.remove(servicePath);
}
if (await exists(timerPath)) {
await Deno.remove(timerPath);
}
} catch (rollbackError) {
console.error('Rollback fehlgeschlagen:', rollbackError);
}
console.error('Fehler beim Schreiben der Units:', error);
return undefined;
}
return { servicePath, timerPath };
}