Skip to content

Issue 73 create issue #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions app/Coding/Issue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace App\Coding;

use Exception;

class Issue extends Base
{
public function create($token, $projectName, $data)
{
$response = $this->client->request('POST', 'https://e.coding.net/open-api', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => "token ${token}",
'Content-Type' => 'application/json'
],
'json' => array_merge([
'Action' => 'CreateIssue',
'ProjectName' => $projectName,
], $data),
]);
$result = json_decode($response->getBody(), true);
if (isset($result['Response']['Error']['Message'])) {
throw new Exception($result['Response']['Error']['Message']);
}
return $result['Response']['Issue'];
}
}
67 changes: 67 additions & 0 deletions app/Commands/IssueCreateCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace App\Commands;

use App\Coding\Issue;
use LaravelZero\Framework\Commands\Command;

class IssueCreateCommand extends Command
{
use WithCoding;

/**
* The signature of the command.
*
* @var string
*/
protected $signature = 'issue:create
{--type= : 类型(使用英文),如 DEFECT(缺陷)、REQUIREMENT(需求)、MISSION(任务)、EPIC(史诗)、SUB_TASK(子任务)}
{--name= : 标题}
{--priority=2 : 优先级,0(低), 1(中), 2(高), 3(紧急)}
{--coding_token= : CODING 令牌}
{--coding_team_domain= : CODING 团队域名,如 xxx.coding.net 即填写 xxx}
{--coding_project_uri= : CODING 项目标识,如 xxx.coding.net/p/yyy 即填写 yyy}
';

/**
* The description of the command.
*
* @var string
*/
protected $description = '创建事项';

/**
* Execute the console command.
*
*/
public function handle(Issue $codingIssue): int
{
$this->setCodingApi();

$data = [];
$data['Type'] = $this->option('type') ?? $this->choice(
'类型:',
['DEFECT', 'REQUIREMENT', 'MISSION', 'EPIC', 'SUB_TASK'],
0
);
$data['Name'] = $this->option('name') ?? $this->ask('标题:');
$data['Priority'] = $this->option('priority') ?? $this->choice(
'优先级:',
['0', '1', '2', '3'],
0
);

try {
$result = $codingIssue->create($this->codingToken, $this->codingProjectUri, $data);
} catch (\Exception $e) {
$this->error('Error: ' . $e->getMessage());
return 1;
}

$this->info('创建成功');
$this->info("https://{$this->codingTeamDomain}.coding.net/p/{$this->codingProjectUri}" .
"/all/issues/${result['Code']}");

return 0;
}
}
59 changes: 59 additions & 0 deletions tests/Feature/IssueCreateCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Tests\Feature;

use App\Coding\Issue;
use Tests\TestCase;

class IssueCreateCommandTest extends TestCase
{
private string $codingToken;
private string $codingTeamDomain;
private string $codingProjectUri;

protected function setUp(): void
{
parent::setUp();
$this->codingToken = $this->faker->md5;
config(['coding.token' => $this->codingToken]);
$this->codingTeamDomain = $this->faker->domainWord;
config(['coding.team_domain' => $this->codingTeamDomain]);
$this->codingProjectUri = $this->faker->slug;
config(['coding.project_uri' => $this->codingProjectUri]);
}

public function testCreateSuccess()
{
$mock = \Mockery::mock(Issue::class, [])->makePartial();
$this->instance(Issue::class, $mock);

$mock->shouldReceive('create')->times(1)->andReturn(json_decode(
file_get_contents($this->dataDir . 'coding/' . 'CreateIssueResponse.json'),
true
)['Response']['Issue']);

$this->artisan('issue:create')
->expectsQuestion('类型:', 'REQUIREMENT')
->expectsQuestion('标题:', $this->faker->title)
->expectsOutput('创建成功')
->expectsOutput("https://$this->codingTeamDomain.coding.net/p/$this->codingProjectUri/all/issues/2742")
->assertExitCode(0);
}

public function testCreateFailed()
{
$mock = \Mockery::mock(Issue::class, [])->makePartial();
$this->instance(Issue::class, $mock);

$mock->shouldReceive('create')->times(1)->andThrow(\Exception::class, json_decode(
file_get_contents($this->dataDir . 'coding/' . 'CreateIssueFailedResponse.json'),
true
)['Response']['Error']['Message']);

$this->artisan('issue:create')
->expectsQuestion('类型:', 'REQUIREMENT')
->expectsQuestion('标题:', $this->faker->title)
->expectsOutput('Error: issue_custom_field_required')
->assertExitCode(1);
}
}
81 changes: 81 additions & 0 deletions tests/Unit/CodingIssueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace Tests\Unit;

use App\Coding\Issue;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use Tests\TestCase;

class CodingIssueTest extends TestCase
{
public function testCreateSuccess()
{
$responseBody = file_get_contents($this->dataDir . 'coding/CreateIssueResponse.json');
$codingToken = $this->faker->md5;
$codingProjectUri = $this->faker->slug;
$data = [
'Type' => 'REQUIREMENT',
'Name' => $this->faker->title,
'Priority' => $this->faker->randomElement([0, 1, 2, 3]),
];

$clientMock = $this->getMockBuilder(Client::class)->getMock();
$clientMock->expects($this->once())
->method('request')
->with(
'POST',
'https://e.coding.net/open-api',
[
'headers' => [
'Accept' => 'application/json',
'Authorization' => "token ${codingToken}",
'Content-Type' => 'application/json'
],
'json' => array_merge([
'Action' => 'CreateIssue',
'ProjectName' => $codingProjectUri,
], $data)
]
)
->willReturn(new Response(200, [], $responseBody));
$coding = new Issue($clientMock);
$result = $coding->create($codingToken, $codingProjectUri, $data);
$this->assertEquals(json_decode($responseBody, true)['Response']['Issue'], $result);
}

public function testCreateFailed()
{
$responseBody = file_get_contents($this->dataDir . 'coding/CreateIssueFailedResponse.json');
$codingToken = $this->faker->md5;
$codingProjectUri = $this->faker->slug;
$data = [
'Type' => 'REQUIREMENT',
'Name' => $this->faker->title,
'Priority' => $this->faker->randomElement([0, 1, 2, 3]),
];

$clientMock = $this->getMockBuilder(Client::class)->getMock();
$clientMock->expects($this->once())
->method('request')
->with(
'POST',
'https://e.coding.net/open-api',
[
'headers' => [
'Accept' => 'application/json',
'Authorization' => "token ${codingToken}",
'Content-Type' => 'application/json'
],
'json' => array_merge([
'Action' => 'CreateIssue',
'ProjectName' => $codingProjectUri,
], $data)
]
)
->willReturn(new Response(200, [], $responseBody));
$coding = new Issue($clientMock);
$this->expectException(\Exception::class);
$coding->create($codingToken, $codingProjectUri, $data);
}
}
9 changes: 9 additions & 0 deletions tests/data/coding/CreateIssueFailedResponse.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Response" : {
"Error" : {
"Code" : "FailedOperation",
"Message" : "issue_custom_field_required"
},
"RequestId" : "504114e3-bcb7-5b51-6ff7-7bb5cb04f121"
}
}
124 changes: 124 additions & 0 deletions tests/data/coding/CreateIssueResponse.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"Response" : {
"Issue" : {
"Assignee" : {
"Avatar" : "",
"Email" : "",
"GlobalKey" : "",
"Id" : 0,
"Name" : "",
"Phone" : "",
"Status" : 0,
"TeamGlobalKey" : "",
"TeamId" : 0
},
"Code" : 2742,
"CompletedAt" : 0,
"CreatedAt" : 1634541907501,
"Creator" : {
"Avatar" : "https://coding-net-production-static-ci.codehub.cn/2cb665a3-bebc-4b09-aa00-2b6df3e33edc.jpg?imageMogr2/auto-orient/format/jpeg/cut/400x400x0x0",
"Email" : "",
"GlobalKey" : "",
"Id" : 183478,
"Name" : "sinkcup",
"Phone" : "",
"Status" : 1,
"TeamGlobalKey" : "",
"TeamId" : 0
},
"CustomFields" : [],
"DefectType" : {
"IconUrl" : "",
"Id" : 0,
"Name" : ""
},
"Description" : "",
"DueDate" : 0,
"Epic" : {
"Assignee" : {
"Avatar" : "",
"Email" : "",
"GlobalKey" : "",
"Id" : 0,
"Name" : "",
"Phone" : "",
"Status" : 0,
"TeamGlobalKey" : "",
"TeamId" : 0
},
"Code" : 0,
"IssueStatusId" : 0,
"IssueStatusName" : "",
"Name" : "",
"Priority" : "",
"Type" : ""
},
"Files" : [],
"IssueStatusId" : 1227034,
"IssueStatusName" : "未开始",
"IssueStatusType" : "TODO",
"IssueTypeDetail" : {
"Description" : "需求是指用户解决某一个问题或达到某一目标所需的软件功能。",
"Id" : 213219,
"IsSystem" : true,
"IssueType" : "REQUIREMENT",
"Name" : "需求"
},
"IssueTypeId" : 213219,
"Iteration" : {
"Code" : 0,
"Name" : "",
"Status" : ""
},
"IterationId" : 0,
"Labels" : [],
"Name" : "issue by curl",
"Parent" : {
"Assignee" : {
"Avatar" : "",
"Email" : "",
"GlobalKey" : "",
"Id" : 0,
"Name" : "",
"Phone" : "",
"Status" : 0,
"TeamGlobalKey" : "",
"TeamId" : 0
},
"Code" : 0,
"IssueStatusId" : 0,
"IssueStatusName" : "",
"IssueStatusType" : "",
"IssueTypeDetail" : {
"Description" : "",
"Id" : 0,
"IsSystem" : false,
"IssueType" : "",
"Name" : ""
},
"Name" : "",
"Priority" : "",
"Type" : ""
},
"ParentType" : "REQUIREMENT",
"Priority" : "0",
"ProjectModule" : {
"Id" : 0,
"Name" : ""
},
"RequirementType" : {
"Id" : 0,
"Name" : ""
},
"StartDate" : 0,
"StoryPoint" : "",
"SubTasks" : [],
"ThirdLinks" : [],
"Type" : "REQUIREMENT",
"UpdatedAt" : 1634541907501,
"Watchers" : [],
"WorkingHours" : 0
},
"RequestId" : "5b7bae01-f26f-16d7-0d61-c8fa67ea0472"
}
}