Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions .github/scripts/test_release_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def select(self, version, repository=REPOSITORY, ref='refs/heads/master-1.12'):
values = dict(line.split('=', 1) for line in output.read_text().splitlines()) if output.exists() else {}
return result.returncode, values

def validate(self, minecraft, names=None, mutation=None, release_exists=False, wrong_tag=False, audit_success=True, qualification=None, local_receipt=None):
def validate(self, minecraft, names=None, mutation=None, release_exists=False, wrong_tag=False, audit_success=True, qualification=None, local_receipt=None, audit_run=None):
suffix, branch, forge = {
'1.10.2': ('110021', '1.10.2', '12.18.3.2511'),
'1.11.2': ('111021', '1.11.2-dev', '13.20.1.2588'),
Expand Down Expand Up @@ -100,8 +100,13 @@ def command(args, **options):
if qualification:row.update(qualification)
return json.dumps({'workflow_runs':[row]})
if '/actions/workflows/' in args[-1]:
return json.dumps({'workflow_runs': [{'id': 1, 'display_title': 'Audit ' + minecraft + ' artifacts from ' + SHA,
'conclusion': 'success' if audit_success else 'failure'}]})
audit = {'id': 1, 'display_title': 'Audit ' + minecraft + ' artifacts from ' + SHA,
'conclusion': 'success' if audit_success else 'failure', 'event': 'workflow_run',
'head_sha': 'c' * 40, 'head_branch': 'master-1.12',
'path': '.github/workflows/artifact-audit-1.21.yml'}
if audit_run is not None:
audit.update(audit_run)
return json.dumps({'workflow_runs': [audit]})
return json.dumps({'check_runs': [dict(name=name, id=i, conclusion='success') for i, name in enumerate(checks)]})
def existing(args, **options):
if '/releases/tags/' in args[-1] and release_exists:
Expand All @@ -112,7 +117,7 @@ def existing(args, **options):
code = script('Validate identity, exact commit and successful checks').split("python3 - <<'PY'\n", 1)[1].rsplit('\nPY', 1)[0]
with tempfile.TemporaryDirectory() as directory, patch.dict(os.environ, {
'RELEASE_VERSION': version, 'GITHUB_REPOSITORY': REPOSITORY,
'MINECRAFT_VERSION': minecraft, 'SOURCE_BRANCH': branch,
'MINECRAFT_VERSION': minecraft, 'SOURCE_BRANCH': branch, 'GITHUB_SHA': 'c' * 40,
'GITHUB_OUTPUT': str(Path(directory) / 'output'),
'LOCAL_QUALIFICATION':json.dumps(receipt) if receipt else ''}), \
patch('pathlib.Path.read_text', side_effect=['\n'.join(k+'='+v for k,v in values.items()),json.dumps({'files':files,'local_qualification_complete':True,'qualification_integrity_status':'verified','manual_accepted':True})]), \
Expand Down Expand Up @@ -143,6 +148,51 @@ def test_1211_requires_exact_archives_and_java_21(self):
with self.subTest(options=options), self.assertRaises(SystemExit):
self.validate('1.21.1', **options)

def test_1211_audit_receives_registered_archive_workflow_completion(self):
audit = WORKFLOW.with_name('artifact-audit-1.21.yml').read_text(encoding='utf-8')
event_names = audit.split('workflows: [', 1)[1].split(']', 1)[0].split(',')
self.assertIn('LootableBodies 1.20 CI', [name.strip() for name in event_names])

def test_1211_only_accepts_an_audit_from_the_active_dispatcher(self):
self.validate('1.21.1', audit_run={'event': 'workflow_dispatch'})
for changes in ({'event': 'push'}, {'head_branch': 'master-1.21.1'},
{'head_sha': 'd' * 40}, {'path': '.github/workflows/artifact-audit-1.20.yml'}):
with self.subTest(changes=changes), self.assertRaises(SystemExit):
self.validate('1.21.1', audit_run=changes)

def test_1211_audit_requires_the_successful_current_source_push(self):
path = WORKFLOW.with_name('artifact-audit-1.21.yml')
text = path.read_text(encoding='utf-8')
code = text.split("python3 - <<'PY'\n", 1)[1].split('\n PY', 1)[0]
code = textwrap.dedent(code)
good = {'id': 25, 'head_repository': {'full_name': REPOSITORY}, 'event': 'push',
'head_branch': 'master-1.21.1', 'head_sha': SHA, 'path': '.github/workflows/native120.yml',
'status': 'completed', 'conclusion': 'success'}

def resolve(run, branch=SHA, run_id='25', source=SHA):
def api(args):
if args[-1].endswith('/actions/runs/25'):
return json.dumps(run)
if args[-1].endswith('/git/ref/heads/master-1.21.1'):
return json.dumps({'object': {'sha': branch}})
raise AssertionError(args)
with tempfile.TemporaryDirectory() as folder, patch('subprocess.check_output', side_effect=api):
output = Path(folder) / 'output'
with patch.dict(os.environ, SOURCE_RUN=run_id, SOURCE_SHA=source, GITHUB_OUTPUT=str(output)):
exec(compile(code, 'audit-source', 'exec'), {})
return output.read_text()

self.assertEqual('run=25\nsha=' + SHA + '\n', resolve(good))
for changes in ({'event': 'pull_request'}, {'head_sha': 'b' * 40}, {'head_branch': 'master-1.20.6'},
{'head_repository': {'full_name': 'SkyBlade1978/LootableBodies'}},
{'path': '.github/workflows/native119.yml'}, {'conclusion': 'failure'}, {'id': 26}):
with self.subTest(changes=changes), self.assertRaises(SystemExit):
resolve(dict(good, **changes))
with self.assertRaises(SystemExit):
resolve(good, branch='b' * 40)
with self.assertRaises(SystemExit):
resolve(good, run_id='25;false')

def test_future_12111_candidate_cannot_dispatch_publication(self):
self.assertNotEqual(0, self.select('2.4.14.121111')[0])

Expand Down
60 changes: 51 additions & 9 deletions .github/workflows/artifact-audit-1.21.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,75 @@
name: Audit LootableBodies 1.21 artifacts
run-name: Audit 1.21.1 artifacts from ${{ github.event.workflow_run.head_sha }}
run-name: Audit 1.21.1 artifacts from ${{ github.event.workflow_run.head_sha || inputs.source_sha }}
on:
workflow_run:
workflows: [LootableBodies 1.21.1 CI]
workflows: [LootableBodies 1.20 CI, LootableBodies 1.20.6 CI, LootableBodies 1.21.1 CI]
types: [completed]
workflow_dispatch:
inputs:
source_run:
description: Successful archive build run ID
required: true
type: string
source_sha:
description: Exact merged 1.21.1 source SHA
required: true
type: string
permissions:
contents: read
actions: read
jobs:
audit:
if: >-
github.repository == 'MinecraftModDevelopmentMods/LootableBodies' &&
github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'master-1.21.1' && github.event.workflow_run.name == 'LootableBodies 1.21.1 CI'
github.ref == 'refs/heads/master-1.12' &&
(github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'master-1.21.1' && github.event.workflow_run.name == 'LootableBodies 1.21.1 CI'))
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Verify the exact merged archive build
id: source
env:
GH_TOKEN: ${{ github.token }}
SOURCE_RUN: ${{ github.event.workflow_run.id || inputs.source_run }}
SOURCE_SHA: ${{ github.event.workflow_run.head_sha || inputs.source_sha }}
run: |
python3 - <<'PY'
import json, os, re, subprocess

repo = 'MinecraftModDevelopmentMods/LootableBodies'
run_id = os.environ['SOURCE_RUN']
source = os.environ['SOURCE_SHA']
if not re.fullmatch(r'[1-9][0-9]*', run_id) or not re.fullmatch(r'[a-f0-9]{40}', source):
raise SystemExit('An exact build run ID and source SHA are required')

def api(path):
return json.loads(subprocess.check_output(['gh', 'api', f'repos/{repo}/{path}']))

run = api(f'actions/runs/{run_id}')
branch = api('git/ref/heads/master-1.21.1')
if (str(run['id']) != run_id or run['head_repository']['full_name'] != repo or
run['event'] != 'push' or run['head_branch'] != 'master-1.21.1' or run['head_sha'] != source or
run['path'] != '.github/workflows/native120.yml' or run['status'] != 'completed' or
run['conclusion'] != 'success' or branch['object']['sha'] != source):
raise SystemExit('The selected run is not the successful build of the current merged 1.21.1 source')
with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
out.write(f'run={run_id}\nsha={source}\n')
PY
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.event.workflow_run.head_sha }}
ref: ${{ steps.source.outputs.sha }}
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: LootableBodies-1.21.1-${{ github.event.workflow_run.head_sha }}
run-id: ${{ github.event.workflow_run.id }}
name: LootableBodies-1.21.1-${{ steps.source.outputs.sha }}
run-id: ${{ steps.source.outputs.run }}
github-token: ${{ github.token }}
path: audited
- name: Independently verify every locally qualified byte
env:
SOURCE_SHA: ${{ github.event.workflow_run.head_sha }}
SOURCE_SHA: ${{ steps.source.outputs.sha }}
run: |
python3 -B tools/native120_build.py --bundle audited
python3 - <<'PY'
Expand All @@ -43,6 +85,6 @@ jobs:
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: native120-independent-audit-${{ github.event.workflow_run.head_sha }}
name: native120-independent-audit-${{ steps.source.outputs.sha }}
if-no-files-found: error
path: independent-audit.json
18 changes: 11 additions & 7 deletions .github/workflows/deploy-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,13 @@ jobs:
raise SystemExit(f'The selected commit has no successful {name} check')
if minecraft in ('1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19.4', '1.20.1', '1.20.6', '1.21.1'):
target = minecraft.rsplit('.', 1)[0]
event_query = '' if minecraft == '1.21.1' else '&event=workflow_run'
audits = json.loads(subprocess.check_output(['gh', 'api',
f'repos/{repo}/actions/workflows/artifact-audit-{target}.yml/runs?event=workflow_run&per_page=100'], text=True))['workflow_runs']
matching = [run for run in audits if run['display_title'] == f'Audit {minecraft} artifacts from {sha}']
f'repos/{repo}/actions/workflows/artifact-audit-{target}.yml/runs?per_page=100{event_query}'], text=True))['workflow_runs']
matching = [run for run in audits if run['display_title'] == f'Audit {minecraft} artifacts from {sha}'
and (minecraft != '1.21.1' or (run['event'] in ('workflow_run', 'workflow_dispatch')
and run['head_branch'] == 'master-1.12' and run['head_sha'] == os.environ['GITHUB_SHA']
and run['path'] == '.github/workflows/artifact-audit-1.21.yml'))]
if not matching or max(matching, key=lambda run: run['id'])['conclusion'] != 'success':
raise SystemExit('The selected commit has no successful independent artifact audit')
release = subprocess.run(['gh', 'api', f'repos/{repo}/releases/tags/{version}'], capture_output=True, text=True)
Expand Down Expand Up @@ -213,25 +217,25 @@ jobs:
with:
ref: ${{ needs.preflight.outputs.release_sha }}
- name: Install Mavenizer Java
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1'
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1'
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: '25.0.3+9.0.LTS'
- name: Install production Java
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1'
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1'
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: ${{ needs.preflight.outputs.minecraft_version == '1.18.2' && '17.0.20+101' || needs.preflight.outputs.minecraft_version == '1.19.4' && '17.0.20+101' || needs.preflight.outputs.minecraft_version == '1.20.1' && '17.0.20+101' || needs.preflight.outputs.minecraft_version == '1.17.1' && '16.0.2+7' || '8.0.502+7' }}
- name: Install Gradle Java
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1'
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1'
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
distribution: temurin
java-version: ${{ needs.preflight.outputs.minecraft_version == '1.18.2' && '17.0.20+101' || needs.preflight.outputs.minecraft_version == '1.19.4' && '17.0.20+101' || needs.preflight.outputs.minecraft_version == '1.20.1' && '17.0.20+101' || '17.0.1+12' }}
- name: Pin the production toolchain
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1'
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1'
run: |
if [[ '${{ needs.preflight.outputs.minecraft_version }}' == '1.18.2' || '${{ needs.preflight.outputs.minecraft_version }}' == '1.19.4' || '${{ needs.preflight.outputs.minecraft_version }}' == '1.20.1' ]]; then
echo "LOOTABLEBODIES_JAVA17_HOME=$JAVA_HOME_17_X64" >> "$GITHUB_ENV"
Expand All @@ -242,7 +246,7 @@ jobs:
fi
echo "LOOTABLEBODIES_MAVENIZER_JAVA_HOME=$JAVA_HOME_25_X64" >> "$GITHUB_ENV"
- name: Set up Gradle
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1' && needs.preflight.outputs.minecraft_version != '1.21.1'
if: needs.preflight.outputs.minecraft_version != '1.18.2' && needs.preflight.outputs.minecraft_version != '1.19.4' && needs.preflight.outputs.minecraft_version != '1.20.1' && needs.preflight.outputs.minecraft_version != '1.20.6' && needs.preflight.outputs.minecraft_version != '1.21.1'
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6
- name: Download the qualified native117 six-file bundle
if: needs.preflight.outputs.minecraft_version == '1.17.1'
Expand Down
Loading