-
-
Notifications
You must be signed in to change notification settings - Fork 349
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(release): Scripts to publish automatically a release. (#852)
- Loading branch information
1 parent
3bd2965
commit 7a4a80d
Showing
2 changed files
with
348 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import json as json_converter | ||
import os | ||
import re | ||
import requests | ||
|
||
|
||
def _file_value(settings_filename, expected): | ||
with open(settings_filename) as settings: | ||
for line in settings: | ||
key, value = line.split(':')[:2] | ||
if key == expected: | ||
return value | ||
raise EOFError | ||
|
||
|
||
def _os_value(key, default_value=None): | ||
try: | ||
return os.environ[key] | ||
except KeyError: | ||
return default_value | ||
|
||
|
||
class GitHubRelease(object): | ||
base_url = 'https://api.github.com/repos/INRIA/spoon' | ||
|
||
def __init__(self, settings_file): | ||
super(GitHubRelease, self).__init__() | ||
self.settings_file = settings_file | ||
|
||
def _headers(self): | ||
return { | ||
'Authorization': 'Token ' + _file_value(self.settings_file, 'TOKEN') | ||
} | ||
|
||
def get(self, url): | ||
response = requests.get(self.base_url + url, headers=self._headers()) | ||
return json_converter.loads(response.text) | ||
|
||
def post(self, url, data=None, json=None, headers=None): | ||
if not json: | ||
json = {} | ||
if not headers: | ||
headers = self._headers() | ||
if not data: | ||
data = {} | ||
response = requests.post(self.base_url + url, data=data, json=json, headers=headers) | ||
return json_converter.loads(response.text) | ||
|
||
def delete(self, url): | ||
requests.delete(self.base_url + url, headers=self._headers()) | ||
|
||
def _create(self, tag, name): | ||
return self.post('/releases', json={ | ||
'tag_name': tag, | ||
'name': name, | ||
'body': 'Changelog here.' | ||
}) | ||
|
||
def _upload_asset(self, upload_url, filename): | ||
self.base_url = upload_url.replace('{?name,label}', '?name={}'.format(os.path.basename(filename))) | ||
headers = self._headers() | ||
headers['Content-Type'] = 'application/zip' | ||
data = open(filename, 'r').read() | ||
return self.post('', data=data, headers=headers) | ||
|
||
def perform(self, tag, name, assets): | ||
release = self._create(tag, name) | ||
for asset in assets: | ||
self._upload_asset(release['upload_url'], asset[1]) | ||
|
||
|
||
class GforgeRelease(object): | ||
base_url = 'https://gforge.inria.fr' | ||
id_spoon = '86' | ||
group_spoon = '73' | ||
session = requests.Session() | ||
|
||
def __init__(self, settings_file): | ||
super(GforgeRelease, self).__init__() | ||
self.settings_file = settings_file | ||
|
||
def get(self, url, params=None): | ||
if not params: | ||
params = {} | ||
return self.session.get(self.base_url + url, params=params) | ||
|
||
def post(self, url, data=None, files=None): | ||
if not data: | ||
data = {} | ||
if not files: | ||
files = {} | ||
return self.session.post(self.base_url + url, data=data, files=files) | ||
|
||
def login(self, return_to='/'): | ||
self.session = requests.Session() | ||
url = '/plugins/authbuiltin/post-login.php' | ||
response = self.get(url) | ||
form_key = re.search('<input type="hidden" name="form_key" value="(.*)" />', response.text) | ||
payload = { | ||
'form_loginname': _file_value(self.settings_file, 'USERNAME'), | ||
'form_pw': _file_value(self.settings_file, 'PASSWORD_FORGE'), | ||
'return_to': return_to, | ||
'form_key': form_key.group(1), | ||
'login': 'Identification' | ||
} | ||
return self.get(url, payload) | ||
|
||
def _create(self, name, asset): | ||
self.login('/frs/?view=qrs&group_id={}'.format(self.group_spoon)) | ||
url = '/frs/?group_id={}&action=addrelease'.format(self.group_spoon) | ||
payload = { | ||
'package_id': self.id_spoon, | ||
'release_name': re.search('Spoon ([0-9]+.[0-9]+.[0-9]+)', name).group(1), | ||
'type_id': asset[0], | ||
'processor_id': '100', | ||
'release_changes': 'Changelog here.', | ||
'release_notes': '', | ||
'preformatted': '1', | ||
'submit': 'Create release' | ||
} | ||
files = { | ||
'userfile': open(asset[1], 'r') | ||
} | ||
return self.post(url, data=payload, files=files) | ||
|
||
def _upload_asset(self, release_id, asset): | ||
self.login( | ||
'/frs/?view=editrelease&group_id={}&package_id={}&release_id={}' | ||
.format(self.group_spoon, self.id_spoon, release_id)) | ||
url = '/frs/?group_id={}&package_id={}&release_id={}&action=addfile' \ | ||
.format(self.group_spoon, self.id_spoon, release_id) | ||
payload = { | ||
'type_id': asset[0], | ||
'processor_id': '100', | ||
'submit': 'Add This File' | ||
} | ||
files = { | ||
'userfile': open(asset[1], 'r') | ||
} | ||
return self.post(url, data=payload, files=files) | ||
|
||
def perform(self, name, assets): | ||
response = self._create(name, assets[0]) | ||
release_id = re.search('<tr id="releaseid([0-9]+)" class="bgcolor-white ff">', response.text).group(1) | ||
for asset in assets[1:]: | ||
self._upload_asset(release_id, asset) | ||
|
||
|
||
type_ = _os_value('TYPE', 'minor') | ||
settings_file = _os_value('SETTINGS_PATH', '/builds/resources/settings.txt') | ||
release = _os_value('RELEASE') | ||
|
||
tag_name = 'spoon-core-{}'.format(release) | ||
name = 'Spoon {}'.format(release) | ||
assets = [ | ||
('3000', 'target/{}.jar'.format(tag_name)), | ||
('5000', 'target/{}-jar-with-dependencies.jar'.format(tag_name)), | ||
('8200', 'target/{}-javadoc.jar'.format(tag_name)), | ||
('5000', 'target/{}-sources.jar'.format(tag_name)) | ||
] | ||
github = GitHubRelease(settings_file) | ||
github.perform(tag_name, name, assets) | ||
|
||
gforge = GforgeRelease(settings_file) | ||
gforge.perform(name, assets) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
#!/bin/bash | ||
# | ||
# Deploys a new release of Spoon. This script uses the maven | ||
# release plugin to deploy the project or rollback if we got any | ||
# error during the deployment. | ||
# Note that this script doesn't make the git clone. Think to do it by yourself | ||
# or to execute this script in a Spoon repository. | ||
|
||
USER_SERVER="spoon-bot" | ||
SERVER="${USER_SERVER}@scm.gforge.inria.fr" | ||
HOST_DESTINATION="/home/groups/spoon/" | ||
FOLDER_DESTINATION="spoon.git" | ||
DESTINATION="${HOST_DESTINATION}${FOLDER_DESTINATION}/" | ||
|
||
# Determine the type. | ||
|
||
MAJOR=0 | ||
MINOR=1 | ||
PATCH=2 | ||
TYPES=('major' 'minor' 'patch') | ||
if [ -z "$TYPE" ]; then | ||
TYPE='minor' | ||
fi | ||
if ! [[ ${TYPES[*]} =~ "$TYPE" ]]; then | ||
echo "Error: type should be 'major', 'minor' or 'patch'!" | ||
exit 1 | ||
fi | ||
if [[ ${TYPES[$PATCH]} = $TYPE ]]; then | ||
git checkout stable | ||
fi | ||
|
||
# Save the current release version. | ||
|
||
RELEASE_TEXT=$(grep "^spoon_release:" doc/_jekyll/_config.yml | cut -d' ' -f2-) | ||
REGEX="^\"([0-9]+).([0-9]+).([0-9]+)\"$" | ||
if [[ $RELEASE_TEXT =~ $REGEX ]]; then | ||
RVERSIONS[0]="${BASH_REMATCH[1]}" | ||
RVERSIONS[1]="${BASH_REMATCH[2]}" | ||
RVERSIONS[2]="${BASH_REMATCH[3]}" | ||
else | ||
echo "Error: Can't get the last release version from jekyll config file." | ||
exit 1 | ||
fi | ||
|
||
# Save the next version. | ||
|
||
if [[ ${TYPES[$MAJOR]} = $TYPE ]]; then | ||
NSVERSIONS[0]=$((RVERSIONS[0] + 1)) | ||
NSVERSIONS[1]=1 | ||
NSVERSIONS[2]=0 | ||
NRVERSIONS[0]=$((RVERSIONS[0] + 1)) | ||
NRVERSIONS[1]=0 | ||
NRVERSIONS[2]=0 | ||
elif [[ ${TYPES[$MINOR]} = $TYPE ]]; then | ||
NSVERSIONS[0]=${RVERSIONS[0]} | ||
NSVERSIONS[1]=$((RVERSIONS[1] + 2)) | ||
NSVERSIONS[2]=0 | ||
NRVERSIONS[0]=${RVERSIONS[0]} | ||
NRVERSIONS[1]=$((RVERSIONS[1] + 1)) | ||
NRVERSIONS[2]=0 | ||
elif [[ ${TYPES[$PATCH]} = $TYPE ]]; then | ||
NSVERSIONS[0]=${RVERSIONS[0]} | ||
NSVERSIONS[1]=$((RVERSIONS[1] + 1)) | ||
NSVERSIONS[2]=0 | ||
NRVERSIONS[0]=${RVERSIONS[0]} | ||
NRVERSIONS[1]=${RVERSIONS[1]} | ||
NRVERSIONS[2]=$((RVERSIONS[2] + 1)) | ||
fi | ||
|
||
OLD_RELEASE="${RVERSIONS[0]}.${RVERSIONS[1]}.${RVERSIONS[2]}" | ||
NEXT_SNAPSHOT="${NSVERSIONS[0]}.${NSVERSIONS[1]}.${NSVERSIONS[2]}-SNAPSHOT" | ||
NEXT_RELEASE="${NRVERSIONS[0]}.${NRVERSIONS[1]}.${NRVERSIONS[2]}" | ||
TAG="spoon-core-$NEXT_RELEASE" | ||
|
||
echo "You'll create a $TYPE version $NEXT_RELEASE and the next snapshot will be $NEXT_SNAPSHOT" | ||
|
||
# Release to Maven Central. | ||
|
||
mvn release:clean | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't clean the project for the release!" | ||
mvn release:rollback | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't rollback at the clean step!" | ||
fi | ||
exit 1 | ||
fi | ||
|
||
mvn release:prepare -DreleaseVersion=$NEXT_RELEASE -DdevelopmentVersion=$NEXT_SNAPSHOT -Dtag=$TAG | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't prepare the project for the release!" | ||
mvn release:rollback | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't rollback at the prepare step!" | ||
fi | ||
exit 1 | ||
fi | ||
|
||
mvn release:perform -Dusername=$USER_SERVER | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't perform the project for the release!" | ||
mvn release:rollback | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't rollback at the perform step!" | ||
fi | ||
exit 1 | ||
fi | ||
|
||
# Updates Jekyll documentation. | ||
|
||
sed -i -re "s/^spoon_release: \"[0-9]+.[0-9]+.[0-9]+\"/spoon_release: \"$NEXT_RELEASE\"/;s/^sidebar_version: version [0-9]+.[0-9]+.[0-9]+/sidebar_version: version $NEXT_RELEASE/;s/^spoon_snapshot: \"[0-9]+.[0-9]+.[0-9]+-SNAPSHOT\"/spoon_snapshot: \"$NEXT_SNAPSHOT\"/" doc/_config.yml | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't update new versions in the jekyll config file." | ||
echo "rollback at the previous state..." | ||
git checkout doc/_config.yml | ||
exit 1 | ||
fi | ||
|
||
DATE=$(date +"%B %d, %Y: Spoon $NEXT_RELEASE is released.") | ||
DATE="$(tr '[:lower:]' '[:upper:]' <<< ${DATE:0:1})${DATE:1}" | ||
DATE="- $DATE" | ||
awk -i inplace -v date="$DATE" '{print} /^<!-- .* Marker comment. -->$/ {print date}' doc/doc_homepage.md | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't update news feed in the website." | ||
echo "rollback at the previous state..." | ||
git checkout doc/doc_homepage.md | ||
exit 1 | ||
fi | ||
|
||
# Updates Readme. | ||
|
||
sed -i -re "s/<version>$OLD_RELEASE<\/version>/<version>$NEXT_RELEASE<\/version>/;s/<version>[0-9]+.[0-9]+.[0-9]+-SNAPSHOT<\/version>/<version>$NEXT_SNAPSHOT<\/version>/" README.md | ||
if [ "$?" -ne 0 ]; then | ||
echo "Can't update new versions in the README file." | ||
echo "rollback at the previous state..." | ||
git checkout README.md | ||
exit 1 | ||
fi | ||
|
||
# Commit changes. | ||
|
||
echo "What is changes?" | ||
|
||
git diff | ||
git add . --all | ||
git commit -m "docs(version): Updates documentation." | ||
if [[ ${TYPES[$PATCH]} = $TYPE ]]; then | ||
git push origin stable | ||
else | ||
git push origin master | ||
fi | ||
|
||
# Updates stable branch. | ||
|
||
if [[ ${TYPES[$PATCH]} != $TYPE ]]; then | ||
git checkout master | ||
git branch -D stable | ||
git checkout -b stable | ||
git push origin stable -f | ||
fi | ||
|
||
# Retrieves all commits and tag from GitHub repo to INRIA Forge. | ||
|
||
ssh -A $SERVER "cd ${DESTINATION} && git fetch origin master:master" | ||
if [ "$?" -ne 0 ]; then | ||
echo "Error when you fetch sources from GitHub for the master branch!" | ||
exit 1 | ||
fi | ||
|
||
ssh -A $SERVER "cd ${DESTINATION} && git fetch origin stable:stable" | ||
if [ "$?" -ne 0 ]; then | ||
echo "Error when you fetch sources from GitHub for the stable branch!" | ||
exit 1 | ||
fi | ||
|
||
ssh -A $SERVER "cd ${DESTINATION} && git fetch --tags" | ||
if [ "$?" -ne 0 ]; then | ||
echo "Error when you fetch tags!" | ||
exit 1 | ||
fi | ||
|
||
echo RELEASE="$NEXT_RELEASE" > target/variables.properties | ||
echo SNAPSHOT="$NEXT_SNAPSHOT" >> target/variables.properties |