Ports changelog system from /tg/station and updates Travis
Travis update is a port of Baystation12/Baystation12#10096
29
.travis.yml
@@ -1,5 +1,6 @@
|
|||||||
#pretending we're C because otherwise ruby will initialize, even with "language: dm".
|
#pretending we're C because otherwise ruby will initialize, even with "language: dm".
|
||||||
language: c
|
language: c
|
||||||
|
sudo: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
@@ -9,18 +10,30 @@ env:
|
|||||||
- DM_MAPFILE="cyberiad"
|
- DM_MAPFILE="cyberiad"
|
||||||
- DM_MAPFILE="metastation"
|
- DM_MAPFILE="metastation"
|
||||||
|
|
||||||
before_install:
|
cache:
|
||||||
- sudo apt-get update -qq
|
directories:
|
||||||
- sudo apt-get install libc6:i386 libgcc1:i386 libstdc++6:i386 -qq
|
- $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libc6-i386
|
||||||
|
- libgcc1:i386
|
||||||
|
- libstdc++6:i386
|
||||||
|
- python
|
||||||
|
- python-pip
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip
|
- pip install --user PyYaml -q
|
||||||
- unzip byond.zip
|
- pip install --user beautifulsoup4 -q
|
||||||
- cd byond
|
|
||||||
- sudo make install
|
|
||||||
- cd ..
|
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- chmod +x ./install-byond.sh
|
||||||
|
- ./install-byond.sh
|
||||||
script:
|
script:
|
||||||
- shopt -s globstar
|
- shopt -s globstar
|
||||||
- (! grep 'step_[xy]' _maps/map_files/**/*.dmm)
|
- (! grep 'step_[xy]' _maps/map_files/**/*.dmm)
|
||||||
|
- md5sum -c - <<< "6dc1b6bf583f3bd4176b6df494caa5f1 *html/changelogs/example.yml"
|
||||||
|
- python tools/ss13_genchangelog.py html/changelog.html html/changelogs
|
||||||
|
- source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup
|
||||||
- bash dm.sh -M${DM_MAPFILE} paradise.dme
|
- bash dm.sh -M${DM_MAPFILE} paradise.dme
|
||||||
|
|||||||
@@ -112,7 +112,7 @@
|
|||||||
if(self_message && M==src)
|
if(self_message && M==src)
|
||||||
msg = self_message
|
msg = self_message
|
||||||
M.show_message(msg, 2, deaf_message, 1)
|
M.show_message(msg, 2, deaf_message, 1)
|
||||||
|
|
||||||
// based on say code
|
// based on say code
|
||||||
var/omsg = replacetext(message, "<B>[src]</B> ", "")
|
var/omsg = replacetext(message, "<B>[src]</B> ", "")
|
||||||
var/list/listening_obj = new
|
var/list/listening_obj = new
|
||||||
|
|||||||
BIN
html/88x31.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
html/bug-minus.png
Normal file
|
After Width: | Height: | Size: 657 B |
BIN
html/burn-exclamation.png
Normal file
|
After Width: | Height: | Size: 727 B |
35
html/changelog.css
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
.top{font-family:Tahoma,sans-serif;font-size:12px;}
|
||||||
|
h2{font-family:Tahoma,sans-serif;}
|
||||||
|
a img {border:none;}
|
||||||
|
.bgimages16 li {
|
||||||
|
padding:2px 10px 2px 30px;
|
||||||
|
background-position:6px center;
|
||||||
|
background-repeat:no-repeat;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
border-left:4px solid #999;
|
||||||
|
margin-bottom:2px;
|
||||||
|
}
|
||||||
|
.bugfix {background-image:url(bug-minus.png)}
|
||||||
|
.wip {background-image:url(hard-hat-exclamation.png)}
|
||||||
|
.tweak {background-image:url(wrench-screwdriver.png)}
|
||||||
|
.soundadd {background-image:url(music-plus.png)}
|
||||||
|
.sounddel {background-image:url(music-minus.png)}
|
||||||
|
.rscdel {background-image:url(cross-circle.png)}
|
||||||
|
.rscadd {background-image:url(tick-circle.png)}
|
||||||
|
.imageadd {background-image:url(image-plus.png)}
|
||||||
|
.imagedel {background-image:url(image-minus.png)}
|
||||||
|
.spellcheck {background-image:url(spell-check.png)}
|
||||||
|
.experiment {background-image:url(burn-exclamation.png)}
|
||||||
|
.sansserif {font-family:Tahoma,sans-serif;font-size:12px;}
|
||||||
|
.commit {margin-bottom:20px;font-size:100%;font-weight:normal;}
|
||||||
|
.changes {list-style:none;margin:5px 0;padding:0 0 0 25px;font-size:0.8em;}
|
||||||
|
.date {margin:10px 0;color:blue;border-bottom:2px solid #00f;width:60%;padding:2px 0;font-size:1em;font-weight:bold;}
|
||||||
|
.author {padding-left:10px;margin:0;font-weight:bold;font-size:0.9em;}
|
||||||
|
.drop {cursor:pointer;border:1px solid #999;display:inline;font-size:0.9em;padding:1px 20px 1px 5px;line-height:16px;}
|
||||||
|
.hidden {display:none;}
|
||||||
|
.indrop {margin:2px 0 0 0;clear:both;background:#fff;border:1px solid #ddd;padding:5px 10px;}
|
||||||
|
.indrop p {margin:0;font-size:0.8em;line-height:16px;margin:1px 0;}
|
||||||
|
.indrop img {margin-right:5px;vertical-align:middle;}
|
||||||
|
.closed {background:url(chevron-expand.png) right center no-repeat;}
|
||||||
|
.open {background:url(chevron.png) right center no-repeat;}
|
||||||
|
.lic {font-size:9px;}
|
||||||
75
html/changelog.html
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Paradise Station Changelog</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="changelog.css">
|
||||||
|
<base target="_blank" />
|
||||||
|
<script type='text/javascript'>
|
||||||
|
|
||||||
|
function changeText(tagID, newText, linkTagID){
|
||||||
|
var tag = document.getElementById(tagID);
|
||||||
|
tag.innerHTML = newText;
|
||||||
|
var linkTag = document.getElementById(linkTagID);
|
||||||
|
linkTag.removeAttribute("href");
|
||||||
|
linkTag.removeAttribute("onclick");
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<table align='center' width='650'><tr><td>
|
||||||
|
<table align='center' class="top">
|
||||||
|
<tr>
|
||||||
|
<td valign='top'>
|
||||||
|
<div align='center'><font size='3'><b>Paradise Station</b></font></div>
|
||||||
|
|
||||||
|
<p><div align='center'><font size='3'><a href="http://nanotrasen.se/phpBB3/index.php">Forum</a> | <a href="http://nanotrasen.se/wiki/index.php/Main_Page">Wiki</a> | <a href="https://github.com/ParadiseSS13/Paradise">Source</a></font></div></p>
|
||||||
|
<font size='2'><b>Visit our IRC channel:</b> #crew on neko.sneeza.me</font>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table align='center' class="top">
|
||||||
|
<tr>
|
||||||
|
<td valign='top'>
|
||||||
|
<font size='2'><b>Current Project Maintainers:</b> <a href='https://github.com/ParadiseSS13?tab=members'>-Click Here-</a><br></font>
|
||||||
|
<font size='2'><b>Currently Active GitHub contributor list:</b> <a href='https://github.com/ParadiseSS13/Paradise/graphs/contributors'>-Click Here-</a><br></font>
|
||||||
|
<font size='2'><b>Coders:</b> ZomgPonies, DaveTheHeadcrab, tigercat2000, FalseIncarnate, AuroraBlade, Tastyfish, Crazylemon64, KasparoVy<br></font>
|
||||||
|
<font size='2'><b>Spriters:</b> FullOfSkittles<br></font>
|
||||||
|
<font size='2'><b>Sounds:</b> <br></font>
|
||||||
|
<font size='2'><b>Main Testers:</b> Anyone who has submitted a bug to the issue tracker<br></font>
|
||||||
|
<font size='2'><b>Thanks to:</b> Baystation 12, /tg/station, /vg/station, NTstation, CDK Station devs, FacepunchStation, GoonStation devs, the original SpaceStation developers and Radithor for the title image.<br> Also a thanks to anybody who has contributed who is not listed here :( Ask to be added here on irc.</font>
|
||||||
|
<font size='2' color='red'><b><br>Have a bug to report?</b> Visit our <a href="https://github.com/ParadiseSS13/Paradise/issues?labels=Bug&state=open">Issue Tracker</a>.<br></font>
|
||||||
|
<font size='2'>Please ensure that the bug has not already been reported and be as descriptive as possible about the circumstances under which the bug occurred</b></a></u>.</font>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
TO ADD AN ENTRY, ADD AND MAINTAIN YOUR OWN changelog/USERNAME.yml FILE.
|
||||||
|
|
||||||
|
*** DO NOT FUCK WITH THIS FILE OR YOU WILL CAUSE MERGE CONFLICTS. ***
|
||||||
|
|
||||||
|
-->
|
||||||
|
<div class="commit sansserif">
|
||||||
|
<h2 class="date">03 January 2016</h2>
|
||||||
|
<h3 class="author">TheDZD updated:</h3>
|
||||||
|
<ul class="changes bgimages16">
|
||||||
|
<li class="rscadd">Ports over changelog system from /tg/station.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<b>GoonStation 13 Development Team</b>
|
||||||
|
<div class = "top">
|
||||||
|
<b>Coders:</b> Stuntwaffle, Showtime, Pantaloons, Nannek, Keelin, Exadv1, hobnob, Justicefries, 0staf, sniperchance, AngriestIBM, BrianOBlivion<br>
|
||||||
|
<b>Spriters:</b> Supernorn, Haruhi, Stuntwaffle, Pantaloons, Rho, SynthOrange, I Said No<br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<p class="lic"><a name="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/"><img src="88x31.png" alt="Creative Commons License" /></a><br><i>Except where otherwise noted, Goon Station 13 is licensed under a <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 License</a>.<br>Rights are currently extended to <a href="http://forums.somethingawful.com/">SomethingAwful Goons</a> only.</i></p>
|
||||||
|
<p class="lic">Some icons by <a href="http://p.yusukekamiyamane.com/">Yusuke Kamiyamane</a>. All rights reserved. Licensed under a <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License</a>.</p>
|
||||||
|
</td></tr></table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
html/changelog.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
function dropdowns() {
|
||||||
|
var divs = document.getElementsByTagName('div');
|
||||||
|
var headers = new Array();
|
||||||
|
var links = new Array();
|
||||||
|
for(var i=0;i<divs.length;i++){
|
||||||
|
if(divs[i].className=='drop') {
|
||||||
|
divs[i].className='drop closed';
|
||||||
|
headers.push(divs[i]);
|
||||||
|
}
|
||||||
|
if(divs[i].className=='indrop') {
|
||||||
|
divs[i].className='indrop hidden';
|
||||||
|
links.push(divs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var i=0;i<headers.length;i++){
|
||||||
|
if(typeof(links[i])!== 'undefined' && links[i]!=null) {
|
||||||
|
headers[i].onclick = (function(elem) {
|
||||||
|
return function() {
|
||||||
|
if(elem.className.search('visible')>=0) {
|
||||||
|
elem.className = elem.className.replace('visible','hidden');
|
||||||
|
this.className = this.className.replace('open','closed');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elem.className = elem.className.replace('hidden','visible');
|
||||||
|
this.className = this.className.replace('closed','open');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})(links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function filterchanges(type){
|
||||||
|
var lists = document.getElementsByTagName('ul');
|
||||||
|
for(var i in lists){
|
||||||
|
if(lists[i].className && lists[i].className.search('changes')>=0) {
|
||||||
|
for(var j in lists[i].childNodes){
|
||||||
|
if(lists[i].childNodes[j].nodeType == 1){
|
||||||
|
if(!type){
|
||||||
|
lists[i].childNodes[j].style.display = 'block';
|
||||||
|
}
|
||||||
|
else if(lists[i].childNodes[j].className!=type) {
|
||||||
|
lists[i].childNodes[j].style.display = 'none';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lists[i].childNodes[j].style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
function dropdowns() {
|
||||||
|
var drops = $('div.drop');
|
||||||
|
var indrops = $('div.indrop');
|
||||||
|
if(drops.length!=indrops.length){
|
||||||
|
alert("Some coder fucked up with dropdowns");
|
||||||
|
}
|
||||||
|
drops.each(function(index){
|
||||||
|
$(this).toggleClass('closed');
|
||||||
|
$(indrops[index]).hide();
|
||||||
|
$(this).click(function(){
|
||||||
|
$(this).toggleClass('closed');
|
||||||
|
$(this).toggleClass('open');
|
||||||
|
$(indrops[index]).toggle();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterchanges(type){
|
||||||
|
$('ul.changes li').each(function(){
|
||||||
|
if(!type || $(this).hasClass(type)){
|
||||||
|
$(this).show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$(this).hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
dropdowns();
|
||||||
|
});
|
||||||
5
html/changelogs/.all_changelog.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
|
||||||
|
---
|
||||||
|
2016-01-03:
|
||||||
|
TheDZD:
|
||||||
|
- rscadd: Ports over changelog system from /tg/station.
|
||||||
19
html/changelogs/__CHANGELOG_README.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Changelogs are included with commits as text .yml files created individually by the committer. If you want to create a changelog entry you create a .yml file in the /changelogs directory; nothing else needs to be touched unless you are a maintainer.
|
||||||
|
|
||||||
|
#######################################################
|
||||||
|
|
||||||
|
TO MAKE A CHANGELOG .YML ENTRRY
|
||||||
|
|
||||||
|
1. Make a copy of the file example.yml in html/changelogs and rename it to [YOUR USERNAME]-PR-[YOUR PR NUMBER].yml (the pr and pr number are organizational and can be ignored if you so wish)
|
||||||
|
|
||||||
|
2. Change the author to yourself
|
||||||
|
|
||||||
|
3. Replace the changes text with a description of the changes in your PR, keep the double quotes to avoid errors (your changelog can be written ICly or OOCly, it doesn't matter)
|
||||||
|
|
||||||
|
4. (Optional) set the change prefix (rscadd) to a different one listed above in example.yml (this affects what icon is used for your changelog entry)
|
||||||
|
|
||||||
|
5. When commiting make sure your .yml file is included in the commit (it will usually be unticked as an unversioned file)
|
||||||
|
|
||||||
|
#######################################################
|
||||||
|
|
||||||
|
If you have trouble ask for help in #codertrain on the Paradise Station IRC.
|
||||||
36
html/changelogs/example.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
################################
|
||||||
|
# Example Changelog File
|
||||||
|
#
|
||||||
|
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||||
|
#
|
||||||
|
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||||
|
# When it is, any changes listed below will disappear.
|
||||||
|
#
|
||||||
|
# Valid Prefixes:
|
||||||
|
# bugfix
|
||||||
|
# wip (For works in progress)
|
||||||
|
# tweak
|
||||||
|
# soundadd
|
||||||
|
# sounddel
|
||||||
|
# rscadd (general adding of nice things)
|
||||||
|
# rscdel (general deleting of nice things)
|
||||||
|
# imageadd
|
||||||
|
# imagedel
|
||||||
|
# spellcheck (typo fixes)
|
||||||
|
# experiment
|
||||||
|
#################################
|
||||||
|
|
||||||
|
# Your name. Remove the quotation mark and put in your name when copy+pasting the example changelog.
|
||||||
|
author: "
|
||||||
|
|
||||||
|
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||||
|
delete-after: True
|
||||||
|
|
||||||
|
# Any changes you've made. See valid prefix list above.
|
||||||
|
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||||
|
# SCREW THIS UP AND IT WON'T WORK.
|
||||||
|
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
|
||||||
|
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
|
||||||
|
changes:
|
||||||
|
- rscadd: "Added a changelog editing system that should cause fewer conflicts and more accurate timestamps."
|
||||||
|
- rscdel: "Killed innocent kittens."
|
||||||
BIN
html/chevron-expand.png
Normal file
|
After Width: | Height: | Size: 495 B |
BIN
html/chevron.png
Normal file
|
After Width: | Height: | Size: 498 B |
BIN
html/cross-circle.png
Normal file
|
After Width: | Height: | Size: 651 B |
BIN
html/hard-hat-exclamation.png
Normal file
|
After Width: | Height: | Size: 678 B |
BIN
html/image-minus.png
Normal file
|
After Width: | Height: | Size: 535 B |
BIN
html/image-plus.png
Normal file
|
After Width: | Height: | Size: 580 B |
BIN
html/music-minus.png
Normal file
|
After Width: | Height: | Size: 403 B |
BIN
html/music-plus.png
Normal file
|
After Width: | Height: | Size: 462 B |
BIN
html/spell-check.png
Normal file
|
After Width: | Height: | Size: 509 B |
13
html/templates/footer.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
</div>
|
||||||
|
|
||||||
|
<b>GoonStation 13 Development Team</b>
|
||||||
|
<div class = "top">
|
||||||
|
<b>Coders:</b> Stuntwaffle, Showtime, Pantaloons, Nannek, Keelin, Exadv1, hobnob, Justicefries, 0staf, sniperchance, AngriestIBM, BrianOBlivion<br>
|
||||||
|
<b>Spriters:</b> Supernorn, Haruhi, Stuntwaffle, Pantaloons, Rho, SynthOrange, I Said No<br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<p class="lic"><a name="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/"><img src="88x31.png" alt="Creative Commons License" /></a><br><i>Except where otherwise noted, Goon Station 13 is licensed under a <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 License</a>.<br>Rights are currently extended to <a href="http://forums.somethingawful.com/">SomethingAwful Goons</a> only.</i></p>
|
||||||
|
<p class="lic">Some icons by <a href="http://p.yusukekamiyamane.com/">Yusuke Kamiyamane</a>. All rights reserved. Licensed under a <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License</a>.</p>
|
||||||
|
</td></tr></table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
57
html/templates/header.html
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Paradise Station Changelog</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="changelog.css">
|
||||||
|
<base target="_blank" />
|
||||||
|
<script type='text/javascript'>
|
||||||
|
|
||||||
|
function changeText(tagID, newText, linkTagID){
|
||||||
|
var tag = document.getElementById(tagID);
|
||||||
|
tag.innerHTML = newText;
|
||||||
|
var linkTag = document.getElementById(linkTagID);
|
||||||
|
linkTag.removeAttribute("href");
|
||||||
|
linkTag.removeAttribute("onclick");
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<table align='center' width='650'><tr><td>
|
||||||
|
<table align='center' class="top">
|
||||||
|
<tr>
|
||||||
|
<td valign='top'>
|
||||||
|
<div align='center'><font size='3'><b>Paradise Station</b></font></div>
|
||||||
|
|
||||||
|
<p><div align='center'><font size='3'><a href="http://nanotrasen.se/phpBB3/index.php">Forum</a> | <a href="http://nanotrasen.se/wiki/index.php/Main_Page">Wiki</a> | <a href="https://github.com/ParadiseSS13/Paradise">Source</a></font></div></p>
|
||||||
|
<font size='2'><b>Visit our IRC channel:</b> #crew on neko.sneeza.me</font>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table align='center' class="top">
|
||||||
|
<tr>
|
||||||
|
<td valign='top'>
|
||||||
|
<font size='2'><b>Current Project Maintainers:</b> <a href='https://github.com/ParadiseSS13?tab=members'>-Click Here-</a><br></font>
|
||||||
|
<font size='2'><b>Currently Active GitHub contributor list:</b> <a href='https://github.com/ParadiseSS13/Paradise/graphs/contributors'>-Click Here-</a><br></font>
|
||||||
|
<font size='2'><b>Coders:</b> ZomgPonies, DaveTheHeadcrab, tigercat2000, FalseIncarnate, AuroraBlade, Tastyfish, Crazylemon64, KasparoVy<br></font>
|
||||||
|
<font size='2'><b>Spriters:</b> FullOfSkittles<br></font>
|
||||||
|
<font size='2'><b>Sounds:</b> <br></font>
|
||||||
|
<font size='2'><b>Main Testers:</b> Anyone who has submitted a bug to the issue tracker<br></font>
|
||||||
|
<font size='2'><b>Thanks to:</b> Baystation 12, /tg/station, /vg/station, NTstation, CDK Station devs, FacepunchStation, GoonStation devs, the original SpaceStation developers and Radithor for the title image.<br> Also a thanks to anybody who has contributed who is not listed here :( Ask to be added here on irc.</font>
|
||||||
|
<font size='2' color='red'><b><br>Have a bug to report?</b> Visit our <a href="https://github.com/ParadiseSS13/Paradise/issues?labels=Bug&state=open">Issue Tracker</a>.<br></font>
|
||||||
|
<font size='2'>Please ensure that the bug has not already been reported and be as descriptive as possible about the circumstances under which the bug occurred</b></a></u>.</font>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
TO ADD AN ENTRY, ADD AND MAINTAIN YOUR OWN changelog/USERNAME.yml FILE.
|
||||||
|
|
||||||
|
*** DO NOT FUCK WITH THIS FILE OR YOU WILL CAUSE MERGE CONFLICTS. ***
|
||||||
|
|
||||||
|
-->
|
||||||
|
<div class="commit sansserif">
|
||||||
BIN
html/tick-circle.png
Normal file
|
After Width: | Height: | Size: 660 B |
BIN
html/wrench-screwdriver.png
Normal file
|
After Width: | Height: | Size: 684 B |
14
install-byond.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
if [ -d "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin" ];
|
||||||
|
then
|
||||||
|
echo "Using cached directory."
|
||||||
|
else
|
||||||
|
echo "Setting up BYOND."
|
||||||
|
mkdir -p "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}"
|
||||||
|
cd "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}"
|
||||||
|
curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip
|
||||||
|
unzip byond.zip
|
||||||
|
cd byond
|
||||||
|
make here
|
||||||
|
fi
|
||||||
@@ -15,16 +15,29 @@
|
|||||||
|
|
||||||
/client/verb/changes()
|
/client/verb/changes()
|
||||||
set name = "Changelog"
|
set name = "Changelog"
|
||||||
set desc = "Visit our repository to check out the changes."
|
set desc = "View the changelog."
|
||||||
set hidden = 1
|
set hidden = 1
|
||||||
|
|
||||||
if(config.repositoryurl)
|
getFiles(
|
||||||
if(alert("This will open the changelog in your browser. Are you sure?",,"Yes","No")=="No")
|
'html/88x31.png',
|
||||||
return
|
'html/bug-minus.png',
|
||||||
src << link("[config.repositoryurl]/pulls?q=is%3Apr+is%3Aclosed")
|
'html/cross-circle.png',
|
||||||
else
|
'html/hard-hat-exclamation.png',
|
||||||
src << "<span class='danger'>The Repository URL is not set in the server configuration.</span>"
|
'html/image-minus.png',
|
||||||
return
|
'html/image-plus.png',
|
||||||
|
'html/music-minus.png',
|
||||||
|
'html/music-plus.png',
|
||||||
|
'html/tick-circle.png',
|
||||||
|
'html/wrench-screwdriver.png',
|
||||||
|
'html/spell-check.png',
|
||||||
|
'html/burn-exclamation.png',
|
||||||
|
'html/chevron.png',
|
||||||
|
'html/chevron-expand.png',
|
||||||
|
'html/changelog.css',
|
||||||
|
'html/changelog.js',
|
||||||
|
'html/changelog.html'
|
||||||
|
)
|
||||||
|
src << browse('html/changelog.html', "window=changes;size=675x650")
|
||||||
|
|
||||||
/client/verb/forum()
|
/client/verb/forum()
|
||||||
set name = "forum"
|
set name = "forum"
|
||||||
@@ -79,7 +92,7 @@ Admin:
|
|||||||
|
|
||||||
if(check_rights(R_MOD|R_ADMIN,0))
|
if(check_rights(R_MOD|R_ADMIN,0))
|
||||||
src << adminhotkeys
|
src << adminhotkeys
|
||||||
|
|
||||||
/mob/proc/hotkey_help()
|
/mob/proc/hotkey_help()
|
||||||
var/hotkey_mode = {"<font color='purple'>
|
var/hotkey_mode = {"<font color='purple'>
|
||||||
Hotkey-Mode: (hotkey-mode must be on)
|
Hotkey-Mode: (hotkey-mode must be on)
|
||||||
|
|||||||
345
tools/github_webhook_processor.php
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Github webhook In-game PR Announcer and Changelog Generator for /tg/Station13
|
||||||
|
* Author: MrStonedOne
|
||||||
|
* For documentation on the changelog generator see https://tgstation13.org/phpBB/viewtopic.php?f=5&t=5157
|
||||||
|
* To hide prs from being announced in game, place a [s] in front of the title
|
||||||
|
* All runtime errors are echo'ed to the webhook's logs in github
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**CREDITS:
|
||||||
|
* GitHub webhook handler template.
|
||||||
|
*
|
||||||
|
* @see https://developer.github.com/webhooks/
|
||||||
|
* @author Miloslav Hula (https://github.com/milo)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//CONFIG START (all defaults are random examples, do change them)
|
||||||
|
//Use single quotes for config options that are strings.
|
||||||
|
|
||||||
|
//Github lets you have it sign the message with a secret that you can validate. This prevents people from faking events.
|
||||||
|
//This var should match the secret you configured for this webhook on github.
|
||||||
|
//set to NULL (no quotes) to disable validation.
|
||||||
|
$hookSecret = '08ajh0qj93209qj90jfq932j32r';
|
||||||
|
|
||||||
|
//Api key for pushing changelogs.
|
||||||
|
$apiKey = '209ab8d879c0f987d06a09b9d879c0f987d06a09b9d8787d0a089c';
|
||||||
|
|
||||||
|
//servers to announce PRs to.
|
||||||
|
$servers = array();
|
||||||
|
/*
|
||||||
|
$servers[0] = array();
|
||||||
|
$servers[0]['address'] = 'game.tgstation13.org';
|
||||||
|
$servers[0]['port'] = '1337';
|
||||||
|
$servers[0]['comskey'] = '89aj90cq2fm0amc90832mn9rm90';
|
||||||
|
$servers[1] = array();
|
||||||
|
$servers[1]['address'] = 'game.tgstation13.org';
|
||||||
|
$servers[1]['port'] = '2337';
|
||||||
|
$servers[1]['comskey'] = '89aj90cq2fm0amc90832mn9rm90';
|
||||||
|
*/
|
||||||
|
|
||||||
|
//CONFIG END
|
||||||
|
set_error_handler(function($severity, $message, $file, $line) {
|
||||||
|
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||||
|
});
|
||||||
|
set_exception_handler(function($e) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
echo "Error on line {$e->getLine()}: " . htmlSpecialChars($e->getMessage());
|
||||||
|
die();
|
||||||
|
});
|
||||||
|
$rawPost = NULL;
|
||||||
|
if ($hookSecret !== NULL) {
|
||||||
|
if (!isset($_SERVER['HTTP_X_HUB_SIGNATURE'])) {
|
||||||
|
throw new \Exception("HTTP header 'X-Hub-Signature' is missing.");
|
||||||
|
} elseif (!extension_loaded('hash')) {
|
||||||
|
throw new \Exception("Missing 'hash' extension to check the secret code validity.");
|
||||||
|
}
|
||||||
|
list($algo, $hash) = explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE'], 2) + array('', '');
|
||||||
|
if (!in_array($algo, hash_algos(), TRUE)) {
|
||||||
|
throw new \Exception("Hash algorithm '$algo' is not supported.");
|
||||||
|
}
|
||||||
|
$rawPost = file_get_contents('php://input');
|
||||||
|
if ($hash !== hash_hmac($algo, $rawPost, $hookSecret)) {
|
||||||
|
throw new \Exception('Hook secret does not match.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isset($_SERVER['HTTP_CONTENT_TYPE'])) {
|
||||||
|
throw new \Exception("Missing HTTP 'Content-Type' header.");
|
||||||
|
} elseif (!isset($_SERVER['HTTP_X_GITHUB_EVENT'])) {
|
||||||
|
throw new \Exception("Missing HTTP 'X-Github-Event' header.");
|
||||||
|
}
|
||||||
|
switch ($_SERVER['HTTP_CONTENT_TYPE']) {
|
||||||
|
case 'application/json':
|
||||||
|
$json = $rawPost ?: file_get_contents('php://input');
|
||||||
|
break;
|
||||||
|
case 'application/x-www-form-urlencoded':
|
||||||
|
$json = $_POST['payload'];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \Exception("Unsupported content type: $_SERVER[HTTP_CONTENT_TYPE]");
|
||||||
|
}
|
||||||
|
# Payload structure depends on triggered event
|
||||||
|
# https://developer.github.com/v3/activity/events/types/
|
||||||
|
$payload = json_decode($json, true);
|
||||||
|
|
||||||
|
switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) {
|
||||||
|
case 'ping':
|
||||||
|
echo 'pong';
|
||||||
|
break;
|
||||||
|
case 'pull_request':
|
||||||
|
handle_pr($payload);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
header('HTTP/1.0 404 Not Found');
|
||||||
|
echo "Event:$_SERVER[HTTP_X_GITHUB_EVENT] Payload:\n";
|
||||||
|
print_r($payload); # For debug only. Can be found in GitHub hook log.
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
function handle_pr($payload) {
|
||||||
|
$action = 'opened';
|
||||||
|
switch ($payload["action"]) {
|
||||||
|
case 'opened':
|
||||||
|
case 'reopened':
|
||||||
|
$action = $payload['action'];
|
||||||
|
break;
|
||||||
|
case 'closed':
|
||||||
|
if (!$payload['pull_request']['merged']) {
|
||||||
|
$action = 'closed';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$action = 'merged';
|
||||||
|
checkchangelog($payload, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strtolower(substr($payload['pull_request']['title'], 0, 3)) == '[s]') {
|
||||||
|
echo "PR Announcement Halted; Secret tag detected.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = 'Pull Request '.$action.' by '.htmlSpecialChars($payload['sender']['login']).': <a href="'.$payload['pull_request']['html_url'].'">'.htmlSpecialChars('#'.$payload['pull_request']['number'].' '.$payload['pull_request']['user']['login'].' - '.$payload['pull_request']['title']).'</a>';
|
||||||
|
sendtoallservers('?announce='.urlencode($msg));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkchangelog($payload, $merge = false) {
|
||||||
|
global $apiKey;
|
||||||
|
if (!$merge)
|
||||||
|
return;
|
||||||
|
if (!isset($payload['pull_request']) || !isset($payload['pull_request']['body'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isset($payload['pull_request']['user']) || !isset($payload['pull_request']['user']['login'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$body = $payload['pull_request']['body'];
|
||||||
|
$body = str_replace("\r\n", "\n", $body);
|
||||||
|
$body = explode("\n", $body);
|
||||||
|
$username = $payload['pull_request']['user']['login'];
|
||||||
|
$incltag = false;
|
||||||
|
$changelogbody = array();
|
||||||
|
$currentchangelogblock = array();
|
||||||
|
$foundcltag = false;
|
||||||
|
foreach ($body as $line) {
|
||||||
|
$line = trim($line);
|
||||||
|
if (substr($line,0,4) == ':cl:') {
|
||||||
|
$incltag = true;
|
||||||
|
$foundcltag = true;
|
||||||
|
$pos = strpos($line, " ");
|
||||||
|
if ($pos)
|
||||||
|
$username = substr($line, $pos+1);
|
||||||
|
continue;
|
||||||
|
} else if (substr($line,0,5) == '/:cl:' || substr($line,0,6) == '/ :cl:' || substr($line,0,5) == ':/cl:') {
|
||||||
|
$incltag = false;
|
||||||
|
$changelogbody = array_merge($changelogbody, $currentchangelogblock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!$incltag)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$firstword = explode(' ', $line)[0];
|
||||||
|
$pos = strpos($line, " ");
|
||||||
|
$item = '';
|
||||||
|
if ($pos) {
|
||||||
|
$firstword = trim(substr($line, 0, $pos));
|
||||||
|
$item = trim(substr($line, $pos+1));
|
||||||
|
} else {
|
||||||
|
$firstword = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strlen($firstword)) {
|
||||||
|
$currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//not a prefix line.
|
||||||
|
//so we add it to the last changelog entry as a separate line
|
||||||
|
if (!strlen($firstword) || $firstword[strlen($firstword)-1] != ':') {
|
||||||
|
if (count($currentchangelogblock) <= 0)
|
||||||
|
continue;
|
||||||
|
$currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n".$line;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cltype = strtolower(substr($firstword, 0, -1));
|
||||||
|
switch ($cltype) {
|
||||||
|
case 'fix':
|
||||||
|
case 'fixes':
|
||||||
|
case 'bugfix':
|
||||||
|
$currentchangelogblock[] = array('type' => 'bugfix', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'wip':
|
||||||
|
$currentchangelogblock[] = array('type' => 'wip', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'rsctweak':
|
||||||
|
case 'tweaks':
|
||||||
|
case 'tweak':
|
||||||
|
$currentchangelogblock[] = array('type' => 'tweak', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'soundadd':
|
||||||
|
$currentchangelogblock[] = array('type' => 'soundadd', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'sounddel':
|
||||||
|
$currentchangelogblock[] = array('type' => 'sounddel', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'add':
|
||||||
|
case 'adds':
|
||||||
|
case 'rscadd':
|
||||||
|
$currentchangelogblock[] = array('type' => 'rscadd', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'del':
|
||||||
|
case 'dels':
|
||||||
|
case 'rscdel':
|
||||||
|
$currentchangelogblock[] = array('type' => 'rscdel', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'imageadd':
|
||||||
|
$currentchangelogblock[] = array('type' => 'imageadd', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'imagedel':
|
||||||
|
$currentchangelogblock[] = array('type' => 'imagedel', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'typo':
|
||||||
|
case 'spellcheck':
|
||||||
|
$currentchangelogblock[] = array('type' => 'spellcheck', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'experimental':
|
||||||
|
case 'experiment':
|
||||||
|
$currentchangelogblock[] = array('type' => 'experiment', 'body' => $item);
|
||||||
|
break;
|
||||||
|
case 'tgs':
|
||||||
|
$currentchangelogblock[] = array('type' => 'tgs', 'body' => $item);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//we add it to the last changelog entry as a separate line
|
||||||
|
if (count($currentchangelogblock) > 0)
|
||||||
|
$currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n".$line;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count($changelogbody))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$file = 'author: '.$username."\n";
|
||||||
|
$file .= "delete-after: True\n";
|
||||||
|
$file .= "changes: \n";
|
||||||
|
foreach ($changelogbody as $changelogitem) {
|
||||||
|
$type = $changelogitem['type'];
|
||||||
|
$body = trim(str_replace(array("\\", '"'), array("\\\\", "\\\""), $changelogitem['body']));
|
||||||
|
$file .= ' - '.$type.': "'.$body.'"';
|
||||||
|
$file .= "\n";
|
||||||
|
}
|
||||||
|
$content = array (
|
||||||
|
'message' => 'Automatic changelog generation for PR #'.$payload['pull_request']['number'],
|
||||||
|
'content' => base64_encode($file)
|
||||||
|
);
|
||||||
|
$scontext = array('http' => array(
|
||||||
|
'method' => 'PUT',
|
||||||
|
'header' =>
|
||||||
|
"Content-type: application/json\r\n".
|
||||||
|
'Authorization: token ' . $apiKey,
|
||||||
|
'content' => json_encode($content),
|
||||||
|
'ignore_errors' => true,
|
||||||
|
'user_agent' => 'tgstation13.org-Github-Automation-Tools'
|
||||||
|
));
|
||||||
|
$filename = '/html/changelogs/AutoChangeLog-pr-'.$payload['pull_request']['number'].'.yml';
|
||||||
|
echo file_get_contents($payload['pull_request']['base']['repo']['url'].'/contents'.$filename, false, stream_context_create($scontext));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendtoallservers($str) {
|
||||||
|
global $servers;
|
||||||
|
foreach ($servers as $serverid => $server) {
|
||||||
|
if (isset($server['comskey']))
|
||||||
|
$rtn = export($server['address'], $server['port'], $str.'&key='.$server['comskey']);
|
||||||
|
else
|
||||||
|
$rtn = export($server['address'], $server['port'], $str);
|
||||||
|
|
||||||
|
echo "Server Number $serverid replied: $rtn\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function export($addr, $port, $str) {
|
||||||
|
global $error;
|
||||||
|
// All queries must begin with a question mark (ie "?players")
|
||||||
|
if($str{0} != '?') $str = ('?' . $str);
|
||||||
|
|
||||||
|
/* --- Prepare a packet to send to the server (based on a reverse-engineered packet structure) --- */
|
||||||
|
$query = "\x00\x83" . pack('n', strlen($str) + 6) . "\x00\x00\x00\x00\x00" . $str . "\x00";
|
||||||
|
|
||||||
|
/* --- Create a socket and connect it to the server --- */
|
||||||
|
$server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or exit("ERROR");
|
||||||
|
socket_set_option($server, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 2, 'usec' => 0)); //sets connect and send timeout to 2 seconds
|
||||||
|
if(!socket_connect($server,$addr,$port)) {
|
||||||
|
$error = true;
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Send bytes to the server. Loop until all bytes have been sent --- */
|
||||||
|
$bytestosend = strlen($query);
|
||||||
|
$bytessent = 0;
|
||||||
|
while ($bytessent < $bytestosend) {
|
||||||
|
//echo $bytessent.'<br>';
|
||||||
|
$result = socket_write($server,substr($query,$bytessent),$bytestosend-$bytessent);
|
||||||
|
//echo 'Sent '.$result.' bytes<br>';
|
||||||
|
if ($result===FALSE) die(socket_strerror(socket_last_error()));
|
||||||
|
$bytessent += $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Idle for a while until recieved bytes from game server --- */
|
||||||
|
$result = socket_read($server, 10000, PHP_BINARY_READ);
|
||||||
|
socket_close($server); // we don't need this anymore
|
||||||
|
|
||||||
|
if($result != "") {
|
||||||
|
if($result{0} == "\x00" || $result{1} == "\x83") { // make sure it's the right packet format
|
||||||
|
|
||||||
|
// Actually begin reading the output:
|
||||||
|
$sizebytes = unpack('n', $result{2} . $result{3}); // array size of the type identifier and content
|
||||||
|
$size = $sizebytes[1] - 1; // size of the string/floating-point (minus the size of the identifier byte)
|
||||||
|
|
||||||
|
if($result{4} == "\x2a") { // 4-byte big-endian floating-point
|
||||||
|
$unpackint = unpack('f', $result{5} . $result{6} . $result{7} . $result{8}); // 4 possible bytes: add them up together, unpack them as a floating-point
|
||||||
|
return $unpackint[1];
|
||||||
|
}
|
||||||
|
else if($result{4} == "\x06") { // ASCII string
|
||||||
|
$unpackstr = ""; // result string
|
||||||
|
$index = 5; // string index
|
||||||
|
|
||||||
|
while($size > 0) { // loop through the entire ASCII string
|
||||||
|
$size--;
|
||||||
|
$unpackstr .= $result{$index}; // add the string position to return string
|
||||||
|
$index++;
|
||||||
|
}
|
||||||
|
return $unpackstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if we get to this point, something went wrong;
|
||||||
|
$error = true;
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
?>
|
||||||
4
tools/makeChangelog.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
rem Cheridan asked for this. - N3X
|
||||||
|
call python ss13_genchangelog.py ../html/changelog.html ../html/changelogs
|
||||||
|
pause
|
||||||
210
tools/ss13_genchangelog.py
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
'''
|
||||||
|
Usage:
|
||||||
|
$ python ss13_genchangelog.py [--dry-run] html/changelog.html html/changelogs/
|
||||||
|
|
||||||
|
ss13_genchangelog.py - Generate changelog from YAML.
|
||||||
|
|
||||||
|
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import yaml, os, glob, sys, re, time, argparse
|
||||||
|
from datetime import datetime, date
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
today = date.today()
|
||||||
|
|
||||||
|
dateformat = "%d %B %Y"
|
||||||
|
|
||||||
|
opt = argparse.ArgumentParser()
|
||||||
|
opt.add_argument('-d', '--dry-run', dest='dryRun', default=False, action='store_true', help='Only parse changelogs and, if needed, the targetFile. (A .dry_changelog.yml will be output for debugging purposes.)')
|
||||||
|
opt.add_argument('targetFile', help='The HTML changelog we wish to update.')
|
||||||
|
opt.add_argument('ymlDir', help='The directory of YAML changelogs we will use.')
|
||||||
|
|
||||||
|
args = opt.parse_args()
|
||||||
|
|
||||||
|
all_changelog_entries = {}
|
||||||
|
|
||||||
|
validPrefixes = [
|
||||||
|
'bugfix',
|
||||||
|
'wip',
|
||||||
|
'tweak',
|
||||||
|
'soundadd',
|
||||||
|
'sounddel',
|
||||||
|
'rscdel',
|
||||||
|
'rscadd',
|
||||||
|
'imageadd',
|
||||||
|
'imagedel',
|
||||||
|
'spellcheck',
|
||||||
|
'experiment',
|
||||||
|
'tgs'
|
||||||
|
]
|
||||||
|
|
||||||
|
def dictToTuples(inp):
|
||||||
|
return [(k, v) for k, v in inp.items()]
|
||||||
|
|
||||||
|
changelog_cache = os.path.join(args.ymlDir, '.all_changelog.yml')
|
||||||
|
|
||||||
|
failed_cache_read = True
|
||||||
|
if os.path.isfile(changelog_cache):
|
||||||
|
try:
|
||||||
|
with open(changelog_cache) as f:
|
||||||
|
(_, all_changelog_entries) = yaml.load_all(f)
|
||||||
|
failed_cache_read = False
|
||||||
|
|
||||||
|
# Convert old timestamps to newer format.
|
||||||
|
new_entries = {}
|
||||||
|
for _date in all_changelog_entries.keys():
|
||||||
|
ty = type(_date).__name__
|
||||||
|
# print(ty)
|
||||||
|
if ty in ['str', 'unicode']:
|
||||||
|
temp_data = all_changelog_entries[_date]
|
||||||
|
_date = datetime.strptime(_date, dateformat).date()
|
||||||
|
new_entries[_date] = temp_data
|
||||||
|
else:
|
||||||
|
new_entries[_date] = all_changelog_entries[_date]
|
||||||
|
all_changelog_entries = new_entries
|
||||||
|
except Exception as e:
|
||||||
|
print("Failed to read cache:")
|
||||||
|
print(e, file=sys.stderr)
|
||||||
|
|
||||||
|
if args.dryRun:
|
||||||
|
changelog_cache = os.path.join(args.ymlDir, '.dry_changelog.yml')
|
||||||
|
|
||||||
|
if failed_cache_read and os.path.isfile(args.targetFile):
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from bs4.element import NavigableString
|
||||||
|
print(' Generating cache...')
|
||||||
|
with open(args.targetFile, 'r') as f:
|
||||||
|
soup = BeautifulSoup(f)
|
||||||
|
for e in soup.find_all('div', {'class':'commit'}):
|
||||||
|
entry = {}
|
||||||
|
date = datetime.strptime(e.h2.string.strip(), dateformat).date() # key
|
||||||
|
for authorT in e.find_all('h3', {'class':'author'}):
|
||||||
|
author = authorT.string
|
||||||
|
# Strip suffix
|
||||||
|
if author.endswith('updated:'):
|
||||||
|
author = author[:-8]
|
||||||
|
author = author.strip()
|
||||||
|
|
||||||
|
# Find <ul>
|
||||||
|
ulT = authorT.next_sibling
|
||||||
|
while(ulT.name != 'ul'):
|
||||||
|
ulT = ulT.next_sibling
|
||||||
|
changes = []
|
||||||
|
|
||||||
|
for changeT in ulT.children:
|
||||||
|
if changeT.name != 'li': continue
|
||||||
|
val = changeT.decode_contents(formatter="html")
|
||||||
|
newdat = {changeT['class'][0] + '': val + ''}
|
||||||
|
if newdat not in changes:
|
||||||
|
changes += [newdat]
|
||||||
|
|
||||||
|
if len(changes) > 0:
|
||||||
|
entry[author] = changes
|
||||||
|
if date in all_changelog_entries:
|
||||||
|
all_changelog_entries[date].update(entry)
|
||||||
|
else:
|
||||||
|
all_changelog_entries[date] = entry
|
||||||
|
|
||||||
|
del_after = []
|
||||||
|
print('Reading changelogs...')
|
||||||
|
for fileName in glob.glob(os.path.join(args.ymlDir, "*.yml")):
|
||||||
|
name, ext = os.path.splitext(os.path.basename(fileName))
|
||||||
|
if name.startswith('.'): continue
|
||||||
|
if name == 'example': continue
|
||||||
|
fileName = os.path.abspath(fileName)
|
||||||
|
print(' Reading {}...'.format(fileName))
|
||||||
|
cl = {}
|
||||||
|
with open(fileName, 'r') as f:
|
||||||
|
cl = yaml.load(f)
|
||||||
|
f.close()
|
||||||
|
if today not in all_changelog_entries:
|
||||||
|
all_changelog_entries[today] = {}
|
||||||
|
author_entries = all_changelog_entries[today].get(cl['author'], [])
|
||||||
|
if len(cl['changes']):
|
||||||
|
new = 0
|
||||||
|
for change in cl['changes']:
|
||||||
|
if change not in author_entries:
|
||||||
|
(change_type, _) = dictToTuples(change)[0]
|
||||||
|
if change_type not in validPrefixes:
|
||||||
|
print(' {0}: Invalid prefix {1}'.format(fileName, change_type), file=sys.stderr)
|
||||||
|
author_entries += [change]
|
||||||
|
new += 1
|
||||||
|
all_changelog_entries[today][cl['author']] = author_entries
|
||||||
|
if new > 0:
|
||||||
|
print(' Added {0} new changelog entries.'.format(new))
|
||||||
|
|
||||||
|
if cl.get('delete-after', False):
|
||||||
|
if os.path.isfile(fileName):
|
||||||
|
if args.dryRun:
|
||||||
|
print(' Would delete {0} (delete-after set)...'.format(fileName))
|
||||||
|
else:
|
||||||
|
del_after += [fileName]
|
||||||
|
|
||||||
|
if args.dryRun: continue
|
||||||
|
|
||||||
|
cl['changes'] = []
|
||||||
|
with open(fileName, 'w') as f:
|
||||||
|
yaml.dump(cl, f, default_flow_style=False)
|
||||||
|
|
||||||
|
targetDir = os.path.dirname(args.targetFile)
|
||||||
|
|
||||||
|
with open(args.targetFile.replace('.htm', '.dry.htm') if args.dryRun else args.targetFile, 'w') as changelog:
|
||||||
|
with open(os.path.join(targetDir, 'templates', 'header.html'), 'r') as h:
|
||||||
|
for line in h:
|
||||||
|
changelog.write(line)
|
||||||
|
|
||||||
|
for _date in reversed(sorted(all_changelog_entries.keys())):
|
||||||
|
entry_htm = '\n'
|
||||||
|
entry_htm += '\t\t\t<h2 class="date">{date}</h2>\n'.format(date=_date.strftime(dateformat))
|
||||||
|
write_entry = False
|
||||||
|
for author in sorted(all_changelog_entries[_date].keys()):
|
||||||
|
if len(all_changelog_entries[_date]) == 0: continue
|
||||||
|
author_htm = '\t\t\t<h3 class="author">{author} updated:</h3>\n'.format(author=author)
|
||||||
|
author_htm += '\t\t\t<ul class="changes bgimages16">\n'
|
||||||
|
changes_added = []
|
||||||
|
for (css_class, change) in (dictToTuples(e)[0] for e in all_changelog_entries[_date][author]):
|
||||||
|
if change in changes_added: continue
|
||||||
|
write_entry = True
|
||||||
|
changes_added += [change]
|
||||||
|
author_htm += '\t\t\t\t<li class="{css_class}">{change}</li>\n'.format(css_class=css_class, change=change.strip())
|
||||||
|
author_htm += '\t\t\t</ul>\n'
|
||||||
|
if len(changes_added) > 0:
|
||||||
|
entry_htm += author_htm
|
||||||
|
if write_entry:
|
||||||
|
changelog.write(entry_htm)
|
||||||
|
|
||||||
|
with open(os.path.join(targetDir, 'templates', 'footer.html'), 'r') as h:
|
||||||
|
for line in h:
|
||||||
|
changelog.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
with open(changelog_cache, 'w') as f:
|
||||||
|
cache_head = 'DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.'
|
||||||
|
yaml.dump_all([cache_head, all_changelog_entries], f, default_flow_style=False)
|
||||||
|
|
||||||
|
if len(del_after):
|
||||||
|
print('Cleaning up...')
|
||||||
|
for fileName in del_after:
|
||||||
|
if os.path.isfile(fileName):
|
||||||
|
print(' Deleting {0} (delete-after set)...'.format(fileName))
|
||||||
|
os.remove(fileName)
|
||||||