mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
feat: Better changelogs
This commit is contained in:
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -11,6 +11,3 @@
|
||||
# dmi icon merger hook
|
||||
# needs additional setup, see tools/dmitool/merging.txt
|
||||
*.dmi merge=merge-dmi
|
||||
|
||||
# force changelog merging to use union
|
||||
html/changelog.html merge=union
|
||||
|
||||
1
.github/workflows/autochangelog.yml
vendored
1
.github/workflows/autochangelog.yml
vendored
@@ -34,7 +34,6 @@ jobs:
|
||||
"${{ github.event.pull_request.user.login }}" \
|
||||
"${{ github.event.pull_request.body }}"
|
||||
python tools/GenerateChangelog/ss13_genchangelog.py \
|
||||
html/changelog.html \
|
||||
html/changelogs
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
debug_log = start_log("[log_path]-debug.log")
|
||||
//VOREStation Edit End
|
||||
|
||||
changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently
|
||||
// CHOMPedit Start - Better Changelogs
|
||||
var/latest_changelog = file("/html/changelogs/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml")
|
||||
changelog_hash = fexists(latest_changelog) ? md5(latest_changelog) : 0 //for telling if the changelog has changed recently
|
||||
// CHOMPedit End
|
||||
|
||||
if(byond_version < RECOMMENDED_VERSION)
|
||||
to_world_log("Your server's byond version does not meet the recommended requirements for this server. Please update BYOND")
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
"no_image32.png" = 'html/images/no_image32.png',
|
||||
)
|
||||
|
||||
/* CHOMPedit Start - Better Changelogs
|
||||
/datum/asset/simple/changelog
|
||||
assets = list(
|
||||
"88x31.png" = 'html/88x31.png',
|
||||
@@ -145,6 +146,7 @@
|
||||
"changelog.js" = 'html/changelog.js',
|
||||
"changelog.html" = 'html/changelog.html'
|
||||
)
|
||||
*/ // CHOMPedit end
|
||||
|
||||
// /datum/asset/group/goonchat
|
||||
// children = list(
|
||||
|
||||
@@ -433,11 +433,20 @@
|
||||
/client/verb/changes()
|
||||
set name = "Changelog"
|
||||
set category = "OOC"
|
||||
src << browse('html/changelog.html', "window=changes;size=675x650")
|
||||
// CHOMPedit Start - Better Changelog
|
||||
//src << browse('html/changelog.html', "window=changes;size=675x650")
|
||||
//return
|
||||
|
||||
if(!GLOB.changelog_tgui)
|
||||
GLOB.changelog_tgui = new /datum/changelog()
|
||||
GLOB.changelog_tgui.tgui_interact(usr)
|
||||
|
||||
/*
|
||||
if(prefs.lastchangelog != changelog_hash)
|
||||
prefs.lastchangelog = changelog_hash
|
||||
SScharacter_setup.queue_preferences_save(prefs)
|
||||
winset(src, "rpane.changelog", "background-color=none;font-style=;")
|
||||
*/ // CHOMPedit End
|
||||
|
||||
/mob/verb/observe()
|
||||
set name = "Observe"
|
||||
|
||||
3
html/changelogs/archive/__example__.yml
Normal file
3
html/changelogs/archive/__example__.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
1970-01-01:
|
||||
ExampleUser:
|
||||
- tweak: Tweaked something in my example PR!
|
||||
@@ -1,37 +1,60 @@
|
||||
################################
|
||||
# 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
|
||||
# maptweak
|
||||
# spellcheck (typo fixes)
|
||||
# experiment
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: N3X15
|
||||
|
||||
# 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, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
|
||||
# Please surround your changes in double quotes ("), as certain characters otherwise 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."
|
||||
################################
|
||||
# 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
|
||||
# - (fixes bugs)
|
||||
# wip
|
||||
# - (work in progress)
|
||||
# qol
|
||||
# - (quality of life)
|
||||
# soundadd
|
||||
# - (adds a sound)
|
||||
# sounddel
|
||||
# - (removes a sound)
|
||||
# rscadd
|
||||
# - (adds a feature)
|
||||
# rscdel
|
||||
# - (removes a feature)
|
||||
# imageadd
|
||||
# - (adds an image or sprite)
|
||||
# imagedel
|
||||
# - (removes an image or sprite)
|
||||
# maptweak
|
||||
# spellcheck
|
||||
# - (fixes spelling or grammar)
|
||||
# experiment
|
||||
# - (experimental change)
|
||||
# balance
|
||||
# - (balance changes)
|
||||
# code_imp
|
||||
# - (misc internal code change)
|
||||
# refactor
|
||||
# - (refactors code)
|
||||
# config
|
||||
# - (makes a change to the config files)
|
||||
# admin
|
||||
# - (makes changes to administrator tools)
|
||||
# server
|
||||
# - (miscellaneous changes to server)
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
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, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
|
||||
# Please surround your changes in double quotes ("), as certain characters otherwise 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."
|
||||
|
||||
1
modular_chomp/code/_global_vars/tgui.dm
Normal file
1
modular_chomp/code/_global_vars/tgui.dm
Normal file
@@ -0,0 +1 @@
|
||||
GLOBAL_DATUM(changelog_tgui, /datum/changelog)
|
||||
32
modular_chomp/code/datums/changelog/changelog.dm
Normal file
32
modular_chomp/code/datums/changelog/changelog.dm
Normal file
@@ -0,0 +1,32 @@
|
||||
/datum/changelog
|
||||
var/static/list/changelog_items = list()
|
||||
|
||||
/datum/changelog/tgui_state()
|
||||
return GLOB.tgui_always_state
|
||||
|
||||
/datum/changelog/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!ui)
|
||||
ui = new(user, src, "Changelog")
|
||||
ui.open()
|
||||
|
||||
/datum/changelog/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(action == "get_month")
|
||||
var/datum/asset/changelog_item/changelog_item = changelog_items[params["date"]]
|
||||
if (!changelog_item)
|
||||
changelog_item = new /datum/asset/changelog_item(params["date"])
|
||||
changelog_items[params["date"]] = changelog_item
|
||||
return ui.send_asset(changelog_item)
|
||||
|
||||
/datum/changelog/tgui_static_data()
|
||||
var/list/data = list( "dates" = list() )
|
||||
var/regex/ymlRegex = regex(@"\.yml", "g")
|
||||
|
||||
for(var/archive_file in sortList(flist("html/changelogs/archive/")))
|
||||
var/archive_date = ymlRegex.Replace(archive_file, "")
|
||||
data["dates"] = list(archive_date) + data["dates"]
|
||||
|
||||
return data
|
||||
17
modular_chomp/code/modules/asset_cache/asset_list.dm
Normal file
17
modular_chomp/code/modules/asset_cache/asset_list.dm
Normal file
@@ -0,0 +1,17 @@
|
||||
/datum/asset/changelog_item
|
||||
_abstract = /datum/asset/changelog_item
|
||||
var/item_filename
|
||||
|
||||
/datum/asset/changelog_item/New(date)
|
||||
item_filename = sanitize_filename("[date].yml")
|
||||
register_asset(item_filename, file("html/changelogs/archive/" + item_filename))
|
||||
|
||||
/datum/asset/changelog_item/send(client)
|
||||
if (!item_filename)
|
||||
return
|
||||
. = send_asset(client, item_filename)
|
||||
|
||||
/datum/asset/changelog_item/get_url_mappings()
|
||||
if (!item_filename)
|
||||
return
|
||||
. = list("[item_filename]" = get_asset_url(item_filename))
|
||||
315
tgui/packages/tgui_ch/interfaces/Changelog.js
Normal file
315
tgui/packages/tgui_ch/interfaces/Changelog.js
Normal file
@@ -0,0 +1,315 @@
|
||||
import { classes } from 'common/react';
|
||||
import { useBackend } from '../backend';
|
||||
import { Component, Fragment } from 'inferno';
|
||||
import { Box, Button, Dropdown, Icon, Section, Stack, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { resolveAsset } from '../assets';
|
||||
import dateformat from 'dateformat';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
const icons = {
|
||||
bugfix: { icon: 'bug', color: 'green' },
|
||||
wip: { icon: 'hammer', color: 'orange' },
|
||||
qol: { icon: 'hand-holding-heart', color: 'green' },
|
||||
soundadd: { icon: 'tg-sound-plus', color: 'green' },
|
||||
sounddel: { icon: 'tg-sound-minus', color: 'red' },
|
||||
add: { icon: 'check-circle', color: 'green' },
|
||||
expansion: { icon: 'check-circle', color: 'green' },
|
||||
rscadd: { icon: 'check-circle', color: 'green' },
|
||||
rscdel: { icon: 'times-circle', color: 'red' },
|
||||
imageadd: { icon: 'tg-image-plus', color: 'green' },
|
||||
imagedel: { icon: 'tg-image-minus', color: 'red' },
|
||||
spellcheck: { icon: 'spell-check', color: 'green' },
|
||||
experiment: { icon: 'radiation', color: 'yellow' },
|
||||
balance: { icon: 'balance-scale-right', color: 'yellow' },
|
||||
code_imp: { icon: 'code', color: 'green' },
|
||||
refactor: { icon: 'tools', color: 'green' },
|
||||
config: { icon: 'cogs', color: 'purple' },
|
||||
admin: { icon: 'user-shield', color: 'purple' },
|
||||
server: { icon: 'server', color: 'purple' },
|
||||
tgs: { icon: 'toolbox', color: 'purple' },
|
||||
tweak: { icon: 'wrench', color: 'green' },
|
||||
unknown: { icon: 'info-circle', color: 'label' },
|
||||
};
|
||||
|
||||
export class Changelog extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
data: 'Loading changelog data...',
|
||||
selectedDate: '',
|
||||
selectedIndex: 0,
|
||||
};
|
||||
this.dateChoices = [];
|
||||
}
|
||||
|
||||
setData(data) {
|
||||
this.setState({ data });
|
||||
}
|
||||
|
||||
setSelectedDate(selectedDate) {
|
||||
this.setState({ selectedDate });
|
||||
}
|
||||
|
||||
setSelectedIndex(selectedIndex) {
|
||||
this.setState({ selectedIndex });
|
||||
}
|
||||
|
||||
getData = (date, attemptNumber = 1) => {
|
||||
const { act } = useBackend(this.context);
|
||||
const self = this;
|
||||
const maxAttempts = 6;
|
||||
|
||||
if (attemptNumber > maxAttempts) {
|
||||
return this.setData(
|
||||
'Failed to load data after ' + maxAttempts + ' attempts'
|
||||
);
|
||||
}
|
||||
|
||||
act('get_month', { date });
|
||||
|
||||
fetch(resolveAsset(date + '.yml')).then(async (changelogData) => {
|
||||
const result = await changelogData.text();
|
||||
const errorRegex = /^Cannot find/;
|
||||
|
||||
if (errorRegex.test(result)) {
|
||||
const timeout = 50 + attemptNumber * 50;
|
||||
|
||||
self.setData('Loading changelog data' + '.'.repeat(attemptNumber + 3));
|
||||
setTimeout(() => {
|
||||
self.getData(date, attemptNumber + 1);
|
||||
}, timeout);
|
||||
} else {
|
||||
self.setData(yaml.load(result, { schema: yaml.CORE_SCHEMA }));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
data: { dates = [] },
|
||||
} = useBackend(this.context);
|
||||
|
||||
if (dates) {
|
||||
dates.forEach((date) =>
|
||||
this.dateChoices.push(dateformat(date, 'mmmm yyyy', true))
|
||||
);
|
||||
this.setSelectedDate(this.dateChoices[0]);
|
||||
this.getData(dates[0]);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { data, selectedDate, selectedIndex } = this.state;
|
||||
const {
|
||||
data: { dates },
|
||||
} = useBackend(this.context);
|
||||
const { dateChoices } = this;
|
||||
|
||||
const dateDropdown = dateChoices.length > 0 && (
|
||||
<Stack mb={1}>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
className="Changelog__Button"
|
||||
disabled={selectedIndex === 0}
|
||||
icon={'chevron-left'}
|
||||
onClick={() => {
|
||||
const index = selectedIndex - 1;
|
||||
|
||||
this.setData('Loading changelog data...');
|
||||
this.setSelectedIndex(index);
|
||||
this.setSelectedDate(dateChoices[index]);
|
||||
window.scrollTo(
|
||||
0,
|
||||
document.body.scrollHeight ||
|
||||
document.documentElement.scrollHeight
|
||||
);
|
||||
return this.getData(dates[index]);
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
displayText={selectedDate}
|
||||
options={dateChoices}
|
||||
onSelected={(value) => {
|
||||
const index = dateChoices.indexOf(value);
|
||||
|
||||
this.setData('Loading changelog data...');
|
||||
this.setSelectedIndex(index);
|
||||
this.setSelectedDate(value);
|
||||
window.scrollTo(
|
||||
0,
|
||||
document.body.scrollHeight ||
|
||||
document.documentElement.scrollHeight
|
||||
);
|
||||
return this.getData(dates[index]);
|
||||
}}
|
||||
selected={selectedDate}
|
||||
width={'150px'}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
className="Changelog__Button"
|
||||
disabled={selectedIndex === dateChoices.length - 1}
|
||||
icon={'chevron-right'}
|
||||
onClick={() => {
|
||||
const index = selectedIndex + 1;
|
||||
|
||||
this.setData('Loading changelog data...');
|
||||
this.setSelectedIndex(index);
|
||||
this.setSelectedDate(dateChoices[index]);
|
||||
window.scrollTo(
|
||||
0,
|
||||
document.body.scrollHeight ||
|
||||
document.documentElement.scrollHeight
|
||||
);
|
||||
return this.getData(dates[index]);
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const header = (
|
||||
<Section>
|
||||
<h1>CHOMPStation Changelist</h1>
|
||||
<p>
|
||||
{'The GitHub repository can be found '}
|
||||
<a href="https://github.com/CHOMPStation2/CHOMPStation2">here</a>
|
||||
{', recent GitHub contributors can be found '}
|
||||
<a href="https://github.com/CHOMPStation2/CHOMPStation2/pulse/monthly">
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
{'Visit our wiki '}
|
||||
<a href="https://wiki.vore-station.net/Main_Page">here</a>
|
||||
{', check out our discord server '}
|
||||
<a href="https://discord.gg/BaZnwYpAzc">here</a>.
|
||||
</p>
|
||||
{dateDropdown}
|
||||
</Section>
|
||||
);
|
||||
|
||||
const footer = (
|
||||
<Section>
|
||||
{dateDropdown}
|
||||
<h3>CHOMPStation License</h3>
|
||||
<p>
|
||||
{'All code after '}
|
||||
<a
|
||||
href={
|
||||
'https://github.com/CHOMPStation2/CHOMPStation2/commit/' +
|
||||
'333c566b88108de218d882840e61928a9b759d8f'
|
||||
}>
|
||||
commit 333c566b88108de218d882840e61928a9b759d8f on 2014/31/12 at
|
||||
4:38 PM PST
|
||||
</a>
|
||||
{' is licensed under '}
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.html">GNU AGPL v3</a>
|
||||
{'. All code before that commit is licensed under '}
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0.html">GNU GPL v3</a>
|
||||
{', including tools unless their readme specifies otherwise. See '}
|
||||
<a href="https://github.com/CHOMPStation2/CHOMPStation2/blob/master/LICENSE">
|
||||
LICENSE
|
||||
</a>
|
||||
{' and '}
|
||||
<a href="https://github.com/CHOMPStation2/CHOMPStation2/blob/master/LICENSE-GPL3.txt">
|
||||
GPLv3.txt
|
||||
</a>
|
||||
{' for more details.'}
|
||||
</p>
|
||||
<p>
|
||||
The TGS DMAPI API is licensed as a subproject under the MIT license.
|
||||
{' See the footer of '}
|
||||
<a
|
||||
href={
|
||||
'https://github.com/CHOMPStation2/CHOMPStation2/blob/master' +
|
||||
'/code/__DEFINES/tgs.dm'
|
||||
}>
|
||||
code/__DEFINES/tgs.dm
|
||||
</a>
|
||||
{' and '}
|
||||
<a
|
||||
href={
|
||||
'https://github.com/CHOMPStation2/CHOMPStation2/blob/master' +
|
||||
'/code/modules/tgs/LICENSE'
|
||||
}>
|
||||
code/modules/tgs/LICENSE
|
||||
</a>
|
||||
{' for the MIT license.'}
|
||||
</p>
|
||||
<p>
|
||||
{'All assets including icons and sound are under a '}
|
||||
<a href="https://creativecommons.org/licenses/by-sa/3.0/">
|
||||
Creative Commons 3.0 BY-SA license
|
||||
</a>
|
||||
{' unless otherwise indicated.'}
|
||||
</p>
|
||||
</Section>
|
||||
);
|
||||
|
||||
const changes =
|
||||
typeof data === 'object' &&
|
||||
Object.keys(data).length > 0 &&
|
||||
Object.entries(data)
|
||||
.reverse()
|
||||
.map(([date, authors]) => (
|
||||
<Section key={date} title={dateformat(date, 'd mmmm yyyy', true)}>
|
||||
<Box ml={3}>
|
||||
{Object.entries(authors).map(([name, changes]) => (
|
||||
<Fragment key={name}>
|
||||
<h4>{name} changed:</h4>
|
||||
<Box ml={3}>
|
||||
<Table>
|
||||
{changes.map((change) => {
|
||||
const changeType = Object.keys(change)[0];
|
||||
return (
|
||||
<Table.Row key={changeType + change[changeType]}>
|
||||
<Table.Cell
|
||||
className={classes([
|
||||
'Changelog__Cell',
|
||||
'Changelog__Cell--Icon',
|
||||
])}>
|
||||
<Icon
|
||||
color={
|
||||
icons[changeType]
|
||||
? icons[changeType].color
|
||||
: icons['unknown'].color
|
||||
}
|
||||
name={
|
||||
icons[changeType]
|
||||
? icons[changeType].icon
|
||||
: icons['unknown'].icon
|
||||
}
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell className="Changelog__Cell">
|
||||
{change[changeType]}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
</Box>
|
||||
</Fragment>
|
||||
))}
|
||||
</Box>
|
||||
</Section>
|
||||
));
|
||||
|
||||
return (
|
||||
<Window title="Changelog" width={675} height={650}>
|
||||
<Window.Content scrollable>
|
||||
{header}
|
||||
{changes}
|
||||
{typeof data === 'string' && <p>{data}</p>}
|
||||
{footer}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"@popperjs/core": "^2.11.5",
|
||||
"@types/marked": "^4.0.8",
|
||||
"common": "workspace:*",
|
||||
"dateformat": "^5.0.3",
|
||||
"dateformat": "^4.5.1",
|
||||
"dompurify": "^2.3.8",
|
||||
"highlight.js": "^11.5.1",
|
||||
"inferno": "^7.4.11",
|
||||
@@ -15,5 +15,9 @@
|
||||
"marked": "^4.0.16",
|
||||
"tgui-dev-server": "workspace:*",
|
||||
"tgui-polyfill": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dateformat": "^5.0.0",
|
||||
"@types/js-yaml": "^4.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2112,6 +2112,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dateformat@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "@types/dateformat@npm:5.0.0"
|
||||
checksum: fee3fff637675fd55b59fff6a0507a120ae212a0c7ba823c00a45473da617a7d466e6d7d40d2b4b88af9df3f4be3ed80a51e222ea346c7738de688aa2c6747f1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/eslint-scope@npm:^3.7.3":
|
||||
version: 3.7.4
|
||||
resolution: "@types/eslint-scope@npm:3.7.4"
|
||||
@@ -2183,6 +2190,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/js-yaml@npm:^4.0.5":
|
||||
version: 4.0.5
|
||||
resolution: "@types/js-yaml@npm:4.0.5"
|
||||
checksum: 7dcac8c50fec31643cc9d6444b5503239a861414cdfaa7ae9a38bc22597c4d850c4b8cec3d82d73b3fbca408348ce223b0408d598b32e094470dfffc6d486b4d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jsdom@npm:^16.2.14, @types/jsdom@npm:^16.2.4":
|
||||
version: 16.2.15
|
||||
resolution: "@types/jsdom@npm:16.2.15"
|
||||
@@ -3824,6 +3838,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dateformat@npm:^4.5.1":
|
||||
version: 4.6.3
|
||||
resolution: "dateformat@npm:4.6.3"
|
||||
checksum: c3aa0617c0a5b30595122bc8d1bee6276a9221e4d392087b41cbbdf175d9662ae0e50d0d6dcdf45caeac5153c4b5b0844265f8cd2b2245451e3da19e39e3b65d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dateformat@npm:^5.0.3":
|
||||
version: 5.0.3
|
||||
resolution: "dateformat@npm:5.0.3"
|
||||
@@ -9409,9 +9430,11 @@ __metadata:
|
||||
resolution: "tgui_ch@workspace:packages/tgui_ch"
|
||||
dependencies:
|
||||
"@popperjs/core": ^2.11.5
|
||||
"@types/dateformat": ^5.0.0
|
||||
"@types/js-yaml": ^4.0.5
|
||||
"@types/marked": ^4.0.8
|
||||
common: "workspace:*"
|
||||
dateformat: ^5.0.3
|
||||
dateformat: ^4.5.1
|
||||
dompurify: ^2.3.8
|
||||
highlight.js: ^11.5.1
|
||||
inferno: ^7.4.11
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@echo off
|
||||
rem Cheridan asked for this. - N3X
|
||||
call python ss13_genchangelog.py ../../html/changelog.html ../../html/changelogs
|
||||
pause
|
||||
@echo off
|
||||
rem Cheridan asked for this. - N3X
|
||||
call python ss13_genchangelog.py ../../html/changelogs
|
||||
pause
|
||||
|
||||
@@ -29,9 +29,7 @@ validPrefixes = {
|
||||
"fixes": 'bugfix',
|
||||
"bugfix": 'bugfix',
|
||||
"wip": 'wip',
|
||||
"tweak": 'tweak',
|
||||
"tweaks": 'tweak',
|
||||
"rsctweak": 'tweak',
|
||||
"qol": 'qol',
|
||||
"soundadd": 'soundadd',
|
||||
"sounddel": 'sounddel',
|
||||
"add": 'rscadd',
|
||||
@@ -51,7 +49,13 @@ validPrefixes = {
|
||||
"spellcheck": 'spellcheck',
|
||||
"experimental": 'experiment',
|
||||
"experiments": 'experiment',
|
||||
"experiment": 'experiment'
|
||||
"experiment": 'experiment',
|
||||
"balance": 'balance',
|
||||
"code_imp": 'code_imp',
|
||||
"refactor": 'refactor',
|
||||
"config": 'config',
|
||||
"admin": 'admin',
|
||||
"server": 'server',
|
||||
}
|
||||
|
||||
incltag = False
|
||||
|
||||
@@ -1,210 +1,149 @@
|
||||
'''
|
||||
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',
|
||||
'maptweak',
|
||||
'spellcheck',
|
||||
'experiment'
|
||||
]
|
||||
|
||||
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 = []
|
||||
errors = False
|
||||
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:
|
||||
errors = True
|
||||
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)
|
||||
|
||||
if errors:
|
||||
sys.exit(1)
|
||||
'''
|
||||
Usage:
|
||||
$ python ss13_genchangelog.py 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()
|
||||
|
||||
fileDateFormat = "%Y-%m"
|
||||
|
||||
opt = argparse.ArgumentParser()
|
||||
opt.add_argument('ymlDir', help='The directory of YAML changelogs we will use.')
|
||||
|
||||
args = opt.parse_args()
|
||||
archiveDir = os.path.join(args.ymlDir, 'archive')
|
||||
|
||||
all_changelog_entries = {}
|
||||
|
||||
# Do not change the order, add to the bottom of the array if necessary
|
||||
validPrefixes = [
|
||||
'bugfix',
|
||||
'wip',
|
||||
'qol',
|
||||
'soundadd',
|
||||
'sounddel',
|
||||
'rscadd',
|
||||
'rscdel',
|
||||
'imageadd',
|
||||
'imagedel',
|
||||
'maptweak',
|
||||
'spellcheck',
|
||||
'experiment',
|
||||
'balance',
|
||||
'code_imp',
|
||||
'refactor',
|
||||
'config',
|
||||
'admin',
|
||||
'server'
|
||||
]
|
||||
|
||||
def dictToTuples(inp):
|
||||
return [(k, v) for k, v in inp.items()]
|
||||
|
||||
old_changelog_cache = os.path.join(args.ymlDir, '.all_changelog.yml')
|
||||
|
||||
failed_cache_read = True
|
||||
if os.path.isfile(old_changelog_cache):
|
||||
try:
|
||||
print('Reading old changelog cache...')
|
||||
data = {}
|
||||
with open(old_changelog_cache,encoding='utf-8') as f:
|
||||
(_, all_changelog_entries) = yaml.load_all(f, Loader=yaml.SafeLoader)
|
||||
|
||||
# Categorize changes by year and month
|
||||
for _date in all_changelog_entries.keys():
|
||||
ty = type(_date).__name__
|
||||
formattedDate = _date.strftime(fileDateFormat)
|
||||
if not formattedDate in data:
|
||||
data[formattedDate] = {}
|
||||
data[formattedDate][_date] = all_changelog_entries[_date]
|
||||
# Write files with changes by year and month
|
||||
for month in data.keys():
|
||||
print("Writing " + month + ".yml...")
|
||||
if not os.path.exists(archiveDir):
|
||||
os.makedirs(archiveDir)
|
||||
currentFile = os.path.join(archiveDir, month + '.yml')
|
||||
with open(currentFile, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(data[month], f, default_flow_style=False)
|
||||
# Remove the old changelog cache, as we won't use it anymore
|
||||
print("Removing old changelog cache...")
|
||||
os.remove(old_changelog_cache)
|
||||
old_changelog_html = os.path.join(args.ymlDir, '..', 'changelog.html')
|
||||
if os.path.isfile(old_changelog_html):
|
||||
print("Removing old changelog html...")
|
||||
os.remove(old_changelog_html)
|
||||
except Exception as e:
|
||||
print("Failed to read old changelog cache:")
|
||||
print(e, file=sys.stderr)
|
||||
|
||||
errors = False
|
||||
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)
|
||||
formattedDate = today.strftime(fileDateFormat)
|
||||
monthFile = os.path.join(archiveDir, formattedDate + '.yml')
|
||||
print(' Reading {}...'.format(fileName))
|
||||
cl = {}
|
||||
with open(fileName, 'r') as f:
|
||||
cl = yaml.load(f, Loader=yaml.SafeLoader)
|
||||
currentEntries = {}
|
||||
if os.path.exists(monthFile):
|
||||
with open(monthFile,'r',encoding='utf-8') as f:
|
||||
currentEntries = yaml.load(f, Loader=yaml.SafeLoader)
|
||||
if today not in currentEntries:
|
||||
currentEntries[today] = {}
|
||||
author_entries = currentEntries[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:
|
||||
errors = True
|
||||
print(' {0}: Invalid prefix {1}'.format(fileName, change_type), file=sys.stderr)
|
||||
author_entries += [change]
|
||||
new += 1
|
||||
currentEntries[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):
|
||||
print(' Deleting {0} (delete-after set)...'.format(fileName))
|
||||
os.remove(fileName)
|
||||
|
||||
with open(monthFile, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(currentEntries, f, default_flow_style=False)
|
||||
|
||||
if errors:
|
||||
sys.exit(1)
|
||||
|
||||
@@ -47,7 +47,7 @@ if [ $retVal -ne 0 ]; then
|
||||
fi
|
||||
|
||||
#Checking for a change to html/changelogs/example.yml
|
||||
md5sum -c - <<< "88490b460c26947f5ec1ab1bb9fa9f17 *html/changelogs/example.yml"
|
||||
md5sum -c - <<< "0c56937110d88f750a32d9075ddaab8b *html/changelogs/example.yml"
|
||||
retVal=$?
|
||||
if [ $retVal -ne 0 ]; then
|
||||
echo -e "${RED}Do not modify the example.yml changelog file.${NC}"
|
||||
@@ -71,4 +71,4 @@ if [ $retVal -ne 0 ]; then
|
||||
fi
|
||||
|
||||
# Quit with our status code
|
||||
exit $FAILED
|
||||
exit $FAILED
|
||||
|
||||
@@ -4513,11 +4513,11 @@
|
||||
#include "code\ZAS\Zone.dm"
|
||||
#include "interface\interface.dm"
|
||||
#include "interface\skin.dmf"
|
||||
#include "maps\runtime_station.dm"
|
||||
#include "maps\atoll\atoll_decals.dm"
|
||||
#include "maps\atoll\atoll_objs.dm"
|
||||
#include "maps\atoll\atoll_turfs.dm"
|
||||
#include "maps\gateway_archive_vr\blackmarketpackers.dm"
|
||||
#include "maps\southern_cross\southern_cross.dm"
|
||||
#include "maps\southern_cross\items\encryptionkey_sc.dm"
|
||||
#include "maps\southern_cross\items\headset_sc.dm"
|
||||
#include "maps\southern_cross\items\clothing\sc_accessory.dm"
|
||||
@@ -4538,6 +4538,7 @@
|
||||
#include "maps\~map_system\maps.dm"
|
||||
#include "modular_chomp\code\coalesce_ch.dm"
|
||||
#include "modular_chomp\code\global.dm"
|
||||
#include "modular_chomp\code\_global_vars\tgui.dm"
|
||||
#include "modular_chomp\code\_HELPERS\icons\flatten.dm"
|
||||
#include "modular_chomp\code\_HELPERS\type2type\color.dm"
|
||||
#include "modular_chomp\code\_onclick\hud\alert.dm"
|
||||
@@ -4546,6 +4547,7 @@
|
||||
#include "modular_chomp\code\datums\autolathe\engineering_ch.dm"
|
||||
#include "modular_chomp\code\datums\autolathe\general_ch.dm"
|
||||
#include "modular_chomp\code\datums\browser\color_matrix_picker.dm"
|
||||
#include "modular_chomp\code\datums\changelog\changelog.dm"
|
||||
#include "modular_chomp\code\datums\components\gargoyle.dm"
|
||||
#include "modular_chomp\code\datums\interfaces\appearance.dm"
|
||||
#include "modular_chomp\code\datums\outfits\jobs\noncrew.dm"
|
||||
@@ -4582,6 +4584,7 @@
|
||||
#include "modular_chomp\code\matrices\color_matrix.dm"
|
||||
#include "modular_chomp\code\modules\admin\functions\modify_traits.dm"
|
||||
#include "modular_chomp\code\modules\artifice\deadringer.dm"
|
||||
#include "modular_chomp\code\modules\asset_cache\asset_list.dm"
|
||||
#include "modular_chomp\code\modules\client\preferences.dm"
|
||||
#include "modular_chomp\code\modules\client\preferences_spawnpoints.dm"
|
||||
#include "modular_chomp\code\modules\client\preference_setup\general\03_body.dm"
|
||||
|
||||
Reference in New Issue
Block a user