pycontribs / jira

Python Jira library. Development chat available on https://matrix.to/#/#pycontribs:matrix.org
https://jira.readthedocs.io
BSD 2-Clause "Simplified" License
1.96k stars 873 forks source link

jira.create_sprint() returns HTTP 500 text: No content to map to Object due to end of input #1146

Closed els-pnw closed 3 years ago

els-pnw commented 3 years ago

Before raising any bug be sure that you used the latest release and that it still reproduces with the latest master. No other version is supported.

Describe the bug I am able to run code snippets such as:

jira.boards() and jira.sprints(board_id)

However, when attempting to run:

jira.create_sprint(name=sprint,
                    startDate=start_dttm,
                    endDate=end_start_dttm,
                    board_id="10875"
                    ) 

I receive the following error:

JIRAError                                 Traceback (most recent call last)
~/Documents/Git/jira-util/create-sprint.py in <module>
----> 33 jira.create_sprint(name=sprint,
      34                     startDate=start_dttm,
      35                     endDate=end_start_dttm,
      36                     board_id="10875"
      37                     )

/opt/anaconda3/lib/python3.8/site-packages/jira/client.py in create_sprint(self, name, board_id, startDate, endDate)
   4213         ):
   4214             url = self._get_url("sprint/%s" % board_id, base=self.AGILE_BASE_URL)
-> 4215             r = self._session.post(url)
   4216             raw_issue_json = json_loads(r)
   4217             """ now r contains something like:

/opt/anaconda3/lib/python3.8/site-packages/jira/resilientsession.py in post(self, url, **kwargs)
    173 
    174     def post(self, url, **kwargs):
--> 175         return self.__verb("POST", url, **kwargs)
    176 
    177     def put(self, url, **kwargs):

/opt/anaconda3/lib/python3.8/site-packages/jira/resilientsession.py in __verb(self, verb, url, retry_data, **kwargs)
    166         if exception is not None:
    167             raise exception
--> 168         raise_on_error(response, verb=verb, **kwargs)
    169         return response
    170 

/opt/anaconda3/lib/python3.8/site-packages/jira/resilientsession.py in raise_on_error(r, verb, **kwargs)
     51             except ValueError:
     52                 error = r.text
---> 53         raise JIRAError(
     54             r.status_code, error, r.url, request=request, response=r, **kwargs
     55         )

JIRAError: JiraError HTTP 500 url: https://issues.example.com/rest/greenhopper/1.0/sprint/10875
    text: No content to map to Object due to end of input

To Reproduce Steps to reproduce the behavior:

jira = JIRA(server="https://issues.example.com", 
            basic_auth=(os.environ.get('user'), os.environ.get('password')))

jira.create_sprint(name=sprint,
                    startDate=start_dttm,
                    endDate=end_start_dttm,
                    board_id="10875"
                    ) 
  1. Any additional steps or considerations that happen before or after. I tried:
    
    options = {"server": "https://issues.example.com"}

gh = GreenHopper(options, basic_auth=(os.environ.get('user'), os.environ.get('password')))

%%

gh.create_sprint(sprint, 10875, start_dttm, end_start_dttm, )

With the same result.

**Expected behavior**
Sprint should be created.

**Stack Trace**

JIRAError Traceback (most recent call last) ~/Documents/Git/jira-util/create-sprint.py in ----> 33 jira.create_sprint(name=sprint, 34 startDate=start_dttm, 35 endDate=end_start_dttm, 36 board_id="10875" 37 )

/opt/anaconda3/lib/python3.8/site-packages/jira/client.py in create_sprint(self, name, board_id, startDate, endDate) 4213 ): 4214 url = self._get_url("sprint/%s" % board_id, base=self.AGILE_BASE_URL) -> 4215 r = self._session.post(url) 4216 raw_issue_json = json_loads(r) 4217 """ now r contains something like:

/opt/anaconda3/lib/python3.8/site-packages/jira/resilientsession.py in post(self, url, kwargs) 173 174 def post(self, url, kwargs): --> 175 return self.__verb("POST", url, kwargs) 176 177 def put(self, url, kwargs):

/opt/anaconda3/lib/python3.8/site-packages/jira/resilientsession.py in __verb(self, verb, url, retry_data, kwargs) 166 if exception is not None: 167 raise exception --> 168 raise_on_error(response, verb=verb, kwargs) 169 return response 170

/opt/anaconda3/lib/python3.8/site-packages/jira/resilientsession.py in raise_on_error(r, verb, kwargs) 51 except ValueError: 52 error = r.text ---> 53 raise JIRAError( 54 r.status_code, error, r.url, request=request, response=r, kwargs 55 )

JIRAError: JiraError HTTP 500 url: https://issues.example.com/rest/greenhopper/1.0/sprint/10875 text: No content to map to Object due to end of input



**Version Information**
Type of Jira instance:
- [ ] Jira Cloud (Hosted by Atlassian)
- [x] Jira Server or Data Center (Self-hosted)
Python Interpreter: python 3.8.10
jira-python: 3.1.0
OS: MacOS Intel

Other Dependencies:
dotenv
adehad commented 3 years ago

I wonder if the endpoint URL needs to change to be agile instead of greenhopper https://docs.atlassian.com/jira-software/REST/7.3.1/#agile/1.0/sprint-createSprint

from jira.resources import GreenHopperResource

jira = JIRA(server="https://issues.example.com", 
            basic_auth=(os.environ.get('user'), os.environ.get('password')),
            options={"agile_rest_path": GreenHopperResource.AGILE_BASE_REST_PATH},
)

jira.create_sprint(name=sprint,
                    startDate=start_dttm,
                    endDate=end_start_dttm,
                    board_id="10875"
                    ) 
els-pnw commented 3 years ago

I believe it does, looks like this will work using curl:

curl -X "POST" "https://jira.foo.bar/rest/agile/1.0/sprint" \
     -H 'Content-Type: application/json' \
     -u 'user:pass' \
     -d $'{
  "startDate": "2021-11-09T00:00:00.000-07:00",
  "name": "cool name",
  "endDate": "2021-11-23T23:59:00.000-07:00",
  "originBoardId": xxxxxx
}'
els-pnw commented 3 years ago

The code modification from @adehad worked - thank you!

adehad commented 3 years ago

FYI @els-pnw #1186 aims to make this the default behaviour so you won't need to specify this manually once this is added to a release