├── .travis.yml
├── src
└── main
│ ├── resources
│ └── IssuesDownload.properties
│ └── java
│ └── io
│ └── github
│ └── psgs
│ └── issuesdownload
│ ├── Config.java
│ ├── IssuesDownload.java
│ └── gui
│ ├── GUI.form
│ └── GUI.java
├── .gitattributes
├── .gitignore
├── pom.xml
└── README.md
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk6
4 | - openjdk7
5 | notifications:
6 | email: false
--------------------------------------------------------------------------------
/src/main/resources/IssuesDownload.properties:
--------------------------------------------------------------------------------
1 | ############################################################
2 | # Issues Download - Download GitHub issues for offline use #
3 | # Made by psgs #
4 | ############################################################
5 |
6 | GitHub-Token = " "
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/src/main/java/io/github/psgs/issuesdownload/Config.java:
--------------------------------------------------------------------------------
1 | package io.github.psgs.issuesdownload;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileNotFoundException;
5 | import java.io.IOException;
6 | import java.util.Properties;
7 |
8 | public class Config {
9 |
10 | public static String githubtoken;
11 |
12 | public static void loadConfiguration() throws FileNotFoundException, IOException {
13 |
14 | Properties config = new Properties();
15 | config.load(new FileInputStream("IssuesDownload.properties"));
16 |
17 | githubtoken = config.getProperty("GitHub-Token");
18 |
19 | }
20 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 |
20 | # External tool builders
21 | .externalToolBuilders/
22 |
23 | # Locally stored "Eclipse launch configurations"
24 | *.launch
25 |
26 | # CDT-specific
27 | .cproject
28 |
29 | # PDT-specific
30 | .buildpath
31 |
32 | ############
33 | ## Windows
34 | ############
35 |
36 | # Windows image file caches
37 | Thumbs.db
38 |
39 | # Folder config file
40 | Desktop.ini
41 |
42 | # Installer logs
43 | pip-log.txt
44 |
45 | # Unit test / coverage reports
46 | .coverage
47 | .tox
48 |
49 | #Translations
50 | *.mo
51 |
52 | #Mr Developer
53 | .mr.developer.cfg
54 |
55 | # Mac crap
56 | .DS_Store
57 |
58 | #################
59 | ## Various
60 | #################
61 |
62 | # NetBeans
63 | /nbproject
64 |
65 | # Maven
66 | /target
67 | */target
68 | /dependency-reduced-pom.xml
69 |
70 | # vim
71 | .*.sw[a-p]
72 |
73 | # Various other potential build files
74 | /build
75 | /bin
76 | /dist
77 | /manifest.mf
78 |
79 | /world
80 |
81 | # Mac filesystem dust
82 | .DS_Store
83 |
84 | # IntelliJ
85 | *.iml
86 | *.ipr
87 | *.iws
88 | .idea/
89 |
90 | #############
91 | ## Gradle
92 | #############
93 |
94 | .gradle
95 | build
96 | out
97 |
98 | gradlew
99 | gradlew.bat
100 | gradle
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | IssuesDownload
8 | IssuesDownload
9 | 1.0-RELEASE
10 |
11 |
12 |
13 | org.kohsuke
14 | github-api
15 | 1.49
16 |
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-shade-plugin
24 | 2.1
25 |
26 |
27 | package
28 |
29 | shade
30 |
31 |
32 |
33 |
35 | io.github.psgs.issuesdownload.IssuesDownload
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Issues Download [](https://travis-ci.org/psgs/IssuesDownload) [](https://bitdeli.com/free "Bitdeli Badge")
2 | ====================
3 |
4 | Issues Download is a lightweight java application that will pull issues from a github.com repository, and write them to a .csv file. IssuesDownload uses [Kohsuke Kawaguchi's GitHub API for Java](http://github-api.kohsuke.org) to connect to GitHub when writing issues.
5 |
6 | To run the application once compiled, simply run the .jar file that should have been compiled.
7 | Once the process is complete, a .csv file should contain issue information in the .jar file directory.
8 | Please Note: When the .jar file is run, it will overwrite any other issues.csv files in the jar file directory.
9 |
10 | If downloading Issues doesn't work after multiple tries, you may need to copy the [IssuesDownload properties file](https://github.com/psgs/IssuesDownload/blob/master/src/main/resources/IssuesDownload.properties), and place it in the same directory as the .jar file, then edit the file to contain your [personal or an application access token](https://help.github.com/articles/creating-an-access-token-for-command-line-use).
11 |
12 | Releases
13 | --------
14 |
15 | - [v1.0](https://github.com/psgs/IssuesDownload/releases/download/v1.0/IssuesDownload-1.0-RELEASE.jar)
16 |
17 | Screenshots
18 | -----------
19 |
20 | 
21 |
22 | CSV Format
23 | ----------
24 |
25 | The .csv format used is as follows:
26 | Id, Title, Creator, Assignee, Milestone, State, Body Text.
27 |
28 | The first line of the csv file shows the format used, and therefore does not display any information pulled from issues.
29 |
30 | ID | Title | Creator | Assignee | Milestone | State | Body Text
31 | ------------ | ------------- | ------------- | ------------- | ------------- | ------------- | -------------
32 | 1 | Add a Bitdeli Badge to README | bitdeli-chef | psgs | First-Release | CLOSED | Pull request made by @psgs at https://bitdeli.com
33 |
34 | Compiling
35 | ---------
36 |
37 | Don't feel like compiling? You can download a pre-compiled release from the [Releases section](https://github.com/psgs/IssuesDownload#releases).
38 |
39 | IssuesDownload uses [Apache Maven 3](http://maven.apache.org/) to compile!
40 |
41 | To compile IssuesDownload, simply install [Apache Maven](http://maven.apache.org/), and run:
42 | ```mvn -f pom.xml clean install -P shade```
43 |
--------------------------------------------------------------------------------
/src/main/java/io/github/psgs/issuesdownload/IssuesDownload.java:
--------------------------------------------------------------------------------
1 | package io.github.psgs.issuesdownload;
2 |
3 | import io.github.psgs.issuesdownload.gui.GUI;
4 | import org.kohsuke.github.GHIssue;
5 | import org.kohsuke.github.GHIssueState;
6 | import org.kohsuke.github.GHRepository;
7 | import org.kohsuke.github.GitHub;
8 |
9 | import java.io.FileWriter;
10 | import java.io.IOException;
11 |
12 | public class IssuesDownload {
13 |
14 | public static void main(String[] args) {
15 | try {
16 | Config.loadConfiguration();
17 | } catch (IOException ex) {
18 | System.out.println("An IOException occurred while loading the configuration!");
19 | ex.printStackTrace();
20 | }
21 | GUI.main(args);
22 | }
23 |
24 | public static String saveIssues(String repoDetails, GHIssueState issueState) {
25 |
26 | String[] repoInfo = repoDetails.split("/");
27 |
28 | try {
29 | GitHub github = GitHub.connectUsingOAuth(Config.githubtoken);
30 | GHRepository repository = github.getUser(repoInfo[0]).getRepository(repoInfo[1]);
31 |
32 | FileWriter writer = new FileWriter("issues.csv");
33 | writer.append("Id, Title, Creator, Assignee, Milestone, State, Body Text");
34 | writer.append("\n");
35 |
36 | for (GHIssue issue : repository.getIssues(issueState)) {
37 | writer.append(String.valueOf(issue.getNumber()) + ",");
38 | writer.append(issue.getTitle() + ",");
39 | writer.append(issue.getUser().getLogin() + ",");
40 | if (issue.getAssignee() != null) {
41 | writer.append(issue.getAssignee().getName() + ",");
42 | } else {
43 | writer.append(" ,");
44 | }
45 | if (issue.getMilestone() != null) {
46 | writer.append(issue.getMilestone().getTitle() + ",");
47 | } else {
48 | writer.append(" ,");
49 | }
50 | writer.append(issue.getState() + ",");
51 | writer.append(issue.getBody() + ",");
52 | writer.append("\n");
53 | }
54 | writer.flush();
55 | writer.close();
56 | return "Download Complete!";
57 | } catch (IOException ex) {
58 | System.out.println("An IOException has occurred!");
59 | ex.printStackTrace();
60 | if (ex.getMessage().equalsIgnoreCase("api.github.com")) {
61 | return "An error has occurred reaching " + ex.getMessage() + "! Please check your network connection.";
62 | }
63 | }
64 | return "An error has occurred!";
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/io/github/psgs/issuesdownload/gui/GUI.form:
--------------------------------------------------------------------------------
1 |
2 |
3 |
138 |
--------------------------------------------------------------------------------
/src/main/java/io/github/psgs/issuesdownload/gui/GUI.java:
--------------------------------------------------------------------------------
1 | package io.github.psgs.issuesdownload.gui;
2 |
3 | import io.github.psgs.issuesdownload.IssuesDownload;
4 | import org.kohsuke.github.GHIssueState;
5 |
6 | import java.awt.*;
7 |
8 | public class GUI extends javax.swing.JFrame {
9 |
10 | public GUI() {
11 | initComponents();
12 | }
13 |
14 | @SuppressWarnings("unchecked")
15 | // //GEN-BEGIN:initComponents
16 | private void initComponents() {
17 |
18 | jPanel1 = new javax.swing.JPanel();
19 | jLabel1 = new javax.swing.JLabel();
20 | jTextField1 = new javax.swing.JTextField();
21 | jTextField2 = new javax.swing.JTextField();
22 | jButton1 = new javax.swing.JButton();
23 | jRadioButton1 = new javax.swing.JRadioButton();
24 | jRadioButton2 = new javax.swing.JRadioButton();
25 |
26 | setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
27 |
28 | jLabel1.setFont(new java.awt.Font("Tahoma", Font.BOLD, 15)); // NOI18N
29 | jLabel1.setText(" Issues Download v1.0-SNAPSHOT");
30 |
31 | jTextField1.setText("Path to Repository (psgs/IssuesDownload)");
32 |
33 | jButton1.setText("Download");
34 | jButton1.addActionListener(new java.awt.event.ActionListener() {
35 | public void actionPerformed(java.awt.event.ActionEvent evt) {
36 | jButton1ActionPerformed(evt);
37 | }
38 | });
39 |
40 | jRadioButton1.setSelected(true);
41 | jRadioButton1.setText("Open");
42 | jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
43 | public void actionPerformed(java.awt.event.ActionEvent evt) {
44 | jRadioButton1ActionPerformed(evt);
45 | }
46 | });
47 |
48 | jRadioButton2.setText("Closed");
49 | jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
50 | public void actionPerformed(java.awt.event.ActionEvent evt) {
51 | jRadioButton2ActionPerformed(evt);
52 | }
53 | });
54 |
55 | javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
56 | jPanel1.setLayout(jPanel1Layout);
57 | jPanel1Layout.setHorizontalGroup(
58 | jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
59 | .addGroup(jPanel1Layout.createSequentialGroup()
60 | .addContainerGap()
61 | .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
62 | .addComponent(jTextField2)
63 | .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
64 | .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
65 | .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
66 | .addGroup(jPanel1Layout.createSequentialGroup()
67 | .addGap(0, 0, Short.MAX_VALUE)
68 | .addComponent(jRadioButton1)
69 | .addGap(53, 53, 53)
70 | .addComponent(jRadioButton2)
71 | .addGap(36, 36, 36))
72 | .addComponent(jTextField1))
73 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
74 | .addComponent(jButton1)))
75 | .addContainerGap())
76 | );
77 | jPanel1Layout.setVerticalGroup(
78 | jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
79 | .addGroup(jPanel1Layout.createSequentialGroup()
80 | .addContainerGap()
81 | .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
82 | .addGap(18, 18, 18)
83 | .addComponent(jTextField2, javax.swing.GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE)
84 | .addGap(9, 9, 9)
85 | .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
86 | .addComponent(jRadioButton1)
87 | .addComponent(jRadioButton2))
88 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
89 | .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
90 | .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)
91 | .addComponent(jButton1))
92 | .addContainerGap())
93 | );
94 |
95 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
96 | getContentPane().setLayout(layout);
97 | layout.setHorizontalGroup(
98 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
99 | .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
100 | );
101 | layout.setVerticalGroup(
102 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
103 | .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
104 | );
105 |
106 | pack();
107 | }// //GEN-END:initComponents
108 |
109 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
110 | if (jRadioButton1.isSelected()) {
111 | jTextField2.setText(IssuesDownload.saveIssues(jTextField1.getText(), GHIssueState.OPEN));
112 | } else {
113 | jTextField2.setText(IssuesDownload.saveIssues(jTextField1.getText(), GHIssueState.CLOSED));
114 | }
115 | }//GEN-LAST:event_jButton1ActionPerformed
116 |
117 | private void jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
118 | jRadioButton2.setSelected(false);
119 | }//GEN-LAST:event_jButton1ActionPerformed
120 |
121 | private void jRadioButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
122 | jRadioButton1.setSelected(false);
123 | }//GEN-LAST:event_jButton1ActionPerformed
124 |
125 | public static void main(String args[]) {
126 | /* Set the Nimbus look and feel */
127 | //
128 | /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
129 | * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
130 | */
131 | try {
132 | for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
133 | if ("Nimbus".equals(info.getName())) {
134 | javax.swing.UIManager.setLookAndFeel(info.getClassName());
135 | break;
136 | }
137 | }
138 | } catch (ClassNotFoundException ex) {
139 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
140 | } catch (InstantiationException ex) {
141 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
142 | } catch (IllegalAccessException ex) {
143 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
144 | } catch (javax.swing.UnsupportedLookAndFeelException ex) {
145 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
146 | }
147 | //
148 |
149 | /* Create and display the form */
150 | java.awt.EventQueue.invokeLater(new Runnable() {
151 | public void run() {
152 | new GUI().setVisible(true);
153 | }
154 | });
155 | }
156 |
157 | // Variables declaration - do not modify//GEN-BEGIN:variables
158 | private javax.swing.JButton jButton1;
159 | private javax.swing.JLabel jLabel1;
160 | private javax.swing.JPanel jPanel1;
161 | private javax.swing.JRadioButton jRadioButton1;
162 | private javax.swing.JRadioButton jRadioButton2;
163 | private javax.swing.JTextField jTextField1;
164 | private javax.swing.JTextField jTextField2;
165 | // End of variables declaration//GEN-END:variables
166 | }
167 |
--------------------------------------------------------------------------------