Commit d42bb8ec authored by 汪洋's avatar 汪洋

优化了一部分代码逻辑;优化了Log的形式

parent de92dc3f
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
D30D4AF0224CC3FF004CE936 /* Jira.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30D4AEF224CC3FF004CE936 /* Jira.swift */; };
D30D4AF2224CCDE0004CE936 /* File in Resources */ = {isa = PBXBuildFile; fileRef = D30D4AF1224CCDE0004CE936 /* File */; }; D30D4AF2224CCDE0004CE936 /* File in Resources */ = {isa = PBXBuildFile; fileRef = D30D4AF1224CCDE0004CE936 /* File */; };
D35CADA92642EF611E6ABE62 /* Pods_AutoJira.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D013D83D9CA164C1F113E5D /* Pods_AutoJira.framework */; }; D35CADA92642EF611E6ABE62 /* Pods_AutoJira.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D013D83D9CA164C1F113E5D /* Pods_AutoJira.framework */; };
D386B4C82250A9AB003435E9 /* JiraProject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D386B4C72250A9AB003435E9 /* JiraProject.swift */; };
D3E595DF22240DCC004DCC62 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E595DE22240DCC004DCC62 /* AppDelegate.swift */; }; D3E595DF22240DCC004DCC62 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E595DE22240DCC004DCC62 /* AppDelegate.swift */; };
D3E595E122240DCC004DCC62 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E595E022240DCC004DCC62 /* ViewController.swift */; }; D3E595E122240DCC004DCC62 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E595E022240DCC004DCC62 /* ViewController.swift */; };
D3E595E322240DCF004DCC62 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3E595E222240DCF004DCC62 /* Assets.xcassets */; }; D3E595E322240DCF004DCC62 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3E595E222240DCF004DCC62 /* Assets.xcassets */; };
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
D3E596012227B5A2004DCC62 /* XPath备忘.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E596002227B5A2004DCC62 /* XPath备忘.md */; }; D3E596012227B5A2004DCC62 /* XPath备忘.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E596002227B5A2004DCC62 /* XPath备忘.md */; };
D3E596032227B5CD004DCC62 /* 创建story.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E596022227B5CD004DCC62 /* 创建story.md */; }; D3E596032227B5CD004DCC62 /* 创建story.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E596022227B5CD004DCC62 /* 创建story.md */; };
D3E596052227B628004DCC62 /* 关联story.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E596042227B628004DCC62 /* 关联story.md */; }; D3E596052227B628004DCC62 /* 关联story.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E596042227B628004DCC62 /* 关联story.md */; };
D3E596092227B6F9004DCC62 /* RepeatdWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E596082227B6F9004DCC62 /* RepeatdWork.swift */; }; D3E596092227B6F9004DCC62 /* JiraAutomator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E596082227B6F9004DCC62 /* JiraAutomator.swift */; };
D3E5960B222E1E60004DCC62 /* 登录Login.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E5960A222E1E60004DCC62 /* 登录Login.md */; }; D3E5960B222E1E60004DCC62 /* 登录Login.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E5960A222E1E60004DCC62 /* 登录Login.md */; };
D3E5960D222E2D1D004DCC62 /* Login.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E5960C222E2D1D004DCC62 /* Login.swift */; }; D3E5960D222E2D1D004DCC62 /* Login.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3E5960C222E2D1D004DCC62 /* Login.swift */; };
D3E5960F222FBDBC004DCC62 /* 获取EditIssue.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E5960E222FBDBB004DCC62 /* 获取EditIssue.md */; }; D3E5960F222FBDBC004DCC62 /* 获取EditIssue.md in Resources */ = {isa = PBXBuildFile; fileRef = D3E5960E222FBDBB004DCC62 /* 获取EditIssue.md */; };
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
6D013D83D9CA164C1F113E5D /* Pods_AutoJira.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AutoJira.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6D013D83D9CA164C1F113E5D /* Pods_AutoJira.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AutoJira.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8D92517B7E535BFBB153A49B /* Pods-AutoJira.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AutoJira.release.xcconfig"; path = "Target Support Files/Pods-AutoJira/Pods-AutoJira.release.xcconfig"; sourceTree = "<group>"; }; 8D92517B7E535BFBB153A49B /* Pods-AutoJira.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AutoJira.release.xcconfig"; path = "Target Support Files/Pods-AutoJira/Pods-AutoJira.release.xcconfig"; sourceTree = "<group>"; };
ACBE7590179B597A40CC91EE /* Pods-AutoJira.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AutoJira.debug.xcconfig"; path = "Target Support Files/Pods-AutoJira/Pods-AutoJira.debug.xcconfig"; sourceTree = "<group>"; }; ACBE7590179B597A40CC91EE /* Pods-AutoJira.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AutoJira.debug.xcconfig"; path = "Target Support Files/Pods-AutoJira/Pods-AutoJira.debug.xcconfig"; sourceTree = "<group>"; };
D30D4AEF224CC3FF004CE936 /* Jira.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Jira.swift; sourceTree = "<group>"; };
D30D4AF1224CCDE0004CE936 /* File */ = {isa = PBXFileReference; lastKnownFileType = text; path = File; sourceTree = "<group>"; }; D30D4AF1224CCDE0004CE936 /* File */ = {isa = PBXFileReference; lastKnownFileType = text; path = File; sourceTree = "<group>"; };
D386B4C72250A9AB003435E9 /* JiraProject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JiraProject.swift; sourceTree = "<group>"; };
D3E595DB22240DCC004DCC62 /* AutoJira.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoJira.app; sourceTree = BUILT_PRODUCTS_DIR; }; D3E595DB22240DCC004DCC62 /* AutoJira.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoJira.app; sourceTree = BUILT_PRODUCTS_DIR; };
D3E595DE22240DCC004DCC62 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; D3E595DE22240DCC004DCC62 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D3E595E022240DCC004DCC62 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; }; D3E595E022240DCC004DCC62 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
D3E596002227B5A2004DCC62 /* XPath备忘.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "XPath备忘.md"; sourceTree = "<group>"; }; D3E596002227B5A2004DCC62 /* XPath备忘.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "XPath备忘.md"; sourceTree = "<group>"; };
D3E596022227B5CD004DCC62 /* 创建story.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "创建story.md"; sourceTree = "<group>"; }; D3E596022227B5CD004DCC62 /* 创建story.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "创建story.md"; sourceTree = "<group>"; };
D3E596042227B628004DCC62 /* 关联story.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "关联story.md"; sourceTree = "<group>"; }; D3E596042227B628004DCC62 /* 关联story.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "关联story.md"; sourceTree = "<group>"; };
D3E596082227B6F9004DCC62 /* RepeatdWork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatdWork.swift; sourceTree = "<group>"; }; D3E596082227B6F9004DCC62 /* JiraAutomator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JiraAutomator.swift; sourceTree = "<group>"; };
D3E5960A222E1E60004DCC62 /* 登录Login.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "登录Login.md"; sourceTree = "<group>"; }; D3E5960A222E1E60004DCC62 /* 登录Login.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "登录Login.md"; sourceTree = "<group>"; };
D3E5960C222E2D1D004DCC62 /* Login.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Login.swift; sourceTree = "<group>"; }; D3E5960C222E2D1D004DCC62 /* Login.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Login.swift; sourceTree = "<group>"; };
D3E5960E222FBDBB004DCC62 /* 获取EditIssue.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "获取EditIssue.md"; sourceTree = "<group>"; }; D3E5960E222FBDBB004DCC62 /* 获取EditIssue.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "获取EditIssue.md"; sourceTree = "<group>"; };
...@@ -105,12 +105,12 @@ ...@@ -105,12 +105,12 @@
D3E595FB2227B559004DCC62 /* 代码阅读 */, D3E595FB2227B559004DCC62 /* 代码阅读 */,
D3E595DE22240DCC004DCC62 /* AppDelegate.swift */, D3E595DE22240DCC004DCC62 /* AppDelegate.swift */,
D3E595E022240DCC004DCC62 /* ViewController.swift */, D3E595E022240DCC004DCC62 /* ViewController.swift */,
D3E596082227B6F9004DCC62 /* RepeatdWork.swift */, D3E596082227B6F9004DCC62 /* JiraAutomator.swift */,
D3E595EE22252765004DCC62 /* Page.swift */, D3E595EE22252765004DCC62 /* Page.swift */,
D3E595F42226AEC7004DCC62 /* Story.swift */, D3E595F42226AEC7004DCC62 /* Story.swift */,
D3E595F22226AE50004DCC62 /* RequestUtils.swift */, D386B4C72250A9AB003435E9 /* JiraProject.swift */,
D30D4AEF224CC3FF004CE936 /* Jira.swift */,
D3E5960C222E2D1D004DCC62 /* Login.swift */, D3E5960C222E2D1D004DCC62 /* Login.swift */,
D3E595F22226AE50004DCC62 /* RequestUtils.swift */,
D3E595E222240DCF004DCC62 /* Assets.xcassets */, D3E595E222240DCF004DCC62 /* Assets.xcassets */,
D3E595E422240DCF004DCC62 /* Main.storyboard */, D3E595E422240DCF004DCC62 /* Main.storyboard */,
D3E595E722240DCF004DCC62 /* Info.plist */, D3E595E722240DCF004DCC62 /* Info.plist */,
...@@ -283,9 +283,9 @@ ...@@ -283,9 +283,9 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D3E5960D222E2D1D004DCC62 /* Login.swift in Sources */, D3E5960D222E2D1D004DCC62 /* Login.swift in Sources */,
D3E596092227B6F9004DCC62 /* RepeatdWork.swift in Sources */, D3E596092227B6F9004DCC62 /* JiraAutomator.swift in Sources */,
D3E595E122240DCC004DCC62 /* ViewController.swift in Sources */, D3E595E122240DCC004DCC62 /* ViewController.swift in Sources */,
D30D4AF0224CC3FF004CE936 /* Jira.swift in Sources */, D386B4C82250A9AB003435E9 /* JiraProject.swift in Sources */,
D3E595F52226AEC7004DCC62 /* Story.swift in Sources */, D3E595F52226AEC7004DCC62 /* Story.swift in Sources */,
D3E595DF22240DCC004DCC62 /* AppDelegate.swift in Sources */, D3E595DF22240DCC004DCC62 /* AppDelegate.swift in Sources */,
D3E595EF22252765004DCC62 /* Page.swift in Sources */, D3E595EF22252765004DCC62 /* Page.swift in Sources */,
......
...@@ -2,22 +2,4 @@ ...@@ -2,22 +2,4 @@
<Bucket <Bucket
type = "0" type = "0"
version = "2.0"> version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoJira/Page.swift"
timestampString = "575300302.606153"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "89"
endingLineNumber = "89"
landmarkName = "getUser(tr:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket> </Bucket>
...@@ -785,7 +785,7 @@ ...@@ -785,7 +785,7 @@
</textField> </textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pLx-ea-hpy"> <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pLx-ea-hpy">
<rect key="frame" x="106" y="326" width="540" height="22"/> <rect key="frame" x="106" y="326" width="540" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=18581629" drawsBackground="YES" id="xMA-0w-54b"> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=18587956" drawsBackground="YES" id="xMA-0w-54b">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
...@@ -817,7 +817,7 @@ ...@@ -817,7 +817,7 @@
</menu> </menu>
</popUpButtonCell> </popUpButtonCell>
<connections> <connections>
<action selector="versionSelectionAction:" target="XfG-lQ-9wD" id="mnQ-V7-Ndt"/> <action selector="sprintSelectionAction:" target="XfG-lQ-9wD" id="3IP-CD-xOq"/>
</connections> </connections>
</popUpButton> </popUpButton>
</subviews> </subviews>
...@@ -845,8 +845,8 @@ ...@@ -845,8 +845,8 @@
<connections> <connections>
<outlet property="logTextView" destination="oWH-27-6AA" id="HNL-mY-PU6"/> <outlet property="logTextView" destination="oWH-27-6AA" id="HNL-mY-PU6"/>
<outlet property="segment" destination="Odk-md-Lt7" id="rC3-jS-ysv"/> <outlet property="segment" destination="Odk-md-Lt7" id="rC3-jS-ysv"/>
<outlet property="sprintPopup" destination="Ajo-Dg-gTt" id="6sw-cz-Cld"/>
<outlet property="urlTextField" destination="pLx-ea-hpy" id="5IN-61-bR6"/> <outlet property="urlTextField" destination="pLx-ea-hpy" id="5IN-61-bR6"/>
<outlet property="versionPopup" destination="Ajo-Dg-gTt" id="Nus-dW-6QJ"/>
</connections> </connections>
</viewController> </viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
......
//
// Jira.swift
// AutoJira
//
// Created by wangyang on 2019/3/28.
// Copyright © 2019 wangyang. All rights reserved.
//
import Cocoa
class Jira: NSObject {
var jiraProjectId: String = ""
var sprints: [Sprint] = []
var currentSprint: Sprint?
var subtask_id: String = ""
convenience init(jiraProjectId: String, sprints: [Sprint]) {
self.init()
self.jiraProjectId = jiraProjectId
self.sprints = sprints
// like sub task 10302
// gengmei sub task 10003
if jiraProjectId == "10108" {
// 更美
subtask_id = "10003"
} else {
// like
subtask_id = "10302"
}
}
}
...@@ -8,20 +8,66 @@ ...@@ -8,20 +8,66 @@
import Foundation import Foundation
import Kanna import Kanna
import ReactiveCocoa
struct RepeatedWork { class JiraAutomator: NSObject {
static var jira: Jira?
static let shared = JiraAutomator()
var jira: JiraProject?
var currentSprint: Sprint?
let projects = [JiraProjectType.gengmei: JiraProject(projectType: .gengmei),
JiraProjectType.like: JiraProject(projectType: .like)]
// 参考"获取迭代列表.md"
func fetchJiraSprints() {
let url = URL(string: "http://jira.wanmeizhensuo.com/rest/greenhopper/1.0/sprint/picker?query=&_=1552128647090")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.sync { [weak self] (data, response, error) in
if data == nil {
Log.append(error)
return
}
if self == nil {
Log.append(error: "fetchSprintList self 为空")
return
}
if let json = (try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments)) as? [String: Any] {
guard let sprints = json["suggestions"] as? [[String: Any]] else {
Log.append(error: "json中没有suggestions")
return
}
for sprintDic in sprints {
if let boardName = sprintDic["boardName"] as? String {
if boardName == "Alpha" {
let sprint = Sprint(dic: sprintDic)
self!.projects[JiraProjectType.like]!.sprints.append(sprint)
} else if boardName == "USER board" {
let sprint = Sprint(dic: sprintDic)
self!.projects[JiraProjectType.gengmei]!.sprints.append(sprint)
}
}
}
} else {
Log.append(error: "获取迭代列表失败:\n\(response.debugDescription)")
}
}
}
func switchProject(type: JiraProjectType) {
self.jira = projects[type]
}
// url是“开发与测试资源安排”中的迭代文件 // url是“开发与测试资源安排”中的迭代文件
static func fuckit(on sprintUrl: String) { func start(on sprintUrl: String) {
let url = URL(string: sprintUrl)! let url = URL(string: sprintUrl)!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { (data, response, error) in URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) in
DispatchQueue.main.async { DispatchQueue.main.async {
if data != nil { if data != nil {
doTheRepeatedWork(data!) self?.doTheRepeatedWork(data!)
} else { } else {
Log.append(error) Log.append(error)
} }
...@@ -29,8 +75,7 @@ struct RepeatedWork { ...@@ -29,8 +75,7 @@ struct RepeatedWork {
}.resume() }.resume()
} }
static func doTheRepeatedWork(_ data: Data) { func doTheRepeatedWork(_ data: Data) {
Log.append("开始重复工作")
guard let html = String(data: data, encoding: .utf8) else { guard let html = String(data: data, encoding: .utf8) else {
return return
} }
...@@ -43,32 +88,42 @@ struct RepeatedWork { ...@@ -43,32 +88,42 @@ struct RepeatedWork {
// //
let obj = doc.xpath("//*[@id=\"main-content\"]/div[2]/table/tbody//td[@data-content-id]") let obj = doc.xpath("//*[@id=\"main-content\"]/div[2]/table/tbody//td[@data-content-id]")
if obj.count == 0 { if obj.count == 0 {
Log.append("没有需要列表\nhtml") Log.append(error: "根据XPath没有找到需求。一般来说是XPath出错,原始html内容为\(html)")
return return
} }
// 此处的每一个node就是一个需求,可以使用node.toHTML来查看其内容 // 此处的每一个node就是一个需求,可以使用node.toHTML来查看其内容
var index = 1
Log.append("一共\(obj.count)个需求")
for node in obj.makeIterator() { for node in obj.makeIterator() {
let page = Page(page: node) Log.append("开始处理第\(index)个")
let page = Page(page: node)
if !page.isValide() { if !page.isValide() {
Log.append("\(node.toHTML!) page 信息有问题") Log.append(error: "\(page.title): 验证未通过")
continue continue
} }
if let story = Story.createStory(with: page.title, jiraProjectId: RepeatedWork.jira!.jiraProjectId) { if page.hasCreateStory() {
page.story = story Log.append("\(page.title): 已经创建story,跳过其它步骤")
} else {
Log.append("\(node.toHTML!) story创建出错")
continue continue
} }
page.story.connect(to: page.pageId, with: page.lastFetchTime) if let story = Story.createStory(with: page.title) {
if let foId = page.fo?.id { page.story = story
page.story.editStoryInfo(assignee: foId)
} else { } else {
Log.append("\(node.toHTML!) 没有正确修改story") Log.append(error: "\(page.title): story创建出错")
continue
} }
page.story.createSubtask(page: page) Log.append("story创建完成")
page.story.connect(to: page.pageId, with: page.lastFetchTime)
// if let foId = page.fo?.id {
// page.story.editStoryInfo(assignee: foId)
// } else {
// Log.append(error: "\(node.toHTML!) 没有正确修改story")
// }
// page.story.createSubtask(page: page)
index += 1
} }
} }
} }
//
// Jira.swift
// AutoJira
//
// Created by wangyang on 2019/3/28.
// Copyright © 2019 wangyang. All rights reserved.
//
import Cocoa
class JiraProject: NSObject {
var id: String = ""
var sprints: [Sprint] = []
var subtask_id: String = ""
convenience init(projectType: JiraProjectType) {
self.init()
self.id = projectType.rawValue
self.subtask_id = projectType.subtaskId()
}
}
enum JiraProjectType: String {
case like = "10500"
case gengmei = "10108"
func subtaskId() -> String {
switch self {
case .like:
return "10302"
case .gengmei:
return "10003"
}
}
}
enum SprintState: String {
case future = "FUTURE"
case active = "ACTIVE"
case none = ""
}
struct Sprint {
let name: String
let id: Int
let stateKey: SprintState
init(dic: [String: Any]) {
if let name = dic["name"] as? String,
let id = dic["id"] as? Int,
let stateKey = dic["stateKey"] as? String,
let s = SprintState(rawValue: stateKey) {
self.name = name
self.id = id
self.stateKey = s
} else {
name = ""
id = 0
stateKey = .none
}
}
}
...@@ -14,6 +14,7 @@ struct People { ...@@ -14,6 +14,7 @@ struct People {
var name: String var name: String
var id: String var id: String
} }
/* /*
可以使用html属性进一步来查看当前所代码的html代码。 可以使用html属性进一步来查看当前所代码的html代码。
*/ */
...@@ -45,24 +46,24 @@ class Page: NSObject { ...@@ -45,24 +46,24 @@ class Page: NSObject {
// 核心是得到developers,其它都是错误处理 // 核心是得到developers,其它都是错误处理
guard let tableTr = html?.xpath("//*[@id=\"main-content\"]/div[1]/div/table/tbody/tr") else { guard let tableTr = html?.xpath("//*[@id=\"main-content\"]/div[1]/div/table/tbody/tr") else {
Log.append("没有得到需求文档的table") Log.append(error: "没有得到需求文档的table")
return return
} }
// 循环table中的每一行,如果该行是FO或者开发这一类的,就进行人员解析 // 循环table中的每一行,如果该行是FO或者开发这一类的,就进行人员解析
for tr in tableTr.makeIterator() { for tr in tableTr.makeIterator() {
guard let th = tr.at_xpath("th")?.innerHTML else { guard let th = tr.at_xpath("th")?.innerHTML else {
Log.append("\(tr.toHTML!) table tr/th中没有span") Log.append(error: "\(tr.toHTML!) table tr/th中没有span")
continue continue
} }
if th.contains("FO") { if th.contains("FO") {
if let user = getUser(tr: tr).first { if let user = getUser(tr: tr).first {
fo = user fo = user
} else { } else {
Log.append("\(tr.toHTML!) FO 没有正确生成") Log.append(error: "\(tr.toHTML!) FO 没有正确生成")
continue continue
} }
} else if th.contains("测试") || th.contains("开发") || th.contains("数据") { } else if th.contains("测试") || th.contains("开发") || th.contains("数据") || th.contains("策略"){
developers.append(contentsOf: getUser(tr: tr)) developers.append(contentsOf: getUser(tr: tr))
} }
} }
...@@ -79,11 +80,7 @@ class Page: NSObject { ...@@ -79,11 +80,7 @@ class Page: NSObject {
users.append(People(name: name, id: name_id)) users.append(People(name: name, id: name_id))
} else { } else {
if html.toHTML != nil { Log.append(error: "\(title): getUser没有成功解析")
Log.append("\(html.toHTML!) 没有成功解析")
continue
}
Log.append("\(html)没有成功解析")
} }
} }
return users return users
...@@ -91,14 +88,21 @@ class Page: NSObject { ...@@ -91,14 +88,21 @@ class Page: NSObject {
func isValide() -> Bool { func isValide() -> Bool {
if html == nil { if html == nil {
Log.append("\(pageUrl) 未正常解析") Log.append(error: "\(pageUrl) 未正常解析")
return false return false
} }
Log.append("创建Page成功: \(title)") if html!.body!.toHTML!.contains("是/否") {
Log.append(error: "\(title) 文档中包含“是/否”")
return false
}
return true return true
} }
func hasCreateStory() -> Bool {
return html!.body!.toHTML!.contains("jira-issue-key")
}
// 下载需求页面,从中得到必要的信息 // 下载需求页面,从中得到必要的信息
func loadHTML() -> HTMLDocument? { func loadHTML() -> HTMLDocument? {
let url = URL(string: pageUrl)! let url = URL(string: pageUrl)!
......
...@@ -28,14 +28,13 @@ class Story: NSObject { ...@@ -28,14 +28,13 @@ class Story: NSObject {
/// ///
/// - Parameter page: Page实例 /// - Parameter page: Page实例
/// - Returns: storyKey /// - Returns: storyKey
static func createStory(with title: String, jiraProjectId: String) -> Story? { static func createStory(with title: String) -> Story? {
Log.append("创建story")
let url = URL(string: "http://wiki.wanmeizhensuo.com/rest/jira-integration/1.0/issues?applicationId=54ed5447-b029-3ef0-b638-681b4647313b")! let url = URL(string: "http://wiki.wanmeizhensuo.com/rest/jira-integration/1.0/issues?applicationId=54ed5447-b029-3ef0-b638-681b4647313b")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let jsonDic = ["issues": [["fields":["project":["id":RepeatedWork.jira!.jiraProjectId],"issuetype":["id":"10001"],"summary": title]]]] let jsonDic = ["issues": [["fields":["project":["id":JiraAutomator.shared.jira!.id],"issuetype":["id":"10001"],"summary": title]]]]
request.httpBody = try? JSONSerialization.data(withJSONObject: jsonDic, options: []) request.httpBody = try? JSONSerialization.data(withJSONObject: jsonDic, options: [])
var story: Story? var story: Story?
request.sync { (data, response, error) in request.sync { (data, response, error) in
...@@ -53,7 +52,7 @@ class Story: NSObject { ...@@ -53,7 +52,7 @@ class Story: NSObject {
story?.summary = title story?.summary = title
Log.append("创建story请求成功:\(story!.storyKey)") Log.append("创建story请求成功:\(story!.storyKey)")
} else { } else {
Log.append("创建story请求失败:\n\(response.debugDescription)") Log.append(error: "创建story请求失败:\n\(response.debugDescription)")
} }
} }
return story return story
...@@ -61,7 +60,6 @@ class Story: NSObject { ...@@ -61,7 +60,6 @@ class Story: NSObject {
/// 关联文档与story /// 关联文档与story
func connect(to pageId: String, with pageLastFetchTime: String) { func connect(to pageId: String, with pageLastFetchTime: String) {
Log.append("关联story与wiki")
let url = URL(string: "http://wiki.wanmeizhensuo.com/rest/highlighting/1.0/insert-storage-fragment")! let url = URL(string: "http://wiki.wanmeizhensuo.com/rest/highlighting/1.0/insert-storage-fragment")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
...@@ -79,11 +77,11 @@ class Story: NSObject { ...@@ -79,11 +77,11 @@ class Story: NSObject {
if json { if json {
Log.append("关联story与wiki成功") Log.append("关联story与wiki成功")
} else { } else {
Log.append("关联story与wiki失败,很有可能是文档中没有\"项目背景\"四个字。response:\n \(response.debugDescription)") Log.append(error: "关联story与wiki失败,很有可能是文档中没有\"项目背景\"四个字。response:\n \(response.debugDescription)")
} }
return return
} else { } else {
Log.append("关联story与wiki失败,json没有正常解析。response:\n \(response.debugDescription)") Log.append(error: "关联story与wiki失败,json没有正常解析。response:\n \(response.debugDescription)")
} }
} }
} }
...@@ -91,14 +89,13 @@ class Story: NSObject { ...@@ -91,14 +89,13 @@ class Story: NSObject {
/// 修改story的“指派人” /// 修改story的“指派人”
/// 修改story所在的sprint /// 修改story所在的sprint
func editStoryInfo(assignee: String) { func editStoryInfo(assignee: String) {
Log.append("编辑story的assign与sprint")
let url = URL(string: "http://jira.wanmeizhensuo.com/secure/QuickEditIssue.jspa?issueId=\(storyId)&decorator=none")! let url = URL(string: "http://jira.wanmeizhensuo.com/secure/QuickEditIssue.jspa?issueId=\(storyId)&decorator=none")!
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
guard let formString = getEditIssueFormdata(assignee: assignee) else { guard let formString = getEditIssueFormdata(assignee: assignee) else {
Log.append("editStoryInfo 失败") Log.append(error: "editStoryInfo 失败")
return return
} }
...@@ -128,21 +125,21 @@ class Story: NSObject { ...@@ -128,21 +125,21 @@ class Story: NSObject {
} }
if json == nil { if json == nil {
Log.append("secure/QuickEditIssue出错") Log.append(error: "secure/QuickEditIssue出错")
return nil return nil
} }
guard let formToken = json!["formToken"] as? String else { guard let formToken = json!["formToken"] as? String else {
Log.append("formToken出错") Log.append(error: "formToken出错")
return nil return nil
} }
guard let atl_token = json!["atl_token"] as? String else { guard let atl_token = json!["atl_token"] as? String else {
Log.append("atl_token出错") Log.append(error: "atl_token出错")
return nil return nil
} }
let formData = "id=\(storyId)&atl_token=\(atl_token)&formToken=\(formToken)&assignee=\(assignee)&customfield_10005=\(RepeatedWork.jira!.currentSprint!.id)&isCreateIssue=false&isEditIssue=true&summary=\(summary)&issuetype=10001&reporter=wangyang&description=开始时间%2B开发人员%2B任务名称%2B预计开发时间" let formData = "id=\(storyId)&atl_token=\(atl_token)&formToken=\(formToken)&assignee=\(assignee)&customfield_10005=\(JiraAutomator.shared.currentSprint!.id)&isCreateIssue=false&isEditIssue=true&summary=\(summary)&issuetype=10001&reporter=wangyang&description=开始时间%2B开发人员%2B任务名称%2B预计开发时间"
return formData return formData
} }
...@@ -171,7 +168,7 @@ class Story: NSObject { ...@@ -171,7 +168,7 @@ class Story: NSObject {
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let formString = "pid=\(pid)&issuetype=\(RepeatedWork.jira!.subtask_id)&parentIssueId=\(storyId)&atl_token=\(subtask_atl_token)&formToken=\(subtask_formToken)&summary=\(summary)&isCreateIssue=true&assignee=\(assignee)&reporter=wangyang&priority=3&issuelinks=issuelinks&issuelinks-linktype=blocks&isCreateIssue=true&isEditIssue=false&" let formString = "pid=\(pid)&issuetype=\(JiraAutomator.shared.jira!.subtask_id)&parentIssueId=\(storyId)&atl_token=\(subtask_atl_token)&formToken=\(subtask_formToken)&summary=\(summary)&isCreateIssue=true&assignee=\(assignee)&reporter=wangyang&priority=3&issuelinks=issuelinks&issuelinks-linktype=blocks&isCreateIssue=true&isEditIssue=false&"
let formData = formString.data(using: .utf8) let formData = formString.data(using: .utf8)
request.httpBody = formData request.httpBody = formData
...@@ -199,36 +196,36 @@ class Story: NSObject { ...@@ -199,36 +196,36 @@ class Story: NSObject {
} }
if json == nil { if json == nil {
Log.append("secure/QuickEditIssue出错") Log.append(error: "secure/QuickEditIssue出错")
return return
} }
guard let formToken = json!["formToken"] as? String else { guard let formToken = json!["formToken"] as? String else {
Log.append("formToken出错") Log.append(error: "formToken出错")
return return
} }
self.subtask_formToken = formToken self.subtask_formToken = formToken
guard let atl_token = json!["atl_token"] as? String else { guard let atl_token = json!["atl_token"] as? String else {
Log.append("atl_token出错") Log.append(error: "atl_token出错")
return return
} }
self.subtask_atl_token = atl_token self.subtask_atl_token = atl_token
guard let fields = json!["fields"] as? [[String: Any]] else { guard let fields = json!["fields"] as? [[String: Any]] else {
Log.append("fields出错") Log.append(error: "fields出错")
return return
} }
if fields.count == 0 { if fields.count == 0 {
Log.append("fields.count == 0 出错") Log.append(error: "fields.count == 0 出错")
return return
} }
let firstField = fields[0] let firstField = fields[0]
let editHtml = firstField["editHtml"] as! String let editHtml = firstField["editHtml"] as! String
guard let projectHtml = try? HTML(html: editHtml, encoding: .utf8) else { guard let projectHtml = try? HTML(html: editHtml, encoding: .utf8) else {
Log.append("projectHtml出错") Log.append(error: "projectHtml出错")
return return
} }
......
...@@ -9,130 +9,71 @@ ...@@ -9,130 +9,71 @@
import Cocoa import Cocoa
import Kanna import Kanna
enum SprintState: String {
case future = "FUTURE"
case active = "ACTIVE"
case none = ""
}
struct Sprint {
let name: String
let id: Int
let stateKey: SprintState
init(dic: [String: Any]) {
if let name = dic["name"] as? String,
let id = dic["id"] as? Int,
let stateKey = dic["stateKey"] as? String,
let s = SprintState(rawValue: stateKey) {
self.name = name
self.id = id
self.stateKey = s
} else {
name = ""
id = 0
stateKey = .none
}
}
}
class ViewController: NSViewController { class ViewController: NSViewController {
@IBOutlet var logTextView: NSTextView! @IBOutlet var logTextView: NSTextView!
@IBOutlet weak var urlTextField: NSTextField! @IBOutlet weak var urlTextField: NSTextField!
@IBOutlet weak var versionPopup: NSPopUpButton! @IBOutlet weak var sprintPopup: NSPopUpButton!
@IBOutlet weak var segment: NSSegmentedControl! @IBOutlet weak var segment: NSSegmentedControl!
var jiraProjects: [Int: Jira] = [:]
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
Login.loginWiki() Login.loginWiki()
Login.loginJira() Login.loginJira()
fetchJiraProjects() JiraAutomator.shared.fetchJiraSprints()
segment.selectedSegment = 0 segment.selectedSegment = 0
switchProject(segment) switchProject(segment)
} }
// 参考"获取迭代列表.md" @IBAction func switchProject(_ sender: NSSegmentedControl) {
func fetchJiraProjects() { sprintPopup.removeAllItems()
var gengmeiSprints: [Sprint] = [] sprintPopup.addItem(withTitle: "未选择版本号")
var likeSprints: [Sprint] = [] if sender.indexOfSelectedItem == 0 {
let url = URL(string: "http://jira.wanmeizhensuo.com/rest/greenhopper/1.0/sprint/picker?query=&_=1552128647090")! JiraAutomator.shared.switchProject(type: .gengmei)
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.sync { [weak self] (data, response, error) in
if data == nil {
Log.append(error)
return
}
if self == nil {
Log.append("fetchSprintList self 为空")
return
}
if let json = (try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments)) as? [String: Any] {
guard let sprints = json["suggestions"] as? [[String: Any]] else {
Log.append("json中没有suggestions")
return
}
for sprintDic in sprints {
if let boardName = sprintDic["boardName"] as? String {
if boardName == "Alpha" {
let sprint = Sprint(dic: sprintDic)
likeSprints.append(sprint)
} else if boardName == "USER board" {
let sprint = Sprint(dic: sprintDic)
gengmeiSprints.append(sprint)
}
}
}
} else { } else {
Log.append("获取迭代列表失败:\n\(response.debugDescription)") JiraAutomator.shared.switchProject(type: .like)
}
} }
sprintPopup.addItems(withTitles: JiraAutomator.shared.jira!.sprints.map { return $0.name })
// project AL: 10500
// project USER: 10108
jiraProjects = [0: Jira(jiraProjectId: "10108", sprints: gengmeiSprints),
1: Jira(jiraProjectId: "10500", sprints: likeSprints)]
}
@IBAction func switchProject(_ sender: NSSegmentedControl) {
versionPopup.removeAllItems()
versionPopup.addItem(withTitle: "未选择版本号")
RepeatedWork.jira = jiraProjects[sender.indexOfSelectedItem]!
versionPopup.addItems(withTitles: RepeatedWork.jira!.sprints.map { return $0.name })
} }
@IBAction func versionSelectionAction(_ sender: NSPopUpButton) { @IBAction func sprintSelectionAction(_ sender: NSPopUpButton) {
if sender.indexOfSelectedItem > 0 { if sender.indexOfSelectedItem > 0 {
RepeatedWork.jira?.currentSprint = RepeatedWork.jira!.sprints[sender.indexOfSelectedItem - 1] JiraAutomator.shared.currentSprint? = JiraAutomator.shared.jira!.sprints[sender.indexOfSelectedItem - 1]
} else { } else {
RepeatedWork.jira = nil JiraAutomator.shared.currentSprint = nil
} }
} }
@IBAction func OKAction(_ sender: Any) { @IBAction func OKAction(_ sender: Any) {
if RepeatedWork.jira == nil { if sprintPopup.indexOfSelectedItem == 0 {
Log.append("先选择版本号") Log.append(error: "先选择版本号")
return return
} }
if urlTextField.stringValue.count == 0 || if urlTextField.stringValue.count == 0 {
urlTextField.stringValue.count == 0 { Log.append(error: "填写需求列表地址")
Log.append("需求列表地址没有填写")
return return
} }
RepeatedWork.fuckit(on: urlTextField.stringValue) JiraAutomator.shared.start(on: urlTextField.stringValue)
} }
} }
class Log: NSObject { class Log: NSObject {
static func append(error logText: String) {
DispatchQueue.main.async {
if let controller = NSApplication.shared.keyWindow?.contentViewController as? ViewController {
let textStorage = controller.logTextView.textStorage!
let log = NSMutableAttributedString(string: "\n" + logText, attributes: [NSAttributedString.Key.foregroundColor : NSColor.red])
textStorage.append(log)
}
}
}
static func append(_ logText: String) { static func append(_ logText: String) {
DispatchQueue.main.async { DispatchQueue.main.async {
if let controller = NSApplication.shared.keyWindow?.contentViewController as? ViewController { if let controller = NSApplication.shared.keyWindow?.contentViewController as? ViewController {
let textStorage = controller.logTextView.textStorage! let textStorage = controller.logTextView.textStorage!
textStorage.append(NSAttributedString(string: "\n")) let log = NSMutableAttributedString(string: "\n" + logText, attributes: [NSAttributedString.Key.foregroundColor : NSColor.black])
textStorage.append(NSAttributedString(string: logText)) textStorage.append(log)
} }
} }
} }
...@@ -140,7 +81,7 @@ class Log: NSObject { ...@@ -140,7 +81,7 @@ class Log: NSObject {
static func append(_ error: Error?) { static func append(_ error: Error?) {
DispatchQueue.main.async { DispatchQueue.main.async {
if let err = error as NSError? { if let err = error as NSError? {
append(err.localizedDescription) append(error: err.localizedDescription)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment