Sign in Start free
Documentation

Advanced Scripting

Advanced patterns, cron automation, testing, and best practices for Heyweek CLI scripts.

Last updated:

Advanced patterns, cron automation, testing, and best practices for Heyweek CLI scripts.

Advanced Patterns

State management

Maintain state between runs by saving a value to a file. This example records the project you last logged against:

bash
<span class="token shebang important">#!/bin/bash</span>
<span class="token comment"># stateful-tracker.sh</span>

<span class="token assign-left variable">STATE_FILE</span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$HOME</span>/.hw-script-state"</span>

<span class="token comment"># Load previous state</span>
<span class="token punctuation">[</span> <span class="token parameter variable">-f</span> <span class="token string">"<span class="token variable">$STATE_FILE</span>"</span> <span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">source</span> <span class="token string">"<span class="token variable">$STATE_FILE</span>"</span>

<span class="token comment"># Pick the first project as the current one</span>
<span class="token assign-left variable">CURRENT</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span>hw project list <span class="token parameter variable">-q</span> <span class="token string">'.[0].id'</span><span class="token variable">)</span></span>

<span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$CURRENT</span>"</span> <span class="token operator">!=</span> <span class="token string">"<span class="token variable">${LAST_PROJECT<span class="token operator">:-</span>}</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
  <span class="token builtin class-name">echo</span> <span class="token string">"Active project changed from <span class="token variable">${LAST_PROJECT<span class="token operator">:-</span>none}</span> to <span class="token variable">$CURRENT</span>"</span>
  <span class="token builtin class-name">echo</span> <span class="token string">"LAST_PROJECT='<span class="token variable">$CURRENT</span>'"</span> <span class="token operator">></span> <span class="token string">"<span class="token variable">$STATE_FILE</span>"</span>
<span class="token keyword">fi</span>

Git hook integration

Log time automatically from a git post-commit hook by mapping the branch to a project:

bash
<span class="token shebang important">#!/bin/bash</span>
<span class="token comment"># .git/hooks/post-commit</span>

<span class="token assign-left variable">COMMIT_MSG</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">git</span> log <span class="token parameter variable">-1</span> <span class="token parameter variable">--pretty</span><span class="token operator">=</span>%B<span class="token variable">)</span></span>
<span class="token assign-left variable">BRANCH</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">git</span> branch --show-current<span class="token variable">)</span></span>

<span class="token comment"># Map branch to a project ID</span>
<span class="token keyword">case</span> <span class="token string">"<span class="token variable">$BRANCH</span>"</span> <span class="token keyword">in</span>
  feature/*<span class="token punctuation">)</span> <span class="token assign-left variable">PROJECT</span><span class="token operator">=</span><span class="token string">"proj-123"</span> <span class="token punctuation">;</span><span class="token punctuation">;</span>
  bugfix/*<span class="token punctuation">)</span>  <span class="token assign-left variable">PROJECT</span><span class="token operator">=</span><span class="token string">"proj-456"</span> <span class="token punctuation">;</span><span class="token punctuation">;</span>
  *<span class="token punctuation">)</span>         <span class="token assign-left variable">PROJECT</span><span class="token operator">=</span><span class="token string">"proj-internal"</span> <span class="token punctuation">;</span><span class="token punctuation">;</span>
<span class="token keyword">esac</span>

hw log create <span class="token punctuation">\</span>
  <span class="token parameter variable">-d</span> <span class="token string">"Development: <span class="token variable">$COMMIT_MSG</span>"</span> <span class="token punctuation">\</span>
  <span class="token parameter variable">-p</span> <span class="token string">"<span class="token variable">$PROJECT</span>"</span> <span class="token punctuation">\</span>
  <span class="token parameter variable">-s</span> <span class="token string">"09:00"</span> <span class="token punctuation">\</span>
  <span class="token parameter variable">-e</span> <span class="token string">"09:15"</span>

Cron Automation

Schedule real hw commands with cron. Edit your crontab with crontab -e:

bash
<span class="token comment"># Start a timer at 9 AM on weekdays</span>
<span class="token number">0</span> <span class="token number">9</span> * * <span class="token number">1</span>-5 /usr/local/bin/hw timer start <span class="token parameter variable">-d</span> <span class="token string">"Starting work day"</span>

<span class="token comment"># Stop the timer at 5 PM on weekdays</span>
<span class="token number">0</span> <span class="token number">17</span> * * <span class="token number">1</span>-5 /usr/local/bin/hw timer stop

<span class="token comment"># Run a daily logging script at 6 PM</span>
<span class="token number">0</span> <span class="token number">18</span> * * <span class="token number">1</span>-5 /home/user/scripts/daily-log.sh

<span class="token comment"># Renew the auth token every morning so scheduled jobs stay authenticated</span>
<span class="token number">0</span> <span class="token number">8</span> * * * /usr/local/bin/hw auth renew

Testing Scripts

Test your automation with a small assertion helper. This exercises the real timer commands end to end:

bash
<span class="token shebang important">#!/bin/bash</span>
<span class="token comment"># test-timer-script.sh</span>

<span class="token function-name function">assert_ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token parameter variable">-eq</span> <span class="token number">0</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"ok: <span class="token variable">$2</span>"</span>
  <span class="token keyword">else</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"FAIL: <span class="token variable">$2</span>"</span>
    <span class="token builtin class-name">exit</span> <span class="token number">1</span>
  <span class="token keyword">fi</span>
<span class="token punctuation">}</span>

<span class="token comment"># Start a timer</span>
hw timer start <span class="token parameter variable">-d</span> <span class="token string">"Test timer"</span>
assert_ok <span class="token variable">$?</span> <span class="token string">"timer should start"</span>

<span class="token comment"># Status should succeed while a timer is running</span>
hw timer status <span class="token operator">></span>/dev/null <span class="token operator"><span class="token file-descriptor important">2</span>></span><span class="token file-descriptor important">&amp;1</span>
assert_ok <span class="token variable">$?</span> <span class="token string">"timer should be running"</span>

<span class="token comment"># Stop the timer</span>
hw timer stop
assert_ok <span class="token variable">$?</span> <span class="token string">"timer should stop"</span>

<span class="token builtin class-name">echo</span> <span class="token string">"All tests passed!"</span>

Best Practices

Retry on failure

Wrap commands in a retry loop to survive transient errors:

bash
<span class="token shebang important">#!/bin/bash</span>
<span class="token comment"># robust-script.sh</span>

<span class="token function-name function">retry</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token builtin class-name">local</span> <span class="token assign-left variable">n</span><span class="token operator">=</span><span class="token number">1</span> <span class="token assign-left variable">max</span><span class="token operator">=</span><span class="token number">5</span> <span class="token assign-left variable">delay</span><span class="token operator">=</span><span class="token number">2</span>
  <span class="token keyword">until</span> <span class="token string">"<span class="token variable">$@</span>"</span><span class="token punctuation">;</span> <span class="token keyword">do</span>
    <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$n</span>"</span> <span class="token parameter variable">-lt</span> <span class="token string">"<span class="token variable">$max</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
      <span class="token assign-left variable">n</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$((</span>n <span class="token operator">+</span> <span class="token number">1</span><span class="token variable">))</span></span>
      <span class="token builtin class-name">echo</span> <span class="token string">"Command failed. Attempt <span class="token variable">$n</span>/<span class="token variable">$max</span>..."</span>
      <span class="token function">sleep</span> <span class="token string">"<span class="token variable">$delay</span>"</span>
    <span class="token keyword">else</span>
      <span class="token builtin class-name">echo</span> <span class="token string">"Command failed after <span class="token variable">$n</span> attempts."</span>
      <span class="token builtin class-name">return</span> <span class="token number">1</span>
    <span class="token keyword">fi</span>
  <span class="token keyword">done</span>
<span class="token punctuation">}</span>

retry hw timer start <span class="token parameter variable">-d</span> <span class="token string">"Important task"</span>

Logging

Record what your automation does so you can audit it later:

bash
<span class="token shebang important">#!/bin/bash</span>
<span class="token comment"># logged-automation.sh</span>

<span class="token assign-left variable">LOG_FILE</span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$HOME</span>/.hw-automation.log"</span>

<span class="token function-name function">log</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token builtin class-name">echo</span> <span class="token string">"[<span class="token variable"><span class="token variable">$(</span><span class="token function">date</span> <span class="token string">'+%Y-%m-%d %H:%M:%S'</span><span class="token variable">)</span></span>] <span class="token variable">$1</span>"</span> <span class="token operator">>></span> <span class="token string">"<span class="token variable">$LOG_FILE</span>"</span>
<span class="token punctuation">}</span>

log <span class="token string">"Script started"</span>

<span class="token keyword">if</span> hw timer start <span class="token parameter variable">-d</span> <span class="token string">"Automated task"</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
  log <span class="token string">"Timer started successfully"</span>
<span class="token keyword">else</span>
  log <span class="token string">"ERROR: Failed to start timer"</span>
  <span class="token builtin class-name">exit</span> <span class="token number">1</span>
<span class="token keyword">fi</span>

log <span class="token string">"Script completed"</span>

Check authentication first

Long-running and scheduled scripts should confirm they are authenticated before doing real work:

bash
<span class="token shebang important">#!/bin/bash</span>
<span class="token keyword">if</span> <span class="token operator">!</span> hw user ctx <span class="token operator">></span>/dev/null <span class="token operator"><span class="token file-descriptor important">2</span>></span><span class="token file-descriptor important">&amp;1</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
  <span class="token builtin class-name">echo</span> <span class="token string">"Not authenticated. Run 'hw auth login' or 'hw auth renew'."</span>
  <span class="token builtin class-name">exit</span> <span class="token number">1</span>
<span class="token keyword">fi</span>

hw timer start <span class="token parameter variable">-d</span> <span class="token string">"Background task"</span>

← Back to CLI scripting.