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
67 changes: 61 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: CI

permissions:
contents: read

on:
push:
branches: [main]
Expand All @@ -16,17 +19,69 @@ jobs:
with:
enable-cache: true

- name: Install just
uses: extractions/setup-just@dd310ad5a97d8e7b41793f8ef055398d51ad4de6 # v2

- name: Set up Python
run: uv python install 3.12

- name: Install dependencies
run: uv sync --all-extras --dev

- name: Lint (ruff)
run: uv run ruff check .
- name: Install extension test tools
run: scripts/install-gnome-test-requirements.sh

- name: Lint
run: just lint

- name: Static analysis
run: just static

- name: Static analysis (mypy)
run: uv run mypy src
- name: Tests
run: just test

- name: Tests (pytest + coverage)
run: uv run pytest
- name: Package extension
run: just package-extension

- name: Upload extension package
uses: actions/upload-artifact@v4
with:
name: gnome-shell-extension
path: dist/et@seb4stien.github.com.shell-extension.zip

gnome-shell:
name: GNOME Shell ${{ matrix.shell }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
shell: "46"
- os: ubuntu-26.04
shell: "50"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- name: Install just
uses: extractions/setup-just@dd310ad5a97d8e7b41793f8ef055398d51ad4de6 # v2

- name: Install GNOME Shell test dependencies
run: scripts/install-gnome-test-requirements.sh

- name: Verify scripts
run: shellcheck scripts/*.sh scripts/lib/*.sh

- name: Run real Shell lifecycle test
env:
CI: "true"
ET_DIAGNOSTICS_DIR: ${{ github.workspace }}/artifacts/gnome-${{ matrix.shell }}
run: just test-extension-live --strict --expected-shell-major ${{ matrix.shell }}

- name: Upload Shell diagnostics
if: failure()
uses: actions/upload-artifact@v4
with:
name: gnome-shell-${{ matrix.shell }}-diagnostics
path: artifacts/gnome-${{ matrix.shell }}
if-no-files-found: ignore
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.venv/
__pycache__/
dist/
gschemas.compiled
.coverage
*.egg-info/
11 changes: 5 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@ repos:
hooks:
- id: ruff
name: ruff check
entry: uv run ruff check
entry: just lint
language: system
types: [python]
pass_filenames: false
- id: mypy
name: mypy
entry: uv run mypy src
name: static analysis
entry: just static
language: system
types: [python]
pass_filenames: false
- id: pytest
name: pytest
entry: uv run pytest
entry: just test
language: system
pass_filenames: false
always_run: true
73 changes: 64 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,57 @@ All notable changes to `et` are documented here. Format loosely follows
## [Unreleased]

### Added
- `et config`: an interactive wizard to create or update
`~/.config/et/config.yaml` (the `jira` block and the `workspaces` list),
pre-filling existing values and testing Jira credentials once entered.

## [1.0.0-rc.1]

Release candidate for `v1.0.0`, built from `feat/native-wayland` (PR #9).

### Changed
- **Breaking:** `et jira start` now takes the Jira issue key as a
positional argument (`et jira start KEY`) instead of the `-k`/`--key`
option; the option has been removed.

### Fixed
- Workspace creation, deletion, reset, and reordering now roll back reversible
config and GNOME settings changes when a later step fails, and report when
extension state may still be partially applied.
- Jira worklogs that succeed before a counter-reset failure are now reported
as partial successes with a safe counter-only recovery command, preventing
accidental duplicate worklogs on retry.
- Jira issue and transition parsing now handles malformed nested response
fields without leaking raw `AttributeError` exceptions.
- Config updates are now written atomically with restrictive permissions.
- CI now restricts token permissions and pins the third-party `setup-just`
action to an immutable commit.
- `scripts/install-gnome-shell-extension.sh` now *copies* the `et` GNOME
Shell extension into `~/.local/share/gnome-shell/extensions/` by default
instead of symlinking it, so it keeps working across workspace
re-provisioning that happens on a timeline independent of the GNOME
session (previously, if the symlink's target didn't exist yet at the
exact moment GNOME Shell scanned extensions at startup, the extension was
silently skipped and never loaded until an unrelated further restart).
Pass `--dev`/`--symlink` to opt back into symlinking, e.g. when actively
editing `extension.js`. The "not yet scanned" fallback message now also
queries the running Shell over D-Bus to distinguish "never scanned" from
"scanned but errored".

### Added
- A companion `et` GNOME Shell extension
(`gnome-extension/et@seb4stien.github.com`, installed via
`scripts/install-gnome-shell-extension.sh` / `just install-requirements`)
exposing a D-Bus service used to detect the active workspace on Wayland
sessions and to own persistent per-workspace counters. Managed dynamic
workspaces now start and pause automatically as the active workspace
changes, pause while the session is locked, and resume after unlock.
- Configurable, ticket-system-agnostic workspace labels, reference estimates,
and live counters in both the GNOME top panel and workspace switcher. A
libadwaita preferences window controls each displayed value and location;
only the counter is shown by default.
- D-Bus operations for the CLI to prepare, read, reset, remove, update, and
atomically remap workspace counters without editing extension state directly.
- `et jira start -k KEY` (`--key`): start a task from a specific Jira issue
key directly, skipping the active-issues picker (failing if `KEY` is
already linked to a workspace). Follows the same steps as the
Expand All @@ -30,12 +81,12 @@ All notable changes to `et` are documented here. Format loosely follows
the active workspace (or a different issue via `-j`/`--jira`), prompting
for the message if not given as an argument.
- `et jira log-time [Xh]`: log a manually-specified duration (e.g. `2h`,
`1.5h`) to the linked Jira issue instead of reading the Tracker timer's
`1.5h`) to the linked Jira issue instead of reading the workspace counter's
elapsed time.
- `et jira log-time --all`: log every workspace with a linked Jira issue
(not just the active one) in a single run, each to its own issue, without
switching GNOME workspaces. Workspaces with too little tracked time, no
Tracker timer, or a failing Jira call are skipped and reported instead of
prepared counter, or a failing Jira call are skipped and reported instead of
aborting the rest.
- `et jira status [in-progress|blocked]`: move the linked Jira issue
directly to "In Progress" or "Blocked". With no argument, shows the
Expand All @@ -61,11 +112,16 @@ All notable changes to `et` are documented here. Format loosely follows
issues in the Jira web UI.
- `et ws organize`: reorder dynamic workspaces by editing their order in
`$EDITOR` (static workspaces stay pinned). Shows a before/after summary
(old/new index, name, linked Jira issue, Tracker time) and asks for
confirmation before applying. Tracker timers follow their workspace to
(old/new index, name, linked Jira issue, counter time) and asks for
confirmation before applying. Counters follow their workspace to
its new slot.

### Changed
- The bundled `et` extension replaces the third-party Tracker extension.
Existing Tracker values are intentionally not imported; newly prepared
workspaces start at zero.
- Jira issue reads now include the original estimate so the CLI can provide it
to the generic extension display alongside the workspace label.
- Config gains `jira.project_key` and `jira.board_id`.
- Jira issue references (`et jira log-time`, `et jira complete`) are now
clickable OSC 8 terminal hyperlinks, like `et jira start` already was.
Expand All @@ -74,16 +130,15 @@ All notable changes to `et` are documented here. Format loosely follows
- `et jira complete` now actually deletes the freed GNOME workspace instead
of leaving an empty slot, and prompts for confirmation before freeing the
workspace and closing the linked Jira issue.
- `et jira start` (task creation) now cleans up stale Tracker timers left
behind by previously deleted workspaces.
- `et jira start` resets a reused workspace's extension-owned counter.
- `et ws delete` shrinks GNOME's workspace count instead of leaving a bare
trailing slot, and no longer orphans the Tracker timer when deleting the
trailing slot, and no longer orphans the counter when deleting the
last remaining workspace.
- Workspace names can now be up to 30 characters (up from a shorter limit).
- Dropped the `max_workspaces` config option; `et` now requires a fixed
(non-dynamic) set of GNOME workspaces and manages within it directly.
- README now recommends the Workspace Switcher Manager GNOME extension for
showing workspace names on-screen.
- README now documents the built-in panel/switcher display and extension
preferences.

### Fixed
- Rejected Jira credentials are now reported as such instead of as an
Expand Down
82 changes: 82 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Contributing

This document covers the development workflow for `et`: setting up a dev
environment, running tests/lint/static analysis, and testing the bundled
GNOME Shell extension. For user-facing setup and usage, see the
[README](./README.md); for internal design rationale, see
[docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).

## Setting up a development environment

This project uses [uv](https://docs.astral.sh/uv/) and exposes common tasks
through a [`Justfile`](./Justfile):

```bash
just install-requirements # system tools + uv sync + git hooks + GNOME extension
```

This installs the GNOME test tooling, runs `uv sync --all-extras --dev`,
installs the [`prek`](https://github.com/j178/prek) (pre-commit) git hook,
and installs/enables the bundled GNOME Shell extension (see
[The `et` GNOME Shell extension](./README.md#the-et-gnome-shell-extension)
in the README).

`prek` runs linting, static validation, Python tests, and the fast GJS unit
tests on every commit. It does not launch a real GNOME Shell.

## Common tasks

```bash
just install-requirements # system tools + uv sync + hooks + GNOME extension
just dev # uv run et --help
just lint # ruff + ShellCheck
just static # mypy + extension metadata/schema validation
just test # pytest + coverage + deterministic GJS tests
just test-integ # Python integration + real headless Shell test
just test-extension # isolated interactive nested Shell
just test-extension-live # isolated automated real-Shell lifecycle test
just package-extension # build and validate only the extension ZIP
just ops # build the Python package and extension ZIP
```

Before opening a PR, make sure `just lint`, `just static`, and `just test`
all pass (this is exactly what `prek`/CI check).

`just ops` writes the extensions.gnome.org-ready archive to
`dist/et@seb4stien.github.com.shell-extension.zip`. The package contains
only the extension runtime, preferences, schema source, stylesheet,
metadata, and license; generated schemas and repository tooling are
excluded.

## Testing the GNOME Shell extension

The extension has three test layers:

- `just test` runs the Python suite and deterministic GJS unit tests for
the extension's persisted counter store and display formatting. These
tests do not start GNOME Shell or access the host's GNOME settings.
- `just test-extension-live` starts a real headless GNOME Shell and
exercises the complete D-Bus lifecycle, including timing, remapping,
persistence, and disable/re-enable cleanup. It uses a disposable HOME
and XDG tree.
- `just test-extension` starts an interactive nested Wayland Shell for
visual checks. The extension, dconf database, caches, runtime directory,
and enabled extension list all live under a temporary directory that is
deleted on exit; nothing is installed into the host user's extension
directory. A working user systemd session is required so every helper
daemon is reaped.

GitHub Actions runs the real-Shell lifecycle test on Ubuntu 24.04/GNOME 46
and Ubuntu 26.04/GNOME 50, matching `metadata.json`.

For full-desktop visual compatibility checks, use disposable GNOME Boxes or
QEMU snapshots for both Ubuntu releases:

1. Build the test artifact with `just package-extension`.
2. Restore a clean VM snapshot and copy
`dist/et@seb4stien.github.com.shell-extension.zip` into the VM.
3. Install the ZIP with `gnome-extensions install --force <zip>`, log out
and back in, then enable the extension.
4. Check preferences, the top-panel display, workspace-switcher labels,
workspace changes, lock/unlock counter pausing, and disable/re-enable.
5. Revert the VM snapshot after the test.
21 changes: 21 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
[private]
default:
@just --list --unsorted

install-requirements:
scripts/install-gnome-test-requirements.sh
uv sync --all-extras --dev
uv run prek install
scripts/install-gnome-shell-extension.sh

dev:
uv run et --help

lint:
uv run ruff check .
shellcheck scripts/*.sh scripts/lib/*.sh

static:
uv run mypy src
python3 scripts/check-gnome-shell-extension.py gnome-extension/et@seb4stien.github.com
glib-compile-schemas --strict --dry-run gnome-extension/et@seb4stien.github.com/schemas

test:
uv run pytest
gjs -m tests/gnome-extension/test-extension.js

test-integ:
uv run pytest tests/integration --no-cov
scripts/check-gnome-shell-extension-live.sh

test-extension:
scripts/test-gnome-shell-extension.sh

test-extension-live *ARGS:
scripts/check-gnome-shell-extension-live.sh {{ARGS}}

package-extension:
scripts/package-gnome-shell-extension.sh

ops:
uv build
just package-extension
Loading
Loading