A windowed design is easy. Starting with an ideal zero-phase frequency response:
$$\frac{\omega}{2\pi} + \frac{1}{2}$$
The inverse Fourier transform of that gives the ideal impulse response:
$$\int^\pi_{-\pi}\left(\frac{\omega}{2\pi}+\frac{1}{2}\right)e^{i\omega k}d\omega = \frac{\sin(\pi k)}{k} + i\left(\frac{\sin(\pi k)}{\pi k^2} - \frac{\cos(\pi k)}{k}\right).$$
Similar to the $\text{sinc}$ function, the real part $\frac{\sin(\pi k)}{k}$ has an illegal division by zero at $k=0$ where the limiting value $\pi$ should be used instead. For other integer $k$, the real part is zero. The imaginary part has similar problems at $k=0$, where its limit is 0. Drawing from Rick's answer, at integer $k$, $\sin(\pi k)$ is zero and $\cos(\pi k)$ is +1 or -1. This simplifies the ideal impulse response at integer $k$ to:
$$\begin{cases}\pi&\text{if }k=0,
\\i\frac{-(-1)^k}{k}&\text{otherwise.}\end{cases}$$
If the filter is implemented as a sum of a purely real and a purely imaginary filter, the purely real filter requires no work other than to multiply the input by a constant. The imaginary part of the impulse response is antisymmetrical, which may enable savings.
To continue with the windowed design, choose a window function and its length (equals the number of filter taps) and multiply the ideal impulse response by it.
That gives the impulse response of the filter. The window function should be centered at $k = 0$.