Create Release
Creating an Octopus release when a DataStar project uses dynamic package selection takes a little care. The release has multiple packages (the scripts, DataStar.Tools, templates), and the dynamically-named one needs its version set separately from the release version.
Manual release
Manual release creation works for reversal projects, where reverting is an exceptional action. In the create-release dialog:
- Click Expand All to see the package-version fields.
- Set the Version to
<WorkItem>.<Revision>, for example243432.76if the package isDAT-243432.76.nupkg. - Set the dynamic package version to just the revision,
76.

Automated release
For the deployment project, create the release from the CI pipeline. The script below uses the Octopus REST API; translate to another language freely if Python isn't convenient.
The script:
- Looks up the Octopus space id by name.
- Looks up the project id inside that space.
- Looks up the channel id inside that project.
- For each package the project references, picks the latest published version, except for the dynamic package, which uses the version passed in.
- Creates the release with those package versions resolved.
import json
import requests
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-b', '--base', type=str, required=True)
parser.add_argument('-a', '--apikey', type=str, required=True)
parser.add_argument('-w', '--workitem', type=int, required=True)
parser.add_argument('-v', '--version', type=int, required=True)
parser.add_argument('-c', '--channel', type=str, required=False)
parser.add_argument('-p', '--project', type=str, required=True)
parser.add_argument('-s', '--space', type=str, required=True)
args = parser.parse_args()
spaceName = args.space
projectName = args.project
channelName = "Default"
if args.channel:
channelName = args.channel
workItem = str(args.workitem)
version = str(args.version)
packageVersion = workItem + '.' + version
session = requests.Session()
session.headers.update({'X-Octopus-ApiKey': str(args.apikey)})
response = session.get(str(args.base) + '/spaces/all')
if response.status_code != 200:
print('Error response ' + str(response.status_code) + ' looking up space ' + args.story)
raise SystemExit(1)
spaceId = None
spaces = json.loads(response.content)
for item in spaces:
if item['Name'] == spaceName:
spaceId = item['Id']
break
if spaceId is None:
print('Error response failed to locate spaceId for name ' + spaceName)
raise SystemExit(1)
response = session.get(str(args.base) + "/" + spaceId + '/projects/all')
if response.status_code != 200:
print('Error response ' + str(response.status_code) + ' looking up project ' + projectName)
raise SystemExit(1)
projectId = None
projects = json.loads(response.content)
for item in projects:
if item['Name'] == projectName:
projectId = item['Id']
break
if projectId is None:
print('Error response failed to locate projectId for name ' + projectName)
raise SystemExit(1)
response = session.get(str(args.base) + '/projects/' + projectId + "/channels")
if response.status_code != 200:
print('Error response ' + str(response.status_code) + ' looking up channels')
raise SystemExit(1)
channelId = None
channels = json.loads(response.content)
for item in channels['Items']:
if item['Name'] == channelName:
channelId = item['Id']
break
if channelId is None:
print('Error response failed to locate channelId for name ' + channelName)
raise SystemExit(1)
response = session.get(str(args.base) + '/'
+ spaceId + '/deploymentprocesses/deploymentprocess-'
+ projectId + '/template?channel=' + channelId)
# Create the release body
releaseBody = json.loads('{{ "ChannelId": "{0}", "ProjectId": "{1}", "Version": "{2}", "SelectedPackages": [] }}'.format(channelId, projectId, packageVersion))
templates = json.loads(response.content)
for item in templates['Packages']:
response = session.get(str(args.base) + '/' + spaceId + '/feeds/'
+ item['FeedId'] + '/packages/versions?packageId='
+ item['PackageId'] + '&take=1')
versionSpec = packageVersion
versionInfo = json.loads(response.content)
for versionItem in versionInfo['Items']:
versionSpec = versionItem['Version']
break
if versionSpec == packageVersion:
versionSpec = version
releaseBody['SelectedPackages'] \
.append(json.loads('{{ "ActionName": "{0}", "PackageReferenceName": "{1}", "Version": "{2}" }}'
.format(item['ActionName'], item['PackageReferenceName'], versionSpec)))
print('Creating Release:' + json.dumps(releaseBody))
result = session.post(str(args.base) + '/' + spaceId
+ '/releases?ignoreChannelRules=false', data=json.dumps(releaseBody))
if result.status_code != 200 | result.status_code != 201:
print('Error response ' + str(result.status_code) + ' message: ' + str(result.content))
raise SystemExit(1)