Repository: sw360/capycli (language: python)

Issue:
feature: "project downloadattachments" / "bom uploadattachments"
I currently have the task to synchronize projects' attachments between two SW360 instances. 

In my specific case, certain projects including source attachments are uploaded into two different instances, but clearing results (e.g. reports and CLI files) are uploaded in only one of them. So the remaining bit for me would be to download those from instance A and upload it to instance B.

So my idea would be to add following two commands:

```
    bom
        UploadAttachments    upload all attachments described in a BOM e.g. created by "project DownloadAttachments"
   
    project
        DownloadAttachments    download all attachments (of certain types) and create a BOM listing them
```

This would require extending the BOM formats by some fields, probably something like 

```
 "externalReferences" : [
   {
    "type": "other",
    "url": "file:///attachments/CLIXML_keyutils_1.6-6-debian-combined.tar.bz2_2019-10-10_10_02_52.xml",
    "comment": "component license information (XML)"
    }
  ]
```

Alternatively, I could also implement "project uploadattachments", but I think with the suggestion above, it could be used flexible for multiple use cases. 

Together "project createbom", "bom map" and "bom createcomponents", I think we could even support complete project export/import use cases in the future like:

- sync projects between different SW360 instances
- archive projects from SW360 to other systems
- migrate projects between SW360 and other platforms

What do you think?



Discussion / hints:
This would also include a refactoring of "project getlicenseinfo" as this would mostly be a specific case of "project downloadattachments" then plus the HTML creation bits.

Fix patch:
diff --git a/capycli/project/get_license_info.py b/capycli/project/get_license_info.py
index d94617a..40b12a8 100644
--- a/capycli/project/get_license_info.py
+++ b/capycli/project/get_license_info.py
@@ -161,10 +161,10 @@ def show_command_help(self) -> None:
   -t SW360_TOKEN                 use this token for access to SW360
   -oa,                           this is an oauth2 token
   -url SW360_URL                 use this URL for access to SW360
-  -name                          name of the project, component or release
-  -version                       version of the project, component or release
-  -i INPUTFILE,                  existing configuration file to read from (optional)")
-  -o OUTPUTFILE                  output file to write to
+  -name                          name of the project
+  -version                       version of the project
+  -i INPUTFILE                   existing configuration file to read from (optional)
+  -o OUTPUTFILE                  write config file for "project CreateReadme"
   -dest DESTINATION              destination folder
   -ncli, --no-overwrite-cli      do not overwrite existing CLI files
   -nconf, --no-overwrite-config  do not overwrite an existing configuration file
@@ -206,10 +206,6 @@ def run(self, args):
             print_red("No destination folder specified!")
             sys.exit(ResultCode.RESULT_COMMAND_ERROR)
 
-        if not args.outputfile:
-            print_red("No project file specified!")
-            sys.exit(ResultCode.RESULT_COMMAND_ERROR)
-
         if args.inputfile:
             if not os.path.isfile(args.inputfile):
                 print_red("Input file not found!")
@@ -240,7 +236,8 @@ def run(self, args):
 
         print("")
 
-        print_text("  Writing Readme_OSS config file " + args.outputfile)
-        self.write_result(rdm_info, args.outputfile, args.nconf)
+        if args.outputfile:
+            print_text("  Writing Readme_OSS config file " + args.outputfile)
+            self.write_result(rdm_info, args.outputfile, args.nconf)
 
         print_text("\ndone.")


Test patch:
diff --git a/tests/test_get_license_info.py b/tests/test_get_license_info.py
index 7720e74..715a2f6 100644
--- a/tests/test_get_license_info.py
+++ b/tests/test_get_license_info.py
@@ -53,22 +53,6 @@ def test_no_destination(self) -> None:
         except SystemExit as ex:
             self.assertEqual(ResultCode.RESULT_COMMAND_ERROR, ex.code)
 
-    def test_no_output_file(self) -> None:
-        try:
-            sut = GetLicenseInfo()
-
-            # create argparse command line argument object
-            args = AppArguments()
-            args.command = []
-            args.command.append("project")
-            args.command.append("getlicenseinfo")
-            args.destination = ".//cli_files"
-
-            sut.run(args)
-            self.assertTrue(False, "Failed to report missing file")
-        except SystemExit as ex:
-            self.assertEqual(ResultCode.RESULT_COMMAND_ERROR, ex.code)
-
     # @responses.activate
     def test_no_login(self) -> None:
         sut = GetLicenseInfo()