Skip to content
Snippets Groups Projects
Commit 64b8e746 authored by Anton Soldatov's avatar Anton Soldatov
Browse files

Extracted code for WebService::Redmine into a separate repository

parent c4e25dd1
Branches
No related tags found
No related merge requests found
Revision history for Perl extension WebService::Redmine (initially RedMiner::API). Revision history for Perl extension WebService::Redmine (initially RedMiner::API).
Please see full revision history at https://github.com/igelhaus/redminer/releases Please see full revision history at https://github.com/igelhaus/perl-WebService-Redmine/releases
0.01 Wed Apr 9 07:44:27 2014 0.01 Wed Apr 9 07:44:27 2014
- original version; created by h2xs 1.23 with options - original version; created by h2xs 1.23 with options
......
config-samples
xt xt
.gitignore .gitignore
README.md README.md
redminer
# redminer # WebService::Redmine
Automating routine [RedMine](http://www.redmine.org) tasks with Perl 5.10+. [Redmine REST API](http://www.redmine.org/projects/redmine/wiki/Rest_api) for Perl 5.10+.
Currently the project consists of two parts: ## Installation from CPAN
1. `redminer` script itself. For now it supports only creating projects with subprojects
from a given layout, but in the future it's aimed for various RedMine automation tasks
2. `WebService::Redmine` module, a Perl binding to [RedMine REST API](http://www.redmine.org/projects/redmine/wiki/Rest_api).
Please refer to [built-in POD documentation](../master/lib/WebService/Redmine.pm) for more details
## Installation
`ExtUtils::MakeMaker` style:
```shell ```shell
$ perl Makefile.PL $ cpan -i WebService::RedMiner
$ make
$ make test
$ make install
``` ```
## Documentation
For more details, please refer to [CPAN](https://metacpan.org/pod/WebService::Redmine) or [built-in POD documentation](../master/lib/WebService/Redmine.pm).
## Non-core Dependencies ## Related Projects
1. [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) 1. [redminer](https://github.com/igelhaus/redminer), a console tool for automating Redmine.
2. [URI](https://metacpan.org/pod/URI)
3. [URI::QueryParam](https://metacpan.org/pod/URI::QueryParam)
4. [JSON::XS](https://metacpan.org/pod/JSON::XS)
5. [Config::IniFiles](https://metacpan.org/pod/Config::IniFiles) (`redminer` only)
#
# Default layout should be located at $HOME/.redminer/default-layout.conf
# Custom path may be specified as
# perl redminer.pl --layout /path/to/layout.conf
#
[project]
description=<<DESCRIPTION
Description of the master project
DESCRIPTION
# Copy permission from the project with ID 42
perm_source=42
# Subproject suffix is the rest of the section name after the 'subproject-'part:
[subproject-development]
name_suffix=Development
description=<<DESCRIPTION
Subproject for development tasks
DESCRIPTION
[subproject-management]
name_suffix=Management
description=<<DESCRIPTION
Subproject for generic management tasks
DESCRIPTION
#
# Default config should be located at $HOME/.redminer/redminer.conf
# Custom path may be specified as
# perl redminer.pl --conf /path/to/redminer.conf
#
[redmine]
host=redmine.example.com
# Host could also include a path and/or schema prefix ('http' is the default value), e.g.:
# * example.com/redmine
# * http://example.com/redmine
# * https://example.com/redmine
# etc.
key=xxx
# How to obtain an API key:
# http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication
# You can find your API key on your account page ( /my/account ) when logged in, on the right-hand pane of the default layout.
# Impersonation settings:
work_as=real_user
# User+Password auth is also possible:
# [redmine]
# host=redmine.example.com
# user=redmine-robot
# pass=p@s$w0rD
#/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use Encode qw/encode/;
use Getopt::Long;
use Config::IniFiles;
use WebService::Redmine;
my $conf_fname = $ENV{HOME} . '/.redminer/redminer.conf';
my $layout_fname = $ENV{HOME} . '/.redminer/default-layout.conf';
my $project_id = '';
my $project_name = 'ClientName.domain';
GetOptions(
'conf=s' => \$conf_fname,
'layout=s' => \$layout_fname,
'id=s' => \$project_id,
'name=s' => \$project_name,
);
my $conf = Config::IniFiles->new( -file => $conf_fname );
if (!$conf) {
die 'Unable to access master config';
}
if (!$project_id) {
if ($project_name =~ /^[a-z.\-]+$/i) {
$project_id = $project_name;
$project_id =~ s/\./-/g;
} else {
die 'Invalid --id parameter';
}
}
my $layout = Config::IniFiles->new( -file => $layout_fname );
if (!$layout) {
warn 'Unable to access layout config';
}
my $redminer = WebService::Redmine->new(
host => $conf->val('redmine', 'host') // '',
user => $conf->val('redmine', 'user') // '',
pass => $conf->val('redmine', 'pass') // '',
key => $conf->val('redmine', 'key') // '',
work_as => $conf->val('redmine', 'work_as') // '',
no_wrapper_object => 1,
);
my $description = $layout? $layout->val('project', 'description') // '' : '';
say 'Creating a new project ' . $project_name;
my $project = $redminer->createProject({
identifier => $project_id ,
name => $project_name,
description => $description ,
});
if (!$project) {
say STDERR 'Project was not created';
say STDERR render_errors($redminer->errorDetails);
exit 255;
}
my $pid = $project->{id};
say 'Project created with ID ' . $pid;
$redminer->updateProject($pid, {
inherit_members => 1,
});
if ($layout) {
my @sections = $layout->Sections;
foreach my $section (@sections) {
next if $section !~ /^subproject(-.+)$/;
my $subproject_data = {
identifier => $project_id . $1,
name => $project_name . ': ' . ($layout->val($section, 'name_suffix') // 'Subproject'),
description => $layout->val($section, 'description') // '',
};
say 'Creating a new subproject ' . $subproject_data->{name};
my $subproject = $redminer->createProject($subproject_data);
if (!$subproject) {
say STDERR 'Subproject was not created';
say STDERR render_errors($redminer->errorDetails);
next;
}
say 'Subproject created with ID ' . $subproject->{id};
$redminer->updateProject($subproject->{id}, {
parent_id => $pid,
inherit_members => 1,
});
}
}
# FIXME: handle limit/offset issue
my $perm_source = $layout? $layout->val('project', 'perm_source') : 0;
if ($perm_source) {
my $memberships = $redminer->projectMemberships($perm_source);
if ($memberships) {
say 'Copying project permissions from a template project...';
foreach my $membership (@{ $memberships->{memberships} }) {
my $type = '';
if (exists $membership->{group}) {
$type = 'group';
} elsif (exists $membership->{user}) {
$type = 'user';
}
next if !length $type;
my $new_membership = {
user_id => $membership->{$type}{id},
role_ids => [],
};
for my $role (@{$membership->{roles}}) {
next if $role->{inherited};
push @{ $new_membership->{role_ids} }, $role->{id};
}
if ($new_membership->{user_id} && @{ $new_membership->{role_ids} }) {
$redminer->createProjectMembership($pid, $new_membership);
}
}
say 'Permissions copied';
}
}
say 'Bye';
exit;
sub render_errors
{
my $errors = shift;
if (ref $errors ne 'HASH' && ref $errors->{errors} ne 'ARRAY') {
return 'Unknown server errors';
}
return join "\n", 'Following error(s) reported:', map {
"\t* " . Encode::encode('UTF-8', $_)
} @{ $errors->{errors} };
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment