diff --git a/Build.PL b/Build.PL index b2490a1..5721bf8 100644 --- a/Build.PL +++ b/Build.PL @@ -20,6 +20,7 @@ my $build = Module::Build->new( 'Test::Pod::Coverage' => 0, 'JSON' => 0, 'YAML' => 0, + 'Capture::Tiny' => 0, }, install_path => { 'templates' => "$HOME/.local/share/peace/template", diff --git a/doc/index.html b/doc/index.html index f675881..ba5c8ac 100644 --- a/doc/index.html +++ b/doc/index.html @@ -44,6 +44,9 @@
Peace::Model::Release implements the following methods:
+my $result = $release->generate_build( arch => $arch );
+ +my ($success, $output) = @result{'success', 'output'};
+ +Generates a build for a given arch of the release and returns the success status, any false value failed, any true value succeded and the output which combines stdout and stderr from the ran commands and some application specific data about whats being done.
+ +The output log is thought to be human consumed, not automatically parsed.
+my $uuid = $release->uuid;
diff --git a/doc/lib/Peace/Test/Mock/Model/Application.pm.html b/doc/lib/Peace/Test/Mock/Model/Application.pm.html
index 9ce2577..0988ccb 100644
--- a/doc/lib/Peace/Test/Mock/Model/Application.pm.html
+++ b/doc/lib/Peace/Test/Mock/Model/Application.pm.html
@@ -33,7 +33,7 @@
DESCRIPTION
-Peace::Test::Mock::Model::Application aims to reduce repeated code which doesn't bring new things to tests by avoiding to add long lines in order to create a Peace::Model::Application object on a unrelated test by providing a stub one already created object.
+Peace::Test::Mock::Model::Application aims to reduce repeated code which doesn't bring new things to tests by avoiding to add long lines in order to create a Peace::Model::Application object on a unrelated tests by providing a stub already created object.
INSTANCE METHODS
diff --git a/doc/lib/Peace/Test/Mock/Model/Build.pm.html b/doc/lib/Peace/Test/Mock/Model/Build.pm.html
new file mode 100644
index 0000000..3d21282
--- /dev/null
+++ b/doc/lib/Peace/Test/Mock/Model/Build.pm.html
@@ -0,0 +1,57 @@
+
+
+
+
+Peace::Test::Mock::Model::Build - Mock object for Peace::Model::Build.
+
+
+
+
+
+
+
+
+
+ - NAME
+ - SYNOPSIS
+ - DESCRIPTION
+ - INSTANCE METHODS
+
+ - new
+
+
+ - SEE ALSO
+
+
+NAME
+
+Peace::Test::Mock::Model::Build - Mock object for Peace::Model::Build.
+
+SYNOPSIS
+
+my $build = Peace::Test::Mock::Model::Build->new;
+
+DESCRIPTION
+
+Peace::Test::Mock::Model::Build aims to reduce repeated code which doesn't bring new things to tests by avoiding to add long lines in order to create a Peace::Model::Build object on a unrelated tests by providing a stub already created object.
+
+INSTANCE METHODS
+
+Peace::Test::Mock::Model::Build provides the following instance methods:
+
+new
+
+my $build = Peace::Test::Mock::Model::Build->new;
+
+Instances a Peace::Model::Build mock object.
+
+SEE ALSO
+
+
+
+
+
+
+
+
+
diff --git a/lib/Peace/Model/Build.pm b/lib/Peace/Model/Build.pm
index 3744bbe..6fcedf5 100644
--- a/lib/Peace/Model/Build.pm
+++ b/lib/Peace/Model/Build.pm
@@ -66,7 +66,7 @@ use Peace::DAO::Release;
{
my $validator = validation_for( params =>
- { { type => InstanceOf ['Peace::Model::Release'], optional => 1 } } );
+ [ { type => InstanceOf ['Peace::Model::Release'], optional => 1 } ] );
sub release {
my $self = shift;
diff --git a/lib/Peace/Model/Release.pm b/lib/Peace/Model/Release.pm
index dcc4840..fa48b4b 100644
--- a/lib/Peace/Model/Release.pm
+++ b/lib/Peace/Model/Release.pm
@@ -11,6 +11,9 @@ use Path::Tiny;
use File::pushd;
use YAML;
use JSON;
+use Capture::Tiny qw/tee_merged/;
+use File::Spec;
+use List::AllUtils qw/any/;
{
my $validator = validation_for(
@@ -46,53 +49,77 @@ use JSON;
arch => { type => Str },
}
);
- sub generate_build {
- my $self = shift;
- my %params = $validator->(@_);
- my $application = $self->application;
- my $flatpak_builder_file = $application->flatpak_builder_file;
- my $arch = $params{arch};
- my $dir = Path::Tiny->tempdir;
- my $clone_dir = Path::Tiny->tempdir;
- my $output_dir = Path::Tiny->new($ENV{HOME})->child('.peace-apps');
- local $ENV{HOME} = $dir;
- say $dir;
- system 'git', 'clone', $application->git_repo, $clone_dir;
- my $current_dir = pushd $clone_dir;
- my $flatpak_data = $self->_parse_flatpak_builder_file;
- my $app_id = $flatpak_data->{"app-id"};
- my $sdk = $flatpak_data->{sdk};
- my $runtime = $flatpak_data->{runtime};
- system 'flatpak', '--user', 'list';
- system 'flatpak', '--user', 'remote-add', '--if-not-exists', 'remote', $application->flatpak_repo;
- say $sdk;
- system 'flatpak', '--user', 'install', '--arch', $arch, '-y', "$sdk";
- say $runtime;
- system 'flatpak', '--user', 'install', '--arch', $arch, '-y', "$runtime";
- system 'flatpak-builder', '--arch', $arch, '--install', '--user', 'build', $application->flatpak_builder_file, $app_id;
- $output_dir = $output_dir->child($self->uuid);
- $output_dir->mkpath;
- system 'flatpak', 'build-bundle', '--arch', $arch, $dir->child('.local/share/flatpak/repo/'), $output_dir->child($arch), $app_id;
+ sub generate_build {
+ my $self = shift;
+ my %params = $validator->(@_);
+ my $arch = $params{arch};
+ my $application = $self->application;
+ say "Building @{[$application->name]} for $arch...";
+ my ( $merged_output, $exit ) = tee_merged {
+ my $flatpak_builder_file = $application->flatpak_builder_file;
+ say
+"$flatpak_builder_file directory portions should not be .., . or empty string", return 1
+ if any { $_ eq '..' or $_ eq '.' or $_ eq '' }
+ File::Spec->splitdir($flatpak_builder_file);
+ my $dir = Path::Tiny->tempdir;
+ my $clone_dir = Path::Tiny->tempdir;
+ my $output_dir =
+ Path::Tiny->new( $ENV{HOME} )->child('.peace-apps');
+ local $ENV{HOME} = $dir;
+ say "TEMP_HOME: $dir";
+ system 'git', 'clone', $application->git_repo, $clone_dir and return 1;
+ say "CLONE_DIR: $clone_dir";
+ my $current_dir = pushd $clone_dir;
+ my $flatpak_data = $self->_parse_flatpak_builder_file;
+ my $app_id = $flatpak_data->{"app-id"};
+ say "APP_ID: $app_id";
+ my $sdk = $flatpak_data->{sdk};
+ say "SDK: $sdk";
+ my $runtime = $flatpak_data->{runtime};
+ say "RUNTIME: $runtime";
+
+ system 'flatpak', '--user', 'list' and return 1;
+ system 'flatpak', '--user', 'remote-add', '--if-not-exists',
+ 'remote', $application->flatpak_repo and return 1;
+ say $sdk;
+ system 'flatpak', '--user', 'install', '--arch', $arch, '-y',
+ "$sdk" and return 1;
+ say $runtime;
+ system 'flatpak', '--user', 'install', '--arch', $arch, '-y',
+ "$runtime" and return 1;
+ system 'flatpak-builder', '--arch', $arch, '--install', '--user',
+ 'build', $application->flatpak_builder_file, $app_id and return 1;
+ $output_dir = $output_dir->child( $self->uuid );
+ $output_dir->mkpath;
+ return system 'flatpak', 'build-bundle', '--arch', $arch,
+ $dir->child('.local/share/flatpak/repo/'),
+ $output_dir->child($arch), $app_id;
+ };
+ my $success = 1;
+ if ($exit) {
+ say "BUILD FAILED:\n$merged_output";
+ $success = 0;
+ }
+ return {
+ output => $merged_output,
+ success => $success,
+ };
}
}
sub _parse_flatpak_builder_file {
- my $self = shift;
- my $application = $self->application;
+ my $self = shift;
+ my $application = $self->application;
my $flatpak_builder_file = $application->flatpak_builder_file;
- my $path = Path::Tiny->new($flatpak_builder_file);
- my $payload = $path->slurp_utf8;
+ my $path = Path::Tiny->new($flatpak_builder_file);
+ my $payload = $path->slurp_utf8;
my $structure;
- eval {
- $structure = decode_json($payload);
- };
- if (!defined $structure) {
- eval {
- ($structure) = Load($payload);
- };
+ eval { $structure = decode_json($payload); };
+ if ( !defined $structure ) {
+ eval { ($structure) = Load($payload); };
}
- if (!defined $structure) {
+ if ( !defined $structure ) {
die "Unable to parse flatpak builder file.";
}
return $structure;
@@ -138,6 +165,7 @@ sub _dbh {
{ type => InstanceOf ['Peace::Model::Application'], optional => 1 }
]
);
+
sub application {
my $self = shift;
if (@_) {
@@ -158,12 +186,14 @@ sub _dbh {
{
my $validator = validation_for(
- params => [
- {
- type => Str, optional => 1,
- }
- ]
+ params => [
+ {
+ type => Str,
+ optional => 1,
+ }
+ ]
);
+
sub tag {
my $self = shift;
if (@_) {
@@ -175,11 +205,8 @@ sub _dbh {
}
{
- my $validator = validation_for(
- params => [
- { type => Str, optional => 1 },
- ]
- );
+ my $validator =
+ validation_for( params => [ { type => Str, optional => 1 }, ] );
sub name {
my $self = shift;
@@ -192,6 +219,7 @@ sub _dbh {
}
1;
+
=encoding utf8
=head1 NAME
@@ -231,6 +259,21 @@ methods:
Peace::Model::Release implements the following methods:
+=head2 generate_build
+
+my $result = $release->generate_build( arch => $arch );
+
+my ($success, $output) = @result{'success', 'output'};
+
+Generates a build for a given arch of the release and
+returns the success status, any false value failed,
+any true value succeded and the output which combines
+stdout and stderr from the ran commands and some
+application specific data about whats being done.
+
+The output log is thought to be human consumed, not
+automatically parsed.
+
=head2 uuid
my $uuid = $release->uuid;
diff --git a/t/00009-release-model.t b/t/00009-release-model.t
index fa185cb..c24cc90 100644
--- a/t/00009-release-model.t
+++ b/t/00009-release-model.t
@@ -3,7 +3,7 @@ use v5.30.0;
use strict;
use warnings;
-use Test::Most tests => 5;
+use Test::Most tests => 6;
use Test::MockModule;
use Peace::Model::Application;
@@ -139,3 +139,28 @@ BEGIN {
## THEN
is $release->application, $release_application, 'Uuid is undef.';
}
+
+{
+ my $developer = Peace::Test::Mock::Model::Developer->new;
+ my $application = Peace::Model::Application->new(
+ name => 'OpenMG',
+ description => 'Stub',
+ url => 'https://gitea.sergiotarxz.freemyip.com/sergiotarxz/mangareader',
+ developer => $developer,
+ price => '99',
+ git_repo =>
+ 'https://gitea.sergiotarxz.freemyip.com/sergiotarxz/mangareader',
+ flatpak_builder_file => '../me.sergiotarxz.openmg.json',
+ flatpak_repo => 'https://nightly.gnome.org/gnome-nightly.flatpakrepo',
+ verified => 1,
+ );
+ my $uuid = 'random-uuid';
+ my $release = Peace::Model::Release->new(
+ uuid => $uuid,
+ application => $application,
+ tag => 'main',
+ name => 'test',
+ );
+ my $result = $release->generate_build( arch => 'x86_64' );
+ ok !$result->{success}, 'Build ends fail if flatpak_builder_file contains a .. component to avoid a directory escape vulnerability..';
+}
diff --git a/web_tests/000001-release-model.t b/web_tests/000001-release-model.t
index 53fcce7..b980dbb 100644
--- a/web_tests/000001-release-model.t
+++ b/web_tests/000001-release-model.t
@@ -5,6 +5,8 @@ use v5.30.0;
use strict;
use warnings;
+use Test::Most tests => 1;
+
use Peace::Test::Mock::Model::Developer;
use Peace::Model::Application;
use Peace::Model::Release;
@@ -30,5 +32,6 @@ use Peace::Model::Release;
tag => 'main',
name => 'test',
);
- $release->generate_build( arch => 'x86_64' );
+ my $result = $release->generate_build( arch => 'x86_64' );
+ ok $result->{success}, 'Build ends successfully.';
}