Skip to content

Commit 046c94d

Browse files
Merge branch 'master' into engine-release
2 parents 0b40563 + 58bded4 commit 046c94d

14 files changed

Lines changed: 192 additions & 148 deletions

File tree

.github/workflows/release-engine.yml

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ env:
1717
IS_PUBLIC: YES
1818

1919
jobs:
20-
release:
21-
name: Release
20+
release-java:
21+
name: Release Java
2222
runs-on: ubuntu-latest
2323
permissions:
2424
contents: read
@@ -92,3 +92,82 @@ jobs:
9292
9393
- name: Upload specs
9494
run: gsutil -m rsync -a $OBJECT_ACL -r ./specs gs://$GCS_BUCKET/specs/${RELEASE_ARTIFACT_ID}/$RELEASE_VERSION
95+
release-python:
96+
name: Release Python
97+
runs-on: ubuntu-latest
98+
permissions:
99+
contents: read
100+
id-token: write
101+
102+
steps:
103+
- uses: conda-incubator/setup-miniconda@v3
104+
with:
105+
python-version: 3.12
106+
107+
- name: Checkout branch
108+
uses: actions/checkout@v3
109+
110+
- name: Inject release version
111+
run: |
112+
release_version=${GITHUB_REF#refs/*/}
113+
release_version=${release_version#engine.}
114+
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
115+
echo "The release version is $release_version"
116+
117+
- name: Authenticate to Google Cloud Platform
118+
uses: google-github-actions/auth@v1
119+
with:
120+
create_credentials_file: true
121+
workload_identity_provider: projects/830784087321/locations/global/workloadIdentityPools/releases/providers/github-workflow
122+
service_account: releases-agent@mitbattlecode.iam.gserviceaccount.com
123+
124+
- name: Set up Google Cloud SDK
125+
uses: 'google-github-actions/setup-gcloud@v1'
126+
127+
- name: Clone private maps
128+
if: ${{ env.IS_PUBLIC != 'YES' }}
129+
uses: actions/checkout@v3
130+
with:
131+
repository: battlecode/private-maps
132+
token: ${{ secrets.CI_REPOSITORY_CLONE_PAT }}
133+
path: private-maps
134+
135+
- name: Inject private maps
136+
if: ${{ env.IS_PUBLIC != 'YES' }}
137+
run: |
138+
source="private-maps/$RELEASE_ARTIFACT_ID"
139+
dest="$RELEASE_ARTIFACT_ID/maps"
140+
if [ -d "$source" ]; then
141+
cp -r -i "$source/." "$dest/" < /dev/null &> private-maps-copy-log
142+
if [ -s "private-maps-copy-log" ]; then
143+
echo "FAILED! Public and private maps should not intersect."
144+
cat private-maps-copy-log
145+
exit 1
146+
fi
147+
fi
148+
149+
- name: Build python package
150+
shell: bash -el {0} # Make sure conda is activated
151+
run: |
152+
conda info
153+
python --version
154+
pip install --upgrade build
155+
SETUPTOOLS_SCM_PRETEND_VERSION=${RELEASE_VERSION} python -m build
156+
157+
- name: Determine access control
158+
run: |
159+
[[ "$IS_PUBLIC" = "YES" ]] && acl="public-read" || acl="project-private"
160+
echo "OBJECT_ACL=$acl" >> $GITHUB_ENV
161+
echo "Objects will be uploaded with ACL $acl"
162+
163+
- name: Upload python package to remote repository
164+
run: |
165+
mv *.tar.gz battlecode.tar.gz
166+
gsutil -m cp -a $OBJECT_ACL battlecode.tar.gz gs://$GCS_BUCKET/maven/org/battlecode/${RELEASE_ARTIFACT_ID}-python/${RELEASE_VERSION}/
167+
working-directory: ./dist
168+
169+
# TODO: docs?
170+
#- name: Upload javadocs
171+
# run: |
172+
# unzip -d ${{ runner.temp }}/javadoc $HOME/.m2/repository/org/battlecode/$RELEASE_ARTIFACT_ID/$RELEASE_VERSION/*-javadoc.jar
173+
# gsutil -m rsync -a $OBJECT_ACL -r ${{ runner.temp }}/javadoc gs://$GCS_BUCKET/javadoc/$RELEASE_ARTIFACT_ID/$RELEASE_VERSION

client/src/components/sidebar/runner/runner.tsx

Lines changed: 106 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ type RunnerPageProps = {
2121
}
2222

2323
type Preset = {
24-
name: string,
25-
maps: Set<string>,
24+
name: string
25+
maps: Set<string>
2626
}
2727

2828
export const RunnerPage: React.FC<RunnerPageProps> = ({ open, scaffold }) => {
@@ -121,7 +121,7 @@ export const RunnerPage: React.FC<RunnerPageProps> = ({ open, scaffold }) => {
121121
</>
122122
) : (
123123
<>
124-
<LanguageSelector language={language} onChange={changeLanguage} />
124+
{/*<LanguageSelector language={language} onChange={changeLanguage} />*/}
125125
<LanguageVersionSelector
126126
language={language}
127127
version={langVersion}
@@ -149,8 +149,14 @@ export const RunnerPage: React.FC<RunnerPageProps> = ({ open, scaffold }) => {
149149
<MapSelector
150150
maps={maps}
151151
availableMaps={availableMaps}
152-
onSelect={(m) => {setMaps(new Set([...maps, ...m])); setPreset(undefined)}}
153-
onDeselect={(m) => {setMaps(new Set([...maps].filter((x) => !m.includes(x)))); setPreset(undefined)}}
152+
onSelect={(m) => {
153+
setMaps(new Set([...maps, ...m]))
154+
setPreset(undefined)
155+
}}
156+
onDeselect={(m) => {
157+
setMaps(new Set([...maps].filter((x) => !m.includes(x))))
158+
setPreset(undefined)
159+
}}
154160
/>
155161
<PresetSelector
156162
preset={preset}
@@ -164,8 +170,9 @@ export const RunnerPage: React.FC<RunnerPageProps> = ({ open, scaffold }) => {
164170
newPreset={(n) => {
165171
const preexisting: Preset | undefined = availablePresets.find((x) => x.name === n)
166172
if (preexisting === undefined) {
167-
const p = {name: n, maps: maps}
168-
setAvailablePresets(new Array(...availablePresets, p)); setPreset(p)
173+
const p = { name: n, maps: maps }
174+
setAvailablePresets(new Array(...availablePresets, p))
175+
setPreset(p)
169176
} else {
170177
preexisting.maps = maps
171178
setPreset(preexisting)
@@ -422,26 +429,40 @@ interface PresetSelectorProps {
422429
deletePreset: (preset: Preset | undefined) => void
423430
}
424431

425-
const PresetSelector: React.FC<PresetSelectorProps> = ({ preset, availablePresets, setPreset, newPreset, deletePreset }) => {
426-
const [newName, setNewName] = useState<string>("")
432+
const PresetSelector: React.FC<PresetSelectorProps> = ({
433+
preset,
434+
availablePresets,
435+
setPreset,
436+
newPreset,
437+
deletePreset
438+
}) => {
439+
const [newName, setNewName] = useState<string>('')
427440
return (
428441
<div className="mt-3">
429442
<label>Map Presets</label>
430443
<div className="flex flex-row">
431444
<Button
432445
className="flex-none m-1 w-10 h-10"
433-
style={{padding: 10}}
446+
style={{ padding: 10 }}
434447
onClick={() => deletePreset(preset)}
435448
disabled={preset === undefined}
436-
><BsTrash className="font-bold stroke-[0.5] text-xl"/></Button>
449+
>
450+
<BsTrash className="font-bold stroke-[0.5] text-xl" />
451+
</Button>
437452
<Select
438453
className="flex-initial m-1"
439-
style={{width: 192, height: 40}} // Select has w-full and h-full by default
440-
value={preset?.name ?? ""}
441-
onChange={(e) => {setPreset(availablePresets.find(preset => preset.name === e))}}
454+
style={{ width: 192, height: 40 }} // Select has w-full and h-full by default
455+
value={preset?.name ?? ''}
456+
onChange={(e) => {
457+
setPreset(availablePresets.find((preset) => preset.name === e))
458+
}}
442459
disabled={availablePresets.length === 0}
443460
>
444-
{preset === undefined ? <option key="" value="">Select...</option> : undefined}
461+
{preset === undefined ? (
462+
<option key="" value="">
463+
Select...
464+
</option>
465+
) : undefined}
445466
{availablePresets.map((p) => (
446467
<option key={p.name} value={p.name}>
447468
{p.name}
@@ -452,13 +473,15 @@ const PresetSelector: React.FC<PresetSelectorProps> = ({ preset, availablePreset
452473
className="w-28 flex-initial m-1 h-10"
453474
value={newName}
454475
placeholder="New"
455-
onKeyDown={ev => {
456-
if (ev.key === "Enter") {
457-
if (newName !== "") { newPreset(newName) }
458-
setNewName("")
476+
onKeyDown={(ev) => {
477+
if (ev.key === 'Enter') {
478+
if (newName !== '') {
479+
newPreset(newName)
480+
}
481+
setNewName('')
459482
}
460483
}}
461-
onInput={n => setNewName(n.currentTarget.value)}
484+
onInput={(n) => setNewName(n.currentTarget.value)}
462485
/>
463486
</div>
464487
</div>
@@ -473,7 +496,7 @@ type Props = {
473496

474497
export const Console: React.FC<Props> = ({ lines }) => {
475498
const consoleRef = useRef<HTMLDivElement>(null)
476-
const listRef = useRef<FixedSizeList>(null);
499+
const listRef = useRef<FixedSizeList>(null)
477500

478501
const [tail, setTail] = useState(true)
479502
const [popout, setPopout] = useState(false)
@@ -486,16 +509,15 @@ export const Console: React.FC<Props> = ({ lines }) => {
486509
const goToNextMatch = () => {
487510
if (!matches.length) return
488511
setActiveMatch((prev) => (prev + 1) % matches.length)
489-
listRef.current?.scrollToItem(matches[activeMatch], 'center');
512+
listRef.current?.scrollToItem(matches[activeMatch], 'center')
490513
}
491514

492515
const goToPrevMatch = () => {
493516
if (!matches.length) return
494517
setActiveMatch((prev) => (prev - 1 + matches.length) % matches.length)
495-
listRef.current?.scrollToItem(matches[activeMatch], 'center');
518+
listRef.current?.scrollToItem(matches[activeMatch], 'center')
496519
}
497520

498-
499521
const getLineClass = (line: ConsoleLine) => {
500522
switch (line.type) {
501523
case 'output':
@@ -520,19 +542,19 @@ export const Console: React.FC<Props> = ({ lines }) => {
520542
}
521543
}, 5)
522544
}
523-
545+
524546
const ConsoleRow = (props: { index: number; style: any }) => {
525547
const row = lines.get(props.index)!
526548
const content = row.content
527549

528-
const isMatch = query.length > 0 && content.toLowerCase().includes(query.toLowerCase());
529-
const isActive = isMatch && matches[activeMatch] === props.index;
550+
const isMatch = query.length > 0 && content.toLowerCase().includes(query.toLowerCase())
551+
const isActive = isMatch && matches[activeMatch] === props.index
530552

531553
const getHighlightClass = () => {
532-
if (isActive) return ' bg-yellow-400/60 text-black';
533-
if (isMatch) return ' bg-yellow-200/20';
534-
return '';
535-
};
554+
if (isActive) return ' bg-yellow-400/60 text-black'
555+
if (isMatch) return ' bg-yellow-200/20'
556+
return ''
557+
}
536558

537559
// Check if the printout is from a bot. If so, add a special click element
538560
// that selects the bot
@@ -558,7 +580,10 @@ export const Console: React.FC<Props> = ({ lines }) => {
558580
}
559581

560582
return (
561-
<span style={props.style} className={getLineClass(row) + ' text-xs whitespace-nowrap' + getHighlightClass()}>
583+
<span
584+
style={props.style}
585+
className={getLineClass(row) + ' text-xs whitespace-nowrap' + getHighlightClass()}
586+
>
562587
{content}
563588
</span>
564589
)
@@ -656,67 +681,65 @@ export const Console: React.FC<Props> = ({ lines }) => {
656681
setActiveMatch(0)
657682
}, [query, lines.effectiveLength()])
658683

659-
660684
return (
661685
<>
662686
<Tooltip location="bottom" text={'View output from running the game'}>
663687
<Button onClick={() => updatePopout(true)}>Console</Button>
664688
</Tooltip>
665689
<BasicDialog open={popout} onCancel={() => updatePopout(false)} title="Console" width="lg">
666690
<div className="relative flex flex-col grow h-full w-full min-h-[400px]">
667-
{searchOpen && (
668-
<div className="flex items-center gap-2 mb-1">
669-
<input
670-
autoFocus
671-
className="flex-grow px-2 py-1 text-xs bg-black border border-white rounded"
672-
placeholder="Find…"
673-
value={query}
674-
onChange={(e) => setQuery(e.target.value)}
675-
onKeyDown={(e) => {
676-
if (e.key === 'Escape') {
677-
setSearchOpen(false)
678-
setQuery('')
679-
}
680-
if (e.key === 'Enter') {
681-
e.shiftKey ? goToPrevMatch() : goToNextMatch()
682-
}
683-
}}
684-
/>
685-
<button
686-
className="px-2 py-1 text-xs border border-white rounded disabled:opacity-40"
687-
onClick={goToPrevMatch}
688-
disabled={matches.length === 0}
689-
title="Previous match"
690-
>
691-
<ChevronUpIcon className="w-4 h-4" />
692-
</button>
693-
<button
694-
className="px-2 py-1 text-xs border border-white rounded disabled:opacity-40"
695-
onClick={goToNextMatch}
696-
disabled={matches.length === 0}
697-
title="Next match"
698-
>
699-
<ChevronDownIcon className="w-4 h-4" />
700-
</button>
701-
<span className="text-xs opacity-70">
702-
{matches.length ? `${activeMatch + 1}/${matches.length}` : '0/0'}
703-
</span>
704-
</div>
705-
706-
)}
691+
{searchOpen && (
692+
<div className="flex items-center gap-2 mb-1">
693+
<input
694+
autoFocus
695+
className="flex-grow px-2 py-1 text-xs bg-black border border-white rounded"
696+
placeholder="Find…"
697+
value={query}
698+
onChange={(e) => setQuery(e.target.value)}
699+
onKeyDown={(e) => {
700+
if (e.key === 'Escape') {
701+
setSearchOpen(false)
702+
setQuery('')
703+
}
704+
if (e.key === 'Enter') {
705+
e.shiftKey ? goToPrevMatch() : goToNextMatch()
706+
}
707+
}}
708+
/>
709+
<button
710+
className="px-2 py-1 text-xs border border-white rounded disabled:opacity-40"
711+
onClick={goToPrevMatch}
712+
disabled={matches.length === 0}
713+
title="Previous match"
714+
>
715+
<ChevronUpIcon className="w-4 h-4" />
716+
</button>
717+
<button
718+
className="px-2 py-1 text-xs border border-white rounded disabled:opacity-40"
719+
onClick={goToNextMatch}
720+
disabled={matches.length === 0}
721+
title="Next match"
722+
>
723+
<ChevronDownIcon className="w-4 h-4" />
724+
</button>
725+
<span className="text-xs opacity-70">
726+
{matches.length ? `${activeMatch + 1}/${matches.length}` : '0/0'}
727+
</span>
728+
</div>
729+
)}
707730

708-
<div className="flex flex-col grow h-full w-full">
709-
<div
710-
ref={consoleRef}
711-
tabIndex={0}
712-
className="flex-grow border border-white py-1 px-1 rounded-md overflow-auto flex flex-col min-h-[250px] w-full"
713-
style={{ height: '75vh', maxHeight: '75vh' }}
714-
onKeyDown={handleKeyDown}
715-
>
716-
{popout && lineList}
731+
<div className="flex flex-col grow h-full w-full">
732+
<div
733+
ref={consoleRef}
734+
tabIndex={0}
735+
className="flex-grow border border-white py-1 px-1 rounded-md overflow-auto flex flex-col min-h-[250px] w-full"
736+
style={{ height: '75vh', maxHeight: '75vh' }}
737+
onKeyDown={handleKeyDown}
738+
>
739+
{popout && lineList}
740+
</div>
717741
</div>
718742
</div>
719-
</div>
720743
</BasicDialog>
721744
</>
722745
)

0 commit comments

Comments
 (0)