From 31cb850c04873e29ad1ff5a5d5255283827907b2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 27 Sep 2016 06:42:36 +0200 Subject: Implement update script --- README | 14 ++++-- README.cli | 19 ++++--- update | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 12 deletions(-) create mode 100755 update diff --git a/README b/README index b084a49..5ee7acf 100644 --- a/README +++ b/README @@ -85,9 +85,9 @@ infrastructure). Further, labels can be used to group notes based on certain criteria. For example, doc (documentation issue), windows (Windows-specific), 2.0.0 (scheduled for the 2.0.0 release), john (assigned to John). The names of -subdirectories in which the issue is located are also considered its labels. -So, for example, if the above "Detect empty name" bug was filed in -lihello/format/, then its labels would be bug, format, and libhello. +subdirectories in which the note is located are also considered its labels. So, +for example, if the above "Detect empty name" bug was filed in lihello/format/, +then its labels would be bug, format, and libhello. The body of a note is free-form. However, for clarity, it makes sense to avoid using '-' for lists in the body ('*' for the first level and '~' for the second @@ -158,8 +158,8 @@ For example: Add bug: Detect empty name -If you only have a single issue added in the database then you can use the add -script to automate it. This script will commit the new issues with the correct +If you only have a single note added in the database then you can use the add +script to automate this. This script will commit the new note with the correct message and, unless the -c option is specified, push the result to origin. This should make filing new notes a fairly burdenless process: write a note using your favorite text editor and run the add script. Note that the add script @@ -174,6 +174,10 @@ For example: Update idea: Implement pluggable formatter +Similar to adding, if you only have a single note updated in the database then +you can use the update script to automate this. Note that the update script +currently cannot handle updates with extra files. + Once a note is acted upon (implemented or you have decided not to do anything about it), you can either delete it or move it to the reference. Simply deleting a note is appropriate for simple bugs and features where all the diff --git a/README.cli b/README.cli index 2ca9e55..d61e868 100644 --- a/README.cli +++ b/README.cli @@ -107,7 +107,7 @@ a new feature), \c{quality} (improve quality of implementation), \c{infra} Further, labels can be used to group notes based on certain criteria. For example, \c{doc} (documentation issue), \c{windows} (Windows-specific), \c{2.0.0} (scheduled for the 2.0.0 release), \c{john} (assigned to John). The -names of subdirectories in which the issue is located are also considered its +names of subdirectories in which the note is located are also considered its labels. So, for example, if the above \"Detect empty name\" bug was filed in \c{lihello/format/}, then its labels would be \c{bug}, \c{format}, and \c{libhello}. @@ -189,12 +189,13 @@ For example: Add bug: Detect empty name \ -If you only have a single issue added in the database then you can use the -\c{add} script to automate it. This script will commit the new issues with the -correct message and, unless the \c{-c} option is specified, push the result to -\c{origin}. This should make filing new notes a fairly burdenless process: -write a note using your favorite text editor and run the \c{add} script. Note -that the \c{add} script currently cannot handle notes with extra files. +If you only have a single note added in the database then you can use the +\c{add} script to automate this. This script will commit the new note with +the correct message and, unless the \c{-c} option is specified, push the +result to \c{origin}. This should make filing new notes a fairly burdenless +process: write a note using your favorite text editor and run the \c{add} +script. Note that the \c{add} script currently cannot handle notes with extra +files. If you change an existing note (for example, add additional information), then the commit message should have the following form: @@ -209,6 +210,10 @@ For example: Update idea: Implement pluggable formatter \ +Similar to adding, if you only have a single note updated in the database then +you can use the \c{update} script to automate this. Note that the \c{update} +script currently cannot handle updates with extra files. + Once a note is acted upon (implemented or you have decided not to do anything about it), you can either delete it or move it to the reference. Simply deleting a note is appropriate for simple bugs and features where all the diff --git a/update b/update new file mode 100755 index 0000000..fc2ba54 --- /dev/null +++ b/update @@ -0,0 +1,164 @@ +#! /usr/bin/env bash + +# Commit and push an update to an existing note. +# +# -c +# Commit only, don't push. +# +usage="usage: $0 [-c]" + +owd=`pwd` +trap "{ cd $owd; exit 1; }" ERR +set -o errtrace # Trap in functions. + +function info () { echo "$*" 1>&2; } +function error () { info "$*"; exit 1; } + +push="y" + +while [ $# -gt 0 ]; do + case $1 in + -c) + push="n" + shift + ;; + *) + error "$usage" + ;; + esac +done + +if git status --porcelain | grep -q '^M '; then + error "error: repository already has staged changes" +fi + +# @@ We could probably handle the case where extra files are added to the +# note. We just need to make sure they are not changes to other notes. +# +if git status --porcelain | grep -q '^?? '; then + error "error: repository has untracked files" +fi + +modified="$(git status --porcelain | sed -n -e 's/^ M \(.*\)/\1/p')" + +mc="$(echo "$modified" | wc -w)" + +if [ "$mc" -eq 0 ]; then + error "error: nothing modified" +fi + +if [ "$mc" -gt 1 ]; then + error "error: multiple modified files" +fi + +# Extract the start line and count from the changeset header. +# +# The format is: +# +# @@ [+-]FROM-START,FROM-COUNT [+-]TO-START,TO-COUNT @@ +# +# Note that if the changeset has only one line then the count is omitted. +# +function changeset_start () +{ + echo "$1" | sed -e 's/^@@ [^ ]* [+-]\([^, ]*\).*$/\1/' +} + +function changeset_count () +{ + local r + r="$(echo "$1" | sed -n -e 's/^@@ [^ ]* [+-][^,]*,\([^ ]*\) @@$/\1/p')" + if [ -z "$r" ]; then + r="1" + fi + echo "$r" +} + +#changeset_start "@@ -12,3 +13,11 @@" +#changeset_count "@@ -12,3 +13,11 @@" +#changeset_start "@@ -12 +13 @@" +#changeset_count "@@ -12 +13 @@" + +h= +if [ "$(basename "$modified")" = "list" ]; then + # + # This is a list of notes. The plan is to get the start line numbers for the + # first and last change set. We then scan the list line by line looking for + # headers until we hit the start of the first change set: the last header + # that we see should be our header. We also continue scanning until we hit + # the end of the last changeset: if we see any headers then we are updating + # multiple notes. + # + + # Get the diff output as a list of change set headers. + # + diff="$(git diff -U0 | sed -n -e '/^@@ /p')" + + fc="$(echo "$diff" | head -n 1)" + lc="$(echo "$diff" | tail -n 1)" + + sl="$(changeset_start "$fc")" + el="$(($(changeset_start "$lc") + $(changeset_count "$lc") - 1))" + + # Scan the list looking for headers. + # + l= + c="0" + while read l || [ -n "$l" ]; do + + # Stop if we are past the end line. + # + c="$(($c + 1))" + if [ "$c" -gt "$el" ]; then + break + fi + + # See if this is a header. + # + if echo "$l" | grep -q '^[-?!] '; then + + # If we are past the start line then we are modifying multiple notes. + # + if [ "$c" -gt "$sl" ]; then + error "error: multiple modified notes in $modified:${sl}-${el}" + fi + + # This is the last header. + # + h="$l" + fi + done < <(cat "$modified") + + if [ -z "$h" ]; then + error "error: unable to find note header for $modified:${sl}-${el}" + fi +else + # This is a file note. All we need to do is get its header (the first line). + # + h="$(head -n 1 "$modified")" +fi + +# Header should start with one of [-?!]. +# +sum="$(echo "$h" | sed -n -re 's/^[-?!] ([^[]*)( \[.*\])?$/\1/p')" + +if [ -z "$sum" ]; then + error "error: unable to parse note header '$h'" +fi + +# By convention the first label is a note type (bug, feature, etc). +# +type="$(echo "$h" | sed -n -re 's/^[^[]*\[([^ ]*).*\]$/\1/p')" + +if [ -z "$type" ]; then + error "error: note header does not include note type as first label" +fi + +# Ok, all looks good so add, commit and push the change. +# +git add "$modified" +git ci -m "Update $type: $sum" + +if [ "$push" = "y" ]; then + git push +fi -- cgit v1.1