summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CIL.pm100
-rw-r--r--lib/CIL/Base.pm47
-rw-r--r--lib/CIL/Comment.pm8
-rw-r--r--lib/CIL/Issue.pm63
-rw-r--r--lib/CIL/Utils.pm23
5 files changed, 224 insertions, 17 deletions
diff --git a/lib/CIL.pm b/lib/CIL.pm
index b85f2fb..e2be890 100644
--- a/lib/CIL.pm
+++ b/lib/CIL.pm
@@ -26,12 +26,20 @@ use warnings;
use File::Glob qw(:glob);
use base qw(Class::Accessor);
-__PACKAGE__->mk_accessors(qw(issue_dir));
+__PACKAGE__->mk_accessors(qw(
+ IssueDir
+ StatusStrict StatusAllowed StatusOpen StatusClosed
+ LabelStrict LabelAllowed
+));
my $defaults = {
- issue_dir => 'issues',
+ IssueDir => 'issues', # the dir to save the issues in
+ StatusStrict => 0, # whether to complain if a status is invalid
+ LabelStrict => 0, # whether to complain if a label is invalid
};
+my @config_hashes = qw(StatusAllowed StatusOpen StatusClosed LabelAllowed);
+
## ----------------------------------------------------------------------------
sub new {
@@ -50,21 +58,39 @@ sub new {
return $self;
}
-sub list_issues {
- my ($self) = @_;
+sub list_entities {
+ my ($self, $prefix) = @_;
- my $globpath = $self->issue_dir . "/i_*.cil";
+ my $globpath = $self->IssueDir . "/${prefix}_*.cil";
my @filenames = bsd_glob($globpath);
- my @issues;
+ my @entities;
foreach my $filename ( sort @filenames ) {
- my ($name) = $filename =~ m{/i_(.*)\.cil$}xms;
- push @issues, {
+ my ($name) = $filename =~ m{/${prefix}_(.*)\.cil$}xms;
+ push @entities, {
name => $name,
filename => $filename,
};
}
- return \@issues;
+ return \@entities;
+}
+
+sub list_issues {
+ my ($self) = @_;
+
+ return $self->list_entities('i');
+}
+
+sub list_comments {
+ my ($self) = @_;
+
+ return $self->list_entities('c');
+}
+
+sub list_attachments {
+ my ($self) = @_;
+
+ return $self->list_entities('a');
}
sub get_issues {
@@ -79,6 +105,30 @@ sub get_issues {
return \@issues;
}
+sub get_comments {
+ my ($self) = @_;
+
+ my $comment_list = $self->list_comments();
+
+ my @comments;
+ foreach my $comment ( @$comment_list ) {
+ push @comments, CIL::Comment->new_from_name( $self, $comment->{name} );
+ }
+ return \@comments;
+}
+
+sub get_attachments {
+ my ($self) = @_;
+
+ my $attachment_list = $self->list_attachments();
+
+ my @attachments;
+ foreach my $attachment ( @$attachment_list ) {
+ push @attachments, CIL::Attachment->new_from_name( $self, $attachment->{name} );
+ }
+ return \@attachments;
+}
+
sub get_comments_for {
my ($self, $issue) = @_;
@@ -109,6 +159,38 @@ sub get_attachments_for {
return \@attachments;
}
+sub read_config_file {
+ my ( $self, $filename ) = @_;
+
+ my $cfg = CIL::Utils->parse_cil_file( $filename );
+
+ # set some defaults if we don't have any of these
+ foreach my $key ( keys %$defaults ) {
+ $cfg->{$key} ||= $defaults->{$key};
+ }
+
+ # for some things, make a hash out of them
+ foreach my $hash_name ( @config_hashes ) {
+ my $h = {};
+ foreach my $thing ( @{$cfg->{"${hash_name}List"}} ) {
+ $h->{$thing} = 1;
+ }
+ $cfg->{$hash_name} = $h;
+ undef $cfg->{"${hash_name}List"};
+ }
+
+ # set each config item
+ $self->IssueDir( $cfg->{IssueDir} );
+
+ $self->StatusStrict( $cfg->{StatusStrict} );
+ $self->StatusAllowed( $cfg->{StatusAllowed} );
+ $self->StatusOpen( $cfg->{StatusOpen} );
+ $self->StatusClosed( $cfg->{StatusClosed} );
+
+ $self->LabelStrict( $cfg->{LabelStrict} );
+ $self->LabelAllowed( $cfg->{LabelAllowed} );
+}
+
## ----------------------------------------------------------------------------
1;
## ----------------------------------------------------------------------------
diff --git a/lib/CIL/Base.pm b/lib/CIL/Base.pm
index ed5c3a8..f9b932f 100644
--- a/lib/CIL/Base.pm
+++ b/lib/CIL/Base.pm
@@ -25,6 +25,7 @@ use strict;
use warnings;
use Carp;
use DateTime;
+use CIL::Utils;
use base qw(Class::Accessor);
__PACKAGE__->mk_accessors(qw(CreatedBy Inserted Updated));
@@ -87,6 +88,30 @@ sub new_from_fh {
return $class->new_from_data( $name, $data );
}
+sub set_data {
+ my ($self, $data) = @_;
+
+ # loop through all the allowed fields
+ my $fields = $self->fields();
+ my $array_fields = $self->array_fields();
+
+ # save each field
+ foreach my $field ( @$fields ) {
+ next unless defined $data->{$field};
+
+ # make it an array if it should be one
+ if ( exists $array_fields->{$field} and ref $data->{$field} ne 'ARRAY' ) {
+ $data->{$field} = [ $data->{$field} ];
+ }
+
+ # modify the data directly, otherwise Updated will kick in
+ $self->set_no_update($field, $data->{$field});
+ }
+ $self->set_no_update('Changed', 1);
+
+ $self->{data} = $data;
+}
+
sub save {
my ($self, $cil) = @_;
@@ -96,12 +121,18 @@ sub save {
CIL::Utils->write_cil_file( $filename, $self->{data}, @$fields );
}
+sub as_output {
+ my ($self) = @_;
+ my $fields = $self->fields();
+ return CIL::Utils->format_data_as_output( $self->{data}, @$fields );
+}
+
sub create_filename {
my ($class, $cil, $name) = @_;
# create the filename from it's parts
my $prefix = $class->prefix();
- my $issue_dir = $cil->issue_dir;
+ my $issue_dir = $cil->IssueDir;
my $filename = "${issue_dir}/${prefix}_${name}.cil";
return $filename;
@@ -125,7 +156,7 @@ sub set {
# finish if both are defined and they're the same
if ( defined $orig and defined $value ) {
- return if eval { $orig eq $value };
+ return if $orig eq $value;
}
# finish if neither are defined
@@ -147,7 +178,7 @@ sub set_no_update {
sub set_inserted_now {
my ($self) = @_;
- my $time = DateTime->now;
+ my $time = DateTime->now->iso8601;
$self->{data}{Inserted} = $time;
$self->{data}{Updated} = $time;
$self->{Changed} = 1;
@@ -155,7 +186,7 @@ sub set_inserted_now {
sub set_updated_now {
my ($self) = @_;
- my $time = DateTime->now;
+ my $time = DateTime->now->iso8601;
$self->{data}{Updated} = $time;
$self->{Changed} = 1;
}
@@ -184,6 +215,14 @@ sub name {
return $self->{name};
}
+sub errors {
+ my $self = shift;
+ if( @_ ) {
+ $self->{errors} = $_[0];
+ }
+ return $self->{errors};
+}
+
## ----------------------------------------------------------------------------
1;
## ----------------------------------------------------------------------------
diff --git a/lib/CIL/Comment.pm b/lib/CIL/Comment.pm
index 9d0398c..362f094 100644
--- a/lib/CIL/Comment.pm
+++ b/lib/CIL/Comment.pm
@@ -75,6 +75,14 @@ sub last_field {
return 'Description';
}
+sub is_valid {
+ # ToDo:
+ # * check that the issue is valid
+ # * Inserted and Updated are valid
+ # * Description has something in it
+ return 1;
+}
+
## ----------------------------------------------------------------------------
1;
## ----------------------------------------------------------------------------
diff --git a/lib/CIL/Issue.pm b/lib/CIL/Issue.pm
index 0dfaf53..d44626e 100644
--- a/lib/CIL/Issue.pm
+++ b/lib/CIL/Issue.pm
@@ -90,6 +90,37 @@ sub last_field {
return 'Description';
}
+sub is_valid {
+ my ($self, $cil) = @_;
+
+ my @errors;
+
+ # issues should have a Summary
+ unless ( defined defined $self->Summary and length $self->Summary ) {
+ push @errors, 'Issue does not have a summary';
+ }
+
+ # see if we only allow certain Statuses
+ if ( $cil->StatusStrict ) {
+ unless ( exists $cil->StatusAllowed()->{$self->Status} ) {
+ push @errors, "StatusStrict is turned on but this issue has an invalid status '" . $self->Status . "'";
+ }
+ }
+
+ # see if we only allow certain Labels
+ if ( $cil->LabelStrict ) {
+ my @labels = @{$self->Labels};
+ foreach my $label ( @labels ) {
+ unless ( exists $cil->LabelAllowed()->{$label} ) {
+ push @errors, "LabelStrict is turned on but this issue has an invalid label '$label'";
+ }
+ }
+ }
+
+ $self->errors( \@errors );
+ return @errors ? 0 : 1;
+}
+
sub add_label {
my ($self, $label) = @_;
@@ -124,9 +155,9 @@ sub add_attachment {
$self->flag_as_updated();
}
-sub as_output {
+sub Labels {
my ($self) = @_;
- return CIL::Utils->format_data_as_output( $self->{data}, @FIELDS );
+ return $self->{data}{Label};
}
sub Comments {
@@ -139,6 +170,34 @@ sub Attachments {
return $self->{data}{Attachment};
}
+sub is_open {
+ my ($self, $cil) = @_;
+
+ # check against the list of Open Statuses
+ my $open = $cil->StatusOpen();
+ return exists $open->{$self->Status};
+}
+
+sub is_closed {
+ my ($self, $cil) = @_;
+
+ # check against the list of Closed Statuses
+ my $closed = $cil->StatusClosed();
+ return exists $closed->{$self->Status};
+}
+
+sub assigned_to_email {
+ my ($self) = @_;
+
+ return CIL::Utils->extract_email_address( $self->AssignedTo );
+}
+
+sub created_by_email {
+ my ($self) = @_;
+
+ return CIL::Utils->extract_email_address( $self->CreatedBy );
+}
+
## ----------------------------------------------------------------------------
1;
## ----------------------------------------------------------------------------
diff --git a/lib/CIL/Utils.pm b/lib/CIL/Utils.pm
index a0e165c..e9611cf 100644
--- a/lib/CIL/Utils.pm
+++ b/lib/CIL/Utils.pm
@@ -26,6 +26,7 @@ use warnings;
use Carp;
use File::Slurp;
use File::Temp qw(tempfile);
+use Email::Find;
use POSIX qw(getpgrp tcgetpgrp);
use Fcntl qw(:DEFAULT :flock);
@@ -76,8 +77,9 @@ sub parse_from_lines {
}
}
- # now read everything that's left into the $last_field field
- $data->{$last_field} = join("\n", @lines);
+ # now read everything that's left into the $last_field field (if there is one)
+ $data->{$last_field} = join("\n", @lines)
+ if defined $last_field;
return $data;
}
@@ -128,6 +130,8 @@ sub write_cil_file {
sub solicit {
my ($class, $message) = @_;
+ $message = join('', @$message) if ref $message eq 'ARRAY';
+
# when calling this, assume we're already interactive
File::Temp->safe_level(File::Temp::HIGH);
@@ -179,6 +183,21 @@ sub ensure_interactive {
return;
}
+sub extract_email_address {
+ my ($class, $text) = @_;
+
+ my $email_address;
+ my $num_found = find_emails(
+ $text,
+ sub {
+ my ($mail_address, $text_email) = @_;
+ $email_address = $text_email;
+ }
+ );
+
+ return $email_address;
+}
+
## ----------------------------------------------------------------------------
1;
## ----------------------------------------------------------------------------