mirror of https://github.com/ohmyzsh/ohmyzsh.git
Compare commits
4 Commits
0673285d78
...
395ddb38c7
Author | SHA1 | Date |
---|---|---|
|
395ddb38c7 | |
|
30e516a3aa | |
|
692ae9a5dc | |
|
75483693fb |
|
@ -0,0 +1,43 @@
|
|||
# JIRA auto-worklog
|
||||
|
||||
This plugin automatically logs time to Atlassian's [JIRA](https://www.atlassian.com/software/jira) bug tracking software when on a git branch with a JIRA issue ID in the branch name.
|
||||
|
||||
## Installation
|
||||
|
||||
Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`):
|
||||
|
||||
```sh
|
||||
plugins=(
|
||||
# other plugins...
|
||||
jira-auto-worklog
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Every time the command prompt is generated, the time spent on a JIRA branch is accumulated. Once the accumulated time exceeds a threshold, the time is logged in the background. By default, the time is logged every minute.
|
||||
|
||||
To prevent AFK time from being counted, no time is logged if there is no activity on a JIRA branch for a certain amount of time. By default the AFK threshold is 30m.
|
||||
|
||||
## Setup
|
||||
|
||||
The URL for your JIRA instance is located in the following places, in order of precedence:
|
||||
|
||||
1. `$JIRA_URL` environment variable
|
||||
2. `./.jira-url` file in the current directory
|
||||
3. `~/.jira-url` file in your home directory
|
||||
|
||||
The PAT for your JIRA instance is located in the following places, in order of precedence:
|
||||
|
||||
1. `./.jira-pat` file in the current directory
|
||||
2. `~/.jira-pat` file in your home directory
|
||||
|
||||
Run `jira-auto-worklog-check` in this directory to check if the plugin is correctly configured.
|
||||
|
||||
### Variables
|
||||
|
||||
* `$JIRA_URL` - Your JIRA instance's URL
|
||||
* `$JIRA_AUTO_WORKLOG_AFK_THRESHOLD` - The number of minutes of AFK time before no time is logged. Defaults to 30
|
||||
* `$JIRA_AUTO_WORKLOG_COMMENT` - The comment to add to the work log. Defaults to an empty string
|
||||
* `$JIRA_AUTO_WORKLOG_PRECISION` - The size of the chunks of time that are logged. Must be greater than zero. Defaults to 1. For example, `JIRA_AUTO_WORKLOG_PRECISION=15` will log 15 minutes after being active for 15 minutes a JIRA branch.
|
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'net/http'
|
||||
require 'json'
|
||||
require 'yaml'
|
||||
require 'date'
|
||||
|
||||
JIRA_REGEX = /([A-Z]+-\d+)/.freeze
|
||||
CONFIG_PATH = "#{Dir.home}/.jira-auto-worklog"
|
||||
|
||||
def jira_url
|
||||
ENV.fetch('JIRA_URL', nil) ||
|
||||
(File.read('./.jira-url').chomp if File.exist?('./.jira-url')) ||
|
||||
(File.read("#{Dir.home}/.jira-url").chomp if File.exist?("#{Dir.home}/.jira-url")) ||
|
||||
nil
|
||||
end
|
||||
|
||||
def jira_pat
|
||||
(File.read('./.jira-pat').chomp if File.exist?('./.jira-pat')) ||
|
||||
(File.read("#{Dir.home}/.jira-pat").chomp if File.exist?("#{Dir.home}/.jira-pat")) ||
|
||||
nil
|
||||
end
|
||||
|
||||
def afk_threshold
|
||||
ENV.fetch('JIRA_AUTO_WORKLOG_AFK_THRESHOLD', 30).to_i
|
||||
end
|
||||
|
||||
def comment
|
||||
ENV.fetch('JIRA_AUTO_WORKLOG_COMMENT', '')
|
||||
end
|
||||
|
||||
def precision
|
||||
ENV.fetch('JIRA_AUTO_WORKLOG_PRECISION', 1).to_i
|
||||
end
|
||||
|
||||
unless jira_url
|
||||
puts 'JIRA URL not found.'
|
||||
puts
|
||||
puts 'Valid Locations are, in order of precedence:'
|
||||
puts ' 1. JIRA_URL environment variable'
|
||||
puts ' 2. ./.jira-url'
|
||||
puts ' 3. ~/.jira-url'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
unless jira_pat
|
||||
puts 'JIRA Personal Access Token not found.'
|
||||
puts
|
||||
puts 'Valid Locations are, in order of precedence:'
|
||||
puts ' 1. ./.jira-pat'
|
||||
puts ' 2. ~/.jira-pat'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
unless precision > 0
|
||||
puts 'Precision must be a positive integer.'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
branch = `command git rev-parse --abbrev-ref --symbolic-full-name HEAD 2> /dev/null`
|
||||
exit(0) unless (match = branch.match(JIRA_REGEX))
|
||||
|
||||
ticket = match[1]
|
||||
|
||||
# load the config
|
||||
data = {}
|
||||
if File.exist?(CONFIG_PATH)
|
||||
data = YAML.safe_load(File.read(CONFIG_PATH), permitted_classes: [Time])
|
||||
end
|
||||
data['overflow'] ||= 0
|
||||
data['last_updated'] ||= Time.now
|
||||
|
||||
# Calculate the delta
|
||||
delta_s = Time.now.utc.to_i - data['last_updated'].to_i
|
||||
data['last_updated'] = Time.now.utc
|
||||
|
||||
if (delta_s / 60) > afk_threshold
|
||||
File.write(CONFIG_PATH, YAML.dump(data))
|
||||
exit(0)
|
||||
end
|
||||
|
||||
time_spent = delta_s + data['overflow']
|
||||
precision_s = precision * 60
|
||||
minutes = (time_spent / precision_s)
|
||||
data['overflow'] = (time_spent % precision_s)
|
||||
File.write(CONFIG_PATH, YAML.dump(data))
|
||||
|
||||
exit(0) if minutes.zero?
|
||||
|
||||
uri = URI("#{jira_url}/rest/api/2/issue/#{ticket}/worklog")
|
||||
|
||||
request = Net::HTTP::Post.new(uri)
|
||||
request['Authorization'] = format('Bearer %s', jira_pat)
|
||||
request['Content-Type'] = 'application/json'
|
||||
request.body = JSON.generate({
|
||||
'timeSpent' => minutes,
|
||||
'comment' => comment
|
||||
})
|
||||
|
||||
Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_PEER) do |http|
|
||||
res = http.request(request)
|
||||
if res.is_a?(Net::HTTPSuccess)
|
||||
puts "Logged #{minutes} minutes to #{ticket}"
|
||||
else
|
||||
puts "Failed to log time to #{ticket}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'net/http'
|
||||
require 'json'
|
||||
require 'yaml'
|
||||
require 'date'
|
||||
|
||||
JIRA_REGEX = /([A-Z]+-\d+)/.freeze
|
||||
|
||||
def jira_url
|
||||
ENV.fetch('JIRA_URL', nil) ||
|
||||
(File.read('./.jira-url').chomp if File.exist?('./.jira-url')) ||
|
||||
(File.read("#{Dir.home}/.jira-url").chomp if File.exist?("#{Dir.home}/.jira-url")) ||
|
||||
nil
|
||||
end
|
||||
|
||||
def jira_pat
|
||||
(File.read('./.jira-pat').chomp if File.exist?('./.jira-pat')) ||
|
||||
(File.read("#{Dir.home}/.jira-pat").chomp if File.exist?("#{Dir.home}/.jira-pat")) ||
|
||||
nil
|
||||
end
|
||||
|
||||
def precision
|
||||
ENV.fetch('JIRA_AUTO_WORKLOG_PRECISION', 1).to_i
|
||||
end
|
||||
|
||||
unless jira_url
|
||||
puts 'JIRA URL not found.'
|
||||
puts
|
||||
puts 'Valid Locations are, in order of precedence:'
|
||||
puts ' 1. JIRA_URL environment variable'
|
||||
puts ' 2. ./.jira-url'
|
||||
puts ' 3. ~/.jira-url'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
unless jira_pat
|
||||
puts 'JIRA Personal Access Token not found.'
|
||||
puts
|
||||
puts 'Valid Locations are, in order of precedence:'
|
||||
puts ' 1. ./.jira-pat'
|
||||
puts ' 2. ~/.jira-pat'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
unless precision > 0
|
||||
puts 'Precision must be a positive integer.'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
uri = URI("#{jira_url}/rest/api/2/myself")
|
||||
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request['Authorization'] = format('Bearer %s', jira_pat)
|
||||
request['Content-Type'] = 'application/json'
|
||||
|
||||
Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_PEER) do |http|
|
||||
res = http.request(request)
|
||||
if res.is_a?(Net::HTTPSuccess)
|
||||
puts "Jira auto-worklog is configured correctly. Time will be logged."
|
||||
else
|
||||
puts "Jira auto-worklog is not configured correctly. Please check your JIRA URL and Personal Access Token."
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
# zle-line-init widget (don't redefine if already defined)
|
||||
(( ! ${+functions[_jira-auto-worklog_zle-line-init]} )) || return 0
|
||||
|
||||
# Get the directory of this file
|
||||
dir="$(dirname "$0")"
|
||||
|
||||
case "$widgets[zle-line-init]" in
|
||||
# Simply define the function if zle-line-init doesn't yet exist
|
||||
builtin|"") function _jira-auto-worklog_zle-line-init() {
|
||||
($dir/jira-auto-worklog &> /dev/null)
|
||||
} ;;
|
||||
# Override the current zle-line-init widget, calling the old one
|
||||
user:*) zle -N _jira-auto-worklog_orig_zle-line-init "${widgets[zle-line-init]#user:}"
|
||||
function _jira-auto-worklog_zle-line-init() {
|
||||
($dir/jira-auto-worklog &> /dev/null)
|
||||
zle _jira-auto-worklog_orig_zle-line-init -- "$@"
|
||||
} ;;
|
||||
esac
|
||||
|
||||
zle -N zle-line-init _jira-auto-worklog_zle-line-init
|
|
@ -0,0 +1,89 @@
|
|||
# jj - Jujutsu CLI
|
||||
|
||||
This plugin provides autocompletion for [jj](https://martinvonz.github.io/jj).
|
||||
|
||||
To use it, add `jj` to the plugins array of your zshrc file:
|
||||
|
||||
```zsh
|
||||
plugins=(... jj)
|
||||
```
|
||||
|
||||
## Aliases
|
||||
|
||||
| Alias | Command |
|
||||
| ------ | ----------------------------- |
|
||||
| jjc | `jj commit` |
|
||||
| jjcmsg | `jj commit --message` |
|
||||
| jjd | `jj diff` |
|
||||
| jjdmsg | `jj desc --message` |
|
||||
| jjds | `jj desc` |
|
||||
| jje | `jj edit` |
|
||||
| jjgcl | `jj git clone` |
|
||||
| jjgf | `jj git fetch` |
|
||||
| jjgp | `jj git push` |
|
||||
| jjl | `jj log` |
|
||||
| jjla | `jj log -r "all()"` |
|
||||
| jjn | `jj new` |
|
||||
| jjrb | `jj rebase` |
|
||||
| jjrs | `jj restore` |
|
||||
| jjrt | `cd "$(jj root \|\| echo .)"` |
|
||||
| jjsp | `jj split` |
|
||||
| jjsq | `jj squash` |
|
||||
|
||||
## Prompt usage
|
||||
|
||||
Because `jj` has a very powerful [template syntax](https://martinvonz.github.io/jj/latest/templates/), this
|
||||
plugin only exposes a convenience function `jj_prompt_template` to read information from the current change.
|
||||
It is basically the same as `jj log --no-graph -r @ -T $1`:
|
||||
|
||||
```sh
|
||||
_my_theme_jj_info() {
|
||||
jj_prompt_template 'self.change_id().shortest(3)'
|
||||
}
|
||||
|
||||
PROMPT='$(_my_theme_jj_info) $'
|
||||
```
|
||||
|
||||
`jj_prompt_template` escapes `%` signs in the output. Use `jj_prompt_template_raw` if you don't want that
|
||||
(e.g. to colorize the output).
|
||||
|
||||
However, because `jj` can be used inside a Git repository, some themes might clash with it. Generally, you can
|
||||
fix it with a wrapper function that tries `jj` first and then falls back to `git` if it didn't work:
|
||||
|
||||
```sh
|
||||
_my_theme_vcs_info() {
|
||||
jj_prompt_template 'self.change_id().shortest(3)' \
|
||||
|| git_prompt_info
|
||||
}
|
||||
|
||||
PROMPT='$(_my_theme_vcs_info) $'
|
||||
```
|
||||
|
||||
You can find an example
|
||||
[here](https://github.com/nasso/omzsh/blob/e439e494f22f4fd4ef1b6cb64626255f4b341c1b/themes/sunakayu.zsh-theme).
|
||||
|
||||
### Performance
|
||||
|
||||
Sometimes `jj` can be slower than `git`.
|
||||
|
||||
If you feel slowdowns, consider using the following:
|
||||
|
||||
```
|
||||
zstyle :omz:plugins:jj ignore-working-copy yes
|
||||
```
|
||||
|
||||
This will add `--ignore-working-copy` to all `jj` commands executed by your prompt. The downside here is that
|
||||
your prompt might be out-of-sync until the next time `jj` gets a chance to _not_ ignore the working copy (i.e.
|
||||
you manually run a `jj` command).
|
||||
|
||||
If you prefer to keep your prompt always up-to-date but still don't want to _feel_ the slowdown, you can make
|
||||
your prompt asynchronous. This plugin doesn't do this automatically so you'd have to hack your theme a bit for
|
||||
that.
|
||||
|
||||
## See Also
|
||||
|
||||
- [martinvonz/jj](https://github.com/martinvonz/jj)
|
||||
|
||||
## Contributors
|
||||
|
||||
- [nasso](https://github.com/nasso) - Plugin Author
|
|
@ -0,0 +1,53 @@
|
|||
# if jj is not found, don't do the rest of the script
|
||||
if (( ! $+commands[jj] )); then
|
||||
return
|
||||
fi
|
||||
|
||||
# If the completion file doesn't exist yet, we need to autoload it and
|
||||
# bind it to `jj`. Otherwise, compinit will have already done that.
|
||||
if [[ ! -f "$ZSH_CACHE_DIR/completions/_jj" ]]; then
|
||||
typeset -g -A _comps
|
||||
autoload -Uz _jj
|
||||
_comps[jj]=_jj
|
||||
fi
|
||||
|
||||
jj util completion zsh >| "$ZSH_CACHE_DIR/completions/_jj" &|
|
||||
|
||||
function __jj_prompt_jj() {
|
||||
local -a flags
|
||||
flags=("--no-pager")
|
||||
if zstyle -t ':omz:plugins:jj' ignore-working-copy; then
|
||||
flags+=("--ignore-working-copy")
|
||||
fi
|
||||
command jj $flags "$@"
|
||||
}
|
||||
|
||||
# convenience functions for themes
|
||||
function jj_prompt_template_raw() {
|
||||
__jj_prompt_jj log --no-graph -r @ -T "$@" 2> /dev/null
|
||||
}
|
||||
|
||||
function jj_prompt_template() {
|
||||
local out
|
||||
out=$(jj_prompt_template_raw "$@") || return 1
|
||||
echo "${out:gs/%/%%}"
|
||||
}
|
||||
|
||||
# Aliases (sorted alphabetically)
|
||||
alias jjc='jj commit'
|
||||
alias jjcmsg='jj commit --message'
|
||||
alias jjd='jj diff'
|
||||
alias jjdmsg='jj desc --message'
|
||||
alias jjds='jj desc'
|
||||
alias jje='jj edit'
|
||||
alias jjgcl='jj git clone'
|
||||
alias jjgf='jj git fetch'
|
||||
alias jjgp='jj git push'
|
||||
alias jjl='jj log'
|
||||
alias jjla='jj log -r "all()"'
|
||||
alias jjn='jj new'
|
||||
alias jjrb='jj rebase'
|
||||
alias jjrs='jj restore'
|
||||
alias jjrt='cd "$(jj root || echo .)"'
|
||||
alias jjsp='jj split'
|
||||
alias jjsq='jj squash'
|
Loading…
Reference in New Issue