Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI

on:
push:
branches-ignore:
- 'gh-pages'
pull_request:
branches:
- main
- development

jobs:
lint-and-test:
name: Lint + Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Install
run: npm install

- name: Lint
run: npm run lint

- name: Test
run: npm test
126 changes: 126 additions & 0 deletions .github/workflows/pr-version-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: PR version bump

on:
pull_request:
types: [opened, synchronize, reopened, labeled]
branches:
- main

permissions:
contents: write
pull-requests: read

concurrency:
group: pr-bump-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
bump:
name: Lint, test, bump
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Install
run: npm install

- name: Lint
run: npm run lint

- name: Test
run: npm test

- name: Determine bump kind from PR labels
id: kind
run: |
LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}'
echo "labels: $LABELS"
if echo "$LABELS" | grep -q '"major"'; then
echo "kind=major" >> "$GITHUB_OUTPUT"
elif echo "$LABELS" | grep -q '"minor"'; then
echo "kind=minor" >> "$GITHUB_OUTPUT"
else
echo "kind=patch" >> "$GITHUB_OUTPUT"
fi

- name: Read PR and main versions
id: versions
run: |
PR_VERSION=$(node -p "require('./package.json').version")
git fetch origin main --depth=1
if git cat-file -e origin/main:package.json 2>/dev/null; then
MAIN_VERSION=$(git show origin/main:package.json | node -p "JSON.parse(require('fs').readFileSync(0, 'utf8')).version")
echo "main_has_pkg=true" >> "$GITHUB_OUTPUT"
else
MAIN_VERSION=""
echo "main_has_pkg=false" >> "$GITHUB_OUTPUT"
fi
echo "pr=$PR_VERSION" >> "$GITHUB_OUTPUT"
echo "main=$MAIN_VERSION" >> "$GITHUB_OUTPUT"
echo "PR version: $PR_VERSION"
echo "main version: ${MAIN_VERSION:-<none>}"

- name: Decide whether to skip the bump
id: skip
run: |
MAIN_HAS_PKG="${{ steps.versions.outputs.main_has_pkg }}"
PR="${{ steps.versions.outputs.pr }}"
MAIN="${{ steps.versions.outputs.main }}"
if [ "$MAIN_HAS_PKG" != "true" ]; then
echo "main has no package.json — first-release bootstrap. Skipping bump; PR's version will be released as-is."
echo "skip=true" >> "$GITHUB_OUTPUT"
elif [ "$PR" != "$MAIN" ]; then
echo "PR version differs from main — assuming manual bump. Skipping."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Compute next version
if: steps.skip.outputs.skip == 'false'
id: next
run: |
KIND="${{ steps.kind.outputs.kind }}"
MAIN="${{ steps.versions.outputs.main }}"
NEXT=$(node -e "
const [maj, min, pat] = '$MAIN'.split('.').map(Number);
const kind = '$KIND';
if (kind === 'major') console.log((maj+1) + '.0.0');
else if (kind === 'minor') console.log(maj + '.' + (min+1) + '.0');
else console.log(maj + '.' + min + '.' + (pat+1));
")
echo "version=$NEXT" >> "$GITHUB_OUTPUT"
echo "Next version: $NEXT"

- name: Update package.json
if: steps.skip.outputs.skip == 'false'
run: |
NEXT="${{ steps.next.outputs.version }}"
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '$NEXT';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"

- name: Commit and push bump
if: steps.skip.outputs.skip == 'false'
run: |
NEXT="${{ steps.next.outputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add package.json
git commit -m "chore: bump version to $NEXT [skip ci]"
git push origin HEAD:${{ github.event.pull_request.head.ref }}
72 changes: 72 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Release

on:
push:
branches:
- main

permissions:
contents: write

jobs:
release:
name: Tag and publish
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Install
run: npm install

- name: Lint
run: npm run lint

- name: Test
run: npm test

- name: Read version from package.json
id: pkg
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"

- name: Check if tag already exists
id: check_tag
run: |
TAG="${{ steps.pkg.outputs.tag }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Tag $TAG already exists. Skipping release."
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "Tag $TAG does not exist. Will create release."
fi

- name: Create tag
if: steps.check_tag.outputs.exists == 'false'
run: |
TAG="${{ steps.pkg.outputs.tag }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"

- name: Create GitHub Release
if: steps.check_tag.outputs.exists == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ steps.pkg.outputs.tag }}"
gh release create "$TAG" \
--title "$TAG" \
--generate-notes
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.DS_Store
docs/
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Log Highlighter

A static, no-build browser tool for highlighting and filtering raw logs. Paste log text, define keyword groups (each gets a distinct pastel color), and the output panel highlights matches. Embedded JSON and Apple `NSDictionary` payloads inside log lines are detected and pretty-printed inline.
[![CI](https://github.com/al-af/LogHighlighter/actions/workflows/ci.yml/badge.svg)](https://github.com/al-af/LogHighlighter/actions/workflows/ci.yml)

A static, no-build browser tool for highlighting and filtering raw logs. Paste log text, define keyword groups (each gets a distinct pastel color), and the output panel highlights matches. Embedded JSON and Apple `NSDictionary` payloads inside log lines are detected and pretty-printed inline. Android `logcat` lines (threadtime, time, and brief formats) are detected and colored by severity (V/D/I/W/E/F/A), so iOS and Android logs both render usefully.

## Structure

Expand All @@ -15,8 +17,13 @@ A static, no-build browser tool for highlighting and filtering raw logs. Paste l
│ ├── groups.js # group/keyword CRUD mutators
│ ├── groupsView.js # renders #groups panel
│ ├── payload.js # JSON + NSDictionary detection and pretty-print
│ ├── logcat.js # Android logcat line detection (level + tag)
│ ├── highlight.js # HTML-escaping + overlap-free multi-group highlighter
│ └── output.js # renders #output panel (filter/full modes)
│ ├── output.js # renders #output panel (filter/full modes)
│ ├── storage.js # versioned localStorage I/O
│ ├── presets.js # named-preset CRUD
│ └── share.js # URL hash encode/decode for shareable links
├── tests/ # vitest unit tests
└── .nojekyll # disables Jekyll processing on GitHub Pages
```

Expand All @@ -32,6 +39,36 @@ python3 -m http.server 8000

Then open <http://localhost:8000>.

## Tests

Unit tests cover storage, presets, and share-link encoding.

```bash
npm install
npm test
```

## Sharing setups

Click **Share** in the Keyword Groups panel to copy a URL with your current groups encoded in the fragment. Send it to a teammate — they open the link, get your setup preloaded, and paste their own logs in. The share URL never includes log content.

If the recipient already has local groups configured, a banner asks whether to use the shared setup, keep theirs, or merge.

## Releases

Releases are fully automated. The flow:

1. Open a PR against `main`.
2. The **PR version bump** workflow runs lint + test, then commits a `package.json` bump back to your PR branch as `github-actions[bot]`. Default is a patch bump. Add a label to override:
- `minor` → minor version bump
- `major` → major version bump
3. Merge the PR.
4. The **Release** workflow tags the merge commit `v<version>` and publishes a GitHub Release with auto-generated notes.

If `package.json` is already ahead of `main` when the PR is opened (you bumped manually), the bot skips the bump and respects your version.

The Release workflow is idempotent — pushing unrelated changes to `main` without a version bump does nothing.

## Deploy to GitHub Pages

One-time setup (run from the project root):
Expand Down
Loading
Loading