Skip to content

feat: #72 cli import issues #77

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 12 commits into from
Oct 22, 2021
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/.vscode
/.vagrant
.phpunit.result.cache
/database/database.sqlite
4 changes: 4 additions & 0 deletions app/Coding/Iteration.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Coding;

use Carbon\Carbon;
use Exception;

class Iteration extends Base
{
Expand All @@ -20,6 +21,9 @@ public function create($token, $projectName, $data)
], $data),
]);
$result = json_decode($response->getBody(), true);
if (isset($result['Response']['Error']['Message'])) {
throw new Exception($result['Response']['Error']['Message']);
}
return $result['Response']['Iteration'];
}

Expand Down
23 changes: 0 additions & 23 deletions app/Coding/Project.php

This file was deleted.

42 changes: 42 additions & 0 deletions app/Coding/ProjectSetting.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace App\Coding;

class ProjectSetting extends Base
{
public function getIssueTypes($token, $projectName)
{
$response = $this->client->request('POST', 'https://e.coding.net/open-api', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => "token ${token}",
'Content-Type' => 'application/json'
],
'json' => [
'Action' => 'DescribeProjectIssueTypeList',
'ProjectName' => $projectName,
],
]);
$result = json_decode($response->getBody(), true);
return $result['Response']['IssueTypes'];
}

public function getIssueTypeStatus(string $token, string $projectName, string $issueType, int $issueTypeId)
{
$response = $this->client->request('POST', 'https://e.coding.net/open-api', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => "token ${token}",
'Content-Type' => 'application/json'
],
'json' => [
'Action' => 'DescribeProjectIssueStatusList',
'ProjectName' => $projectName,
'IssueType' => $issueType,
'IssueTypeId' => $issueTypeId,
],
]);
$result = json_decode($response->getBody(), true);
return $result['Response']['ProjectIssueStatusList'];
}
}
151 changes: 151 additions & 0 deletions app/Commands/IssueImportCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<?php

namespace App\Commands;

use App\Coding\Issue;
use App\Coding\Iteration;
use App\Coding\ProjectSetting;
use Exception;
use Illuminate\Support\Arr;
use LaravelZero\Framework\Commands\Command;
use Rap2hpoutre\FastExcel\Facades\FastExcel;

class IssueImportCommand extends Command
{
use WithCoding;

/**
* The signature of the command.
*
* @var string
*/
protected $signature = 'issue:import
{file : 文件(支持格式:csv)}
{--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 = '导入事项';

protected array $issueCodeMap = [];
protected array $issueTypes = [];
protected array $issueTypeStatus = [];
protected array $iterationMap = [];

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

$filePath = $this->argument('file');
if (!file_exists($filePath)) {
$this->error("文件不存在:$filePath");
return 1;
}

$rows = FastExcel::import($filePath);
if (!empty($rows) && isset($rows[0]['ID'])) {
$rows = $rows->sortBy('ID');
}
foreach ($rows as $row) {
try {
$issueResult = $this->createIssueByRow($projectSetting, $codingIssue, $iteration, $row);
} catch (Exception $e) {
$this->error('Error: ' . $e->getMessage());
return 1;
}
$this->info('标题:' . $row['标题']);
$this->info("https://{$this->codingTeamDomain}.coding.net/p/{$this->codingProjectUri}" .
"/all/issues/${issueResult['Code']}");
}

return 0;
}

private function getIssueTypes(ProjectSetting $projectSetting, array $row): void
{
if (empty($this->issueTypes)) {
$result = $projectSetting->getIssueTypes($this->codingToken, $this->codingProjectUri);
foreach ($result as $item) {
$this->issueTypes[$item['Name']] = $item;
}
}
if (!isset($this->issueTypes[$row['事项类型']])) {
throw new Exception('「' . $row['事项类型'] . '」类型不存在,请在项目设置中添加');
}
}

private function getStatusId(ProjectSetting $projectSetting, string $issueTypeName, string $statusName): int
{
if (!isset($this->issueTypeStatus[$issueTypeName])) {
$type = $this->issueTypes[$issueTypeName]['IssueType'];
$typeId = $this->issueTypes[$issueTypeName]['Id'];
$result = $projectSetting->getIssueTypeStatus($this->codingToken, $this->codingProjectUri, $type, $typeId);
foreach ($result as $item) {
$tmp = $item['IssueStatus'];
$this->issueTypeStatus[$issueTypeName][$tmp['Name']] = $tmp['Id'];
}
}
if (!isset($this->issueTypeStatus[$issueTypeName][$statusName])) {
throw new Exception('「' . $statusName . '」不存在,请在设置中添加');
}
return intval($this->issueTypeStatus[$issueTypeName][$statusName]);
}

private function createIssueByRow(ProjectSetting $projectSetting, Issue $issue, Iteration $iteration, array $row)
{
$this->getIssueTypes($projectSetting, $row);
$data = [
'Type' => $this->issueTypes[$row['事项类型']]['IssueType'],
'IssueTypeId' => $this->issueTypes[$row['事项类型']]['Id'],
'Name' => $row['标题'],
];
if (!empty($row['优先级'])) {
$data['Priority'] = \App\Models\Issue::PRIORITY_MAP[$row['优先级']];
}
if (!empty($row['所属迭代'])) {
$data['IterationCode'] = $this->getIterationCode($iteration, $row['所属迭代']);
}
if (!empty($row['ParentCode'])) {
$data['ParentCode'] = $this->issueCodeMap[$row['ParentCode']];
}
foreach (
[
'Description' => '描述',
'DueDate' => '截止日期',
'StartDate' => '开始日期',
'StoryPoint' => '故事点',
] as $english => $chinese
) {
if (!empty($row[$chinese])) {
$data[$english] = $row[$chinese];
}
}
if (!empty($row['状态'])) {
$data['StatusId'] = $this->getStatusId($projectSetting, $row['事项类型'], $row['状态']);
}
$result = $issue->create($this->codingToken, $this->codingProjectUri, $data);
if (isset($row['ID'])) {
$this->issueCodeMap[$row['ID']] = intval($result['Code']);
}
return $result;
}

private function getIterationCode(Iteration $iteration, string $name)
{
if (!isset($this->iterationMap[$name])) {
$result = $iteration->create($this->codingToken, $this->codingProjectUri, ['name' => $name]);
$this->iterationMap[$name] = $result['Code'];
}
return $this->iterationMap[$name];
}
}
7 changes: 3 additions & 4 deletions app/Commands/ProjectGetIssueTypesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

namespace App\Commands;

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

class ProjectGetIssueTypesCommand extends Command
Expand Down Expand Up @@ -32,11 +31,11 @@ class ProjectGetIssueTypesCommand extends Command
* Execute the console command.
*
*/
public function handle(Project $codingProject): int
public function handle(ProjectSetting $projectSetting): int
{
$this->setCodingApi();

$result = $codingProject->getIssueTypes($this->codingToken, $this->codingProjectUri);
$result = $projectSetting->getIssueTypes($this->codingToken, $this->codingProjectUri);

foreach ($result as $item) {
$this->info($item['Id'] . ' ' . $item['Name']);
Expand Down
13 changes: 13 additions & 0 deletions app/Models/Issue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace App\Models;

class Issue
{
public const PRIORITY_MAP = [
'低' => '0',
'中' => '1',
'高' => '2',
'紧急' => '3',
];
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
"laravel-zero/framework": "^8.8",
"league/html-to-markdown": "^5.0",
"nesbot/carbon": "^2.53",
"rap2hpoutre/fast-excel": "^3.1",
"sinkcup/laravel-filesystem-cos-updated": "^4.0"
},
"require-dev": {
"fakerphp/faker": "^1.14",
"fakerphp/faker": "^1.16",
"mockery/mockery": "^1.4.3",
"phpmd/phpmd": "^2.10",
"phpunit/phpunit": "^9.5",
Expand Down
Loading