From: Andrew Chilton Date: Wed, 18 Jun 2008 12:45:10 +0000 (+1200) Subject: Update almost everything to a newer format, both internally and externally. X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=8e70aba75127398cbe485562e15c15abb562cd0e;p=cil.git Update almost everything to a newer format, both internally and externally. --- diff --git a/bin/cil b/bin/cil index edaff38..af6a9fc 100755 --- a/bin/cil +++ b/bin/cil @@ -19,12 +19,14 @@ use strict; use warnings; -use CIL::Issue; -use CIL::Comment; -use Term::CallEditor; + +use Digest::MD5 qw(md5_hex); use File::Touch; use File::Glob ':glob'; use File::Basename; +use Term::CallEditor qw(solicit); +use CIL::Issue; +use CIL::Comment; my $COMMANDS = { init => 1, @@ -40,23 +42,19 @@ my $gan = $ENV{GIT_AUTHOR_NAME} || 'Your Name'; my $gae = $ENV{GIT_AUTHOR_EMAIL} || 'you@example.org'; my $new_issue_text = <<"EOF"; -[Issue] -Summary = -Status =New -CreatedBy =$gan <$gae> -AssignedTo =$gan <$gae> -Labels = -Description = < +AssignedTo : $gan <$gae> +Label : -END_OF_DESCRIPTION +Description... EOF my $add_comment_text = <<"EOF"; -[Comment] -CreatedBy = $gan <$gae> -Description = < -END_OF_DESCRIPTION +Description... EOF ## ---------------------------------------------------------------------------- @@ -191,19 +189,11 @@ sub add { # read in the new issue text my $fh = solicit( $new_issue_text ); - my $issue; - eval { - $issue = CIL::Issue->new_parse_issue( $fh ); - }; - if ( $@ ) { - fatal("couldn't parse issue: $@"); - } - unless ( defined $issue ) { - fatal("couldn't parse issue (program error)"); - } + my $issue = CIL::Issue->new_from_fh( 'tmp', $fh ); - $issue->inserted; - $issue->set_no_update( 'Name', $issue->Inserted ); + # we've got the issue, so let's name it + my $unique_str = $issue->Inserted . $issue->Summary . $issue->Description; + $issue->set_name( substr(md5_hex($unique_str), 0, 8) ); $issue->save(); display_issue_full( $issue ); } @@ -220,7 +210,7 @@ sub edit { my $status = $issue->Status; my $created_by = $issue->CreatedBy; my $assigned_to = $issue->AssignedTo; - my $labels = $issue->Labels; + my $label = $issue->Label; my $description = $issue->Description; # create the ini file, then edit it @@ -231,7 +221,7 @@ Summary = $summary Status = $status CreatedBy = $created_by AssignedTo = $assigned_to -Labels = $labels +Label = $label Description = <name); field( 'Summary', $issue->Summary() ); - field( 'Name', $issue->Name() ); field( 'Status', $issue->Status() ); field( 'CreatedBy', $issue->CreatedBy() ); field( 'AssignedTo', $issue->AssignedTo() ); field( 'Inserted', $issue->Inserted() ); field( 'Updated', $issue->Inserted() ); - field( 'Labels', $issue->Labels() ); + field( 'Label', $issue->Label() ); separator(); text('Description', $issue->Description()); - my $comments = $issue->comments(); - foreach my $comment ( @$comments ) { - separator(); - title('Comment'); - field( 'CreatedBy', $comment->CreatedBy() ); - field( 'Inserted', $comment->Inserted() ); - field( 'Updated', $comment->Inserted() ); - text('Description', $comment->Description()); - } separator(); } diff --git a/issues/1209990028.yaml b/issues/1209990028.yaml deleted file mode 100644 index 611da61..0000000 --- a/issues/1209990028.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -AssignedTo: 'Andrew Chilton ' -CreatedBy: 'Andrew Chilton ' -Description: |- - 'cil' currently has no way of adding attachments to issues. - - This should be added so that the actual data cil stores is complete. -Inserted: 1209990028 -Labels: against-v0.1 type-enhancement priority-medium -Name: 1209990028 -Status: New -Summary: Addition of a 'attach' command -Updated: 1209991365 diff --git a/issues/1209990558.yaml b/issues/1209990558.yaml deleted file mode 100644 index 30e50bb..0000000 --- a/issues/1209990558.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -AssignedTo: 'Andrew Chilton ' -CreatedBy: 'Andrew Chilton ' -Description: |- - When issues are created, they are given the epoch as it's name. - Instead of just using the epoch, the user should be able to configure - the .cil file to use the format of their choice. - - e.g. issue_name_format=[ epoch | inc | iso-8601 ] - - Possible name formats include: - - * an incrementing number - * but if cil goes distributed (which was originally planned), will - this work? - - * ISO 8601 - YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) - * do we need to have TZD on the end (though obviously this wouldn't - then be ISO 8601) - - * GUID/UUID like 9e28b50a-cba1-4b20-9276-d30ee727b14a - - (and maybe others) -Inserted: 1209990558 -Labels: against-v0.1 type-enhancement priority-low -Name: 1209990558 -Status: New -Summary: Options for issues names needs to be added -Updated: 1209990799 diff --git a/issues/1209991618.yaml b/issues/1209991618.yaml deleted file mode 100644 index 3599d18..0000000 --- a/issues/1209991618.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -AssignedTo: 'Andrew Chilton ' -CreatedBy: 'Andrew Chilton ' -Description: |- - For example, if there is a config item in .cil called - 'allowed_statuses', all input values in the 'Status' field should be - checked against it. - - This could also be done for Labels too. -Inserted: 1209991618 -Labels: against-v0.1 type-enhancement priority-medium -Name: 1209991618 -Status: New -Summary: Do checking on input fields after adding or editing issue -Updated: 1209991718 diff --git a/issues/1209992018.yaml b/issues/1209992018.yaml deleted file mode 100644 index f2a3fe9..0000000 --- a/issues/1209992018.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -AssignedTo: 'Andrew Chilton ' -CreatedBy: 'Andrew Chilton ' -Description: |- - In the .cil config file, there should a field which determines a - 'required' set of labels. - - e.g. - - required_labels=against type priority -Inserted: 1209992018 -Labels: against-v0.1 type-enhancement priority-medium -Name: 1209992018 -Status: New -Summary: Labels should be allowed to have a 'required' set -Updated: 1209992018 diff --git a/issues/i_1209990028.cil b/issues/i_1209990028.cil new file mode 100644 index 0000000..05cd80f --- /dev/null +++ b/issues/i_1209990028.cil @@ -0,0 +1,14 @@ +Name: 1209990028 +Summary: Addition of a 'attach' command +Status: New +CreatedBy: Andrew Chilton +Inserted: 1209990028 +AssignedTo: Andrew Chilton +Updated: 1209991365 +Label: against-v0.1 +Label: priority-medium +Label: type-enhancement + +'cil' currently has no way of adding attachments to issues. + +This should be added so that the actual data cil stores is complete. diff --git a/issues/i_1209990558.cil b/issues/i_1209990558.cil new file mode 100644 index 0000000..4b786a8 --- /dev/null +++ b/issues/i_1209990558.cil @@ -0,0 +1,30 @@ +Name: 1209990558 +Summary: Options for issues names needs to be added +Status: New +CreatedBy: Andrew Chilton +Inserted: 1209990558 +AssignedTo: Andrew Chilton +Updated: 1209990799 +Label: against-v0.1 +Label: priority-low +Label: type-enhancement + +When issues are created, they are given the epoch as it's name. +Instead of just using the epoch, the user should be able to configure +the .cil file to use the format of their choice. + +e.g. issue_name_format=[ epoch | inc | iso-8601 ] + +Possible name formats include: + +* an incrementing number + * but if cil goes distributed (which was originally planned), will + this work? + +* ISO 8601 - YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) + * do we need to have TZD on the end (though obviously this wouldn't + then be ISO 8601) + +* GUID/UUID like 9e28b50a-cba1-4b20-9276-d30ee727b14a + +(and maybe others) diff --git a/issues/i_1209991618.cil b/issues/i_1209991618.cil new file mode 100644 index 0000000..afcc16b --- /dev/null +++ b/issues/i_1209991618.cil @@ -0,0 +1,16 @@ +Name: 1209991618 +Summary: Do checking on input fields after adding or editing issue +Status: New +CreatedBy: Andrew Chilton +Inserted: 1209991618 +AssignedTo: Andrew Chilton +Updated: 1209991718 +Label: against-v0.1 +Label: priority-medium +Label: type-enhancement + +For example, if there is a config item in .cil called +'allowed_statuses', all input values in the 'Status' field should be +checked against it. + +This could also be done for Labels too. diff --git a/issues/i_1209992018.cil b/issues/i_1209992018.cil new file mode 100644 index 0000000..66c1f0a --- /dev/null +++ b/issues/i_1209992018.cil @@ -0,0 +1,17 @@ +Name: 1209992018 +Summary: Labels should be allowed to have a 'required' set +Status: New +CreatedBy: Andrew Chilton +Inserted: 1209992018 +AssignedTo: Andrew Chilton +Updated: 1209992018 +Label: against-v0.1 +Label: priority-medium +Label: type-enhancement + +In the .cil config file, there should a field which determines a +'required' set of labels. + +e.g. + +required_labels=against type priority diff --git a/lib/CIL/Base.pm b/lib/CIL/Base.pm index bfa21fc..db1ba62 100644 --- a/lib/CIL/Base.pm +++ b/lib/CIL/Base.pm @@ -29,53 +29,56 @@ use DateTime; use base qw(Class::Accessor); __PACKAGE__->mk_accessors(qw(CreatedBy Inserted Updated Description)); +# override Class::Accessor's get +sub get { + my ($self, $field) = @_; + croak "provide a field name" + unless defined $field; + $self->{data}{$field}; +} + # override Class::Accessor's set sub set { - my ($self, $key, $value) = @_; - croak "provide a key name" unless defined $key; + my ($self, $field, $value) = @_; + croak "provide a field name" + unless defined $field; - my $orig = $self->get($key); + my $orig = $self->get($field); - # get out if both are defined and they're the same + # finish if both are defined and they're the same if ( defined $orig and defined $value ) { return if $orig eq $value } - # get out if neither are defined - if ( !defined $orig and !defined $value ) { - return; - } + # finish if neither are defined + return unless ( defined $orig or defined $value ); - # since we're actually changing the key, say we updated something - $self->{data}{$key} = $value; - $self->updated; + # since we're actually changing the field, say we updated something + $self->{data}{$field} = $value; + $self->set_updated; } +# so that we can update fields without 'Updated' being changed sub set_no_update { - my ($self, $key, $value) = @_; - croak "provide a key name" unless defined $key; - $self->{data}{$key} = $value; -} - -# override Class::Accessor's get -sub get { - my ($self, $key) = @_; - $self->{data}{$key}; + my ($self, $field, $value) = @_; + croak "provide a field name" + unless defined $field; + $self->{data}{$field} = $value; } -sub inserted { +sub flag_inserted { my ($self) = @_; - my $time = time; + my $time = DateTime->now; $self->{data}{Inserted} = $time; $self->{data}{Updated} = $time; - $self->{Changed} = '1'; + $self->{Changed} = 1; } -sub updated { +sub flag_as_updated { my ($self) = @_; - my $time = time; + my $time = DateTime->now; $self->{data}{Updated} = $time; - $self->{Changed} = '1'; + $self->{Changed} = 1; } sub changed { diff --git a/lib/CIL/Issue.pm b/lib/CIL/Issue.pm index 84b86ee..695210d 100644 --- a/lib/CIL/Issue.pm +++ b/lib/CIL/Issue.pm @@ -24,91 +24,99 @@ package CIL::Issue; use strict; use warnings; use Carp; -use Data::Dumper; use Config::IniFiles; use YAML qw(LoadFile DumpFile); +use CIL::Utils; + use base qw(CIL::Base); -__PACKAGE__->mk_accessors(qw(Name Summary AssignedTo Status Labels Comments)); +__PACKAGE__->mk_accessors(qw(Summary Status AssignedTo Label Comment Attachment)); -my @FIELDS = ( qw(Name Summary Description CreatedBy AssignedTo Status Labels Comments) ); +my @FIELDS = ( qw(Summary Status CreatedBy AssignedTo Label Comment Attachment Inserted Updated Description) ); ## ---------------------------------------------------------------------------- sub new { - my ($proto) = @_; + my ($proto, $name) = @_; + + croak 'please provide an issue name' + unless defined $name; + my $class = ref $proto || $proto; my $self = {}; - $self->{data} = {}; - $self->{Changed} = 0; bless $self, $class; - $self->inserted; + + $self->set_name( $name ); + $self->{data} = { + Summary => '', + Status => '', + CreatedBy => '', + AssignedTo => '', + Label => [], + Comment => [], + Attachment => [], + }; + $self->{Changed} = 0; + + $self->flag_inserted; + return $self; } -sub new_load_issue { - my ($class, $name) = @_; +sub new_from_data { + my ($class, $name, $data) = @_; - unless ( defined $name ) { - croak "provide an issue name to load"; - } + croak 'please provide an issue name' + unless defined $name; - my $filename = "issues/$name.yaml"; - unless ( -f $filename ) { - croak "filename '$filename' does no exist"; - } + # ToDo: check we have all the other correct fields - my $data = LoadFile( $filename ); + # create the issue + my $self = $class->new( $name ); - my $issue = CIL::Issue->new(); + # save each field + foreach my $field ( @FIELDS ) { + next unless defined $data->{$field}; - # do the issue - foreach my $field ( qw(Summary Name Description CreatedBy AssignedTo Status Labels Inserted Updated) ) { # modify the data directly, otherwise Updated will kick in - $issue->{data}{$field} = $data->{$field}; - } - - # now the comments - foreach my $c ( @{$data->{comments}} ) { - my $comment = CIL::Comment->new(); - foreach my $field ( qw(CreatedBy Inserted Updated Description) ) { - # modify the data directly, otherwise Updated will kick in - $comment->set_no_update($field, $c->{$field}); - } - push @{$issue->{comments}}, $comment; + $self->set_no_update($field, $data->{$field}); } - $issue->{data}{Name} = $name; + $self->set_no_update('Changed', 0); - return $issue; + return $self; } -sub new_parse_issue { - my ($class, $file) = @_; +sub new_from_fh { + my ($class, $name, $fh) = @_; - # $file may be a string ($filename) or a file handle ($fh) - my $cfg = Config::IniFiles->new( -file => $file ); + croak 'please provide an issue name' + unless defined $name; - unless ( defined $cfg ) { - croak("not a valid inifile"); - } + my $data = CIL::Utils->parse_from_fh( $fh, 'Description' ); + return $class->new_from_data( $name, $data ); +} - my $issue = CIL::Issue->new(); - foreach my $field ( qw(Summary Name Description CreatedBy AssignedTo Status Labels Inserted Updated) ) { - # modify the data directly, otherwise Updated will kick in - my $value = $cfg->val( 'Issue', $field ); - next unless defined $value; +sub set_name { + my ($self, $name) = @_; - $value =~ s/^\s*//; - $value =~ s/\s*$//; - $issue->set_no_update($field, $value); - } - $issue->set_no_update('Comments', []); - return $issue; + croak 'provide a name' + unless defined $name; + + $self->{name} = $name; } -sub comments { +sub name { my ($self) = @_; - return $self->{comments}; + return $self->{name}; +} + +sub add_label { + my ($self, $label) = @_; + + croak 'provide a label when adding one' + unless defined $label; + + push @{$self->{data}{Label}}, $label; } sub add_comment { @@ -117,27 +125,39 @@ sub add_comment { croak "can only add comments of type CIL::Comment" unless ref $comment eq 'CIL::Comment'; - push @{$self->{comments}}, $comment; + push @{$self->{data}{Comment}}, $comment->name; } -sub save { - my ($self) = @_; - my $name = $self->Name; - my $filename = "issues/$name.yaml"; - my $data = {}; - %$data = ( %{$self->{data}}); - foreach my $comment ( @{$self->{comments}} ) { - push @{$data->{comments}}, $comment->{data}; - } - DumpFile($filename, $data); +sub add_attachment { + my ($self, $attachment) = @_; + + croak "can only add comments of type CIL::Attachment" + unless ref $attachment eq 'CIL::Attachment'; + + push @{$self->{data}{Attachment}}, $attachment->name; } -sub reset { - my ($self) = @_; +sub load { + my ($class, $name) = @_; - foreach my $field ( @FIELDS ) { - delete $self->{$field}; - } + croak 'provide an issue name to load' + unless defined $name; + + my $filename = "issues/$name.cil"; + + croak "filename '$filename' does no exist" + unless -f $filename; + + my $data = CIL::Utils->parse_cil_file($filename, 'Description'); + my $issue = CIL::Issue->new_from_data( $name, $data ); + return $issue; +} + +sub save { + my ($self) = @_; + my $name = $self->name; + my $filename = "issues/i_$name.cil"; + CIL::Utils->write_cil_file( $filename, $self->{data}, @FIELDS ); } ## ---------------------------------------------------------------------------- diff --git a/lib/CIL/Utils.pm b/lib/CIL/Utils.pm new file mode 100644 index 0000000..c4841ae --- /dev/null +++ b/lib/CIL/Utils.pm @@ -0,0 +1,102 @@ +## ---------------------------------------------------------------------------- +# cil is a Command line Issue List +# Copyright (C) 2008 Andrew Chilton +# +# This file is part of 'cil'. +# +# cil is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# +## ---------------------------------------------------------------------------- + +package CIL::Utils; + +use strict; +use warnings; +use File::Slurp; + +sub parse_cil_file { + my ($class, $filename, $last_field) = @_; + + my @lines = read_file($filename); + return unless @lines; + + return $class->parse_from_lines( $last_field, @lines ); +} + +sub parse_from_fh { + my ($class, $fh, $last_field) = @_; + + my @lines = <$fh>; + return unless @lines; + + return $class->parse_from_lines( $last_field, @lines ); +} + +sub parse_from_lines { + my ($class, $last_field, @lines) = @_; + return unless @lines; + chomp @lines; + + my $data = {}; + + # read all the initial fields + while ( my $line = shift @lines ) { + my ($key, $value) = split(/\s*:\s*/, $line, 2); + + if ( defined $data->{$key} ) { + unless ( ref $data->{$key} eq 'ARRAY' ) { + $data->{$key} = [ $data->{$key} ]; + }; + push @{$data->{$key}}, $value; + } + else { + $data->{$key} = $value; + } + } + + # now read everything that's left into the $last_field field + $data->{$last_field} = join("\n", @lines); + + return $data; +} + +sub write_cil_file { + my ($class, $filename, $data, @fields) = @_; + + my $last_field = pop @fields; + + my @lines; + + foreach my $field ( @fields ) { + next if $field eq $last_field; + + if ( ref $data->{$field} eq 'ARRAY' ) { + foreach ( sort @{$data->{$field}} ) { + push @lines, "$field: $_\n"; + } + } + else { + push @lines, "$field: $data->{$field}\n"; + } + } + + push @lines, "\n"; + push @lines, $data->{$last_field}, "\n"; + + write_file($filename, \@lines); +} + +## ---------------------------------------------------------------------------- +1; +## ---------------------------------------------------------------------------- diff --git a/t/00_files.t b/t/00_files.t new file mode 100644 index 0000000..b000c56 --- /dev/null +++ b/t/00_files.t @@ -0,0 +1,33 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Test::More qw(no_plan); +use Data::Dumper; +use CIL::Utils; + +my $parsed_fields = CIL::Utils->parse_cil_file( 't/i_cafebabe.cil', 'Description' ); + +my $correct_fields = { + 'Summary' => 'Addition of a \'attach\' command', + 'Status' => 'New', + 'CreatedBy' => 'A N Other ', + 'AssignedTo' => 'A Name ', + 'Label' => [ + 'against-v0.1', + 'priority-medium', + 'type-enhancement', + ], + 'Inserted' => '2008-06-15 18:22:01', + 'Updated' => '2008-06-15 23:15:27', + 'Description' => '\'cil\' currently has no way of adding attachments to issues. + +This should be added so that the actual data cil stores is complete.' +}; + +is_deeply($parsed_fields, $correct_fields, 'Check parsing of file'); + +CIL::Utils->write_cil_file( '/tmp/i_deadbeef.cil', $correct_fields, qw(Summary Status CreatedBy AssignedTo Label Inserted Updated Description) ); +CIL::Utils->write_cil_file( '/tmp/i_decaf7ea.cil', $parsed_fields, qw(Summary Status CreatedBy AssignedTo Label Inserted Updated Description) ); + +# is($parsed_fields, $correct_fields, 'Check parsing of file'); diff --git a/t/i_cafebabe.cil b/t/i_cafebabe.cil new file mode 100644 index 0000000..04aeb0c --- /dev/null +++ b/t/i_cafebabe.cil @@ -0,0 +1,13 @@ +Summary: Addition of a 'attach' command +Status: New +CreatedBy: A N Other +AssignedTo: A Name +Label: against-v0.1 +Label: priority-medium +Label: type-enhancement +Inserted: 2008-06-15 18:22:01 +Updated: 2008-06-15 23:15:27 + +'cil' currently has no way of adding attachments to issues. + +This should be added so that the actual data cil stores is complete.