mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
Add GitHub Actions configuration
This commit is contained in:
parent
9a6f925bcb
commit
35c7afc6a1
11 changed files with 341 additions and 9 deletions
50
.github/actions/download_artifacts/action.yaml
vendored
Normal file
50
.github/actions/download_artifacts/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
name: Download Artifacts
|
||||
description: Download artifacts preserving file permissions
|
||||
inputs:
|
||||
keys:
|
||||
description: The artifact keys
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
shell: python3 {0}
|
||||
run: |
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.abspath('.github/workflows'))
|
||||
|
||||
from configure_logger import configure_logger
|
||||
from github_api_request import json_github_api_request, download_github_api_request
|
||||
|
||||
from logging import getLogger
|
||||
from os import environ
|
||||
from zipfile import ZipFile
|
||||
import tarfile
|
||||
|
||||
logger = getLogger(__name__)
|
||||
configure_logger(logger)
|
||||
|
||||
input_keys = """${{ inputs.keys }}"""
|
||||
logger.debug(f'Input keys: {input_keys}')
|
||||
artifact_keys = filter(None, [x.strip() for x in input_keys.split('\n')])
|
||||
logger.debug(f'Parsed keys: {artifact_keys}')
|
||||
|
||||
api_prefix = 'actions'
|
||||
artifacts_info = json_github_api_request(f'{api_prefix}/runs/{environ["GITHUB_RUN_ID"]}/artifacts')
|
||||
|
||||
for key in artifact_keys:
|
||||
artifact_id = [x['id'] for x in artifacts_info['artifacts'] if x['name'] == key][0]
|
||||
logger.debug(f'Artifact id: {key}: {artifact_id}')
|
||||
zip_file = f'{key}.zip'
|
||||
download_github_api_request(zip_file, f'{api_prefix}/artifacts/{artifact_id}/zip')
|
||||
logger.debug(f'Unzipping: {zip_file}')
|
||||
with ZipFile(zip_file) as archive:
|
||||
archive.extractall()
|
||||
os.remove(zip_file)
|
||||
tar_file = f'{key}.tar'
|
||||
logger.debug(f'Extracting: {tar_file}')
|
||||
with tarfile.open(tar_file, 'r') as tar:
|
||||
tar.extractall()
|
||||
os.remove(tar_file)
|
||||
|
||||
26
.github/actions/job_wrapper/action.yaml
vendored
Normal file
26
.github/actions/job_wrapper/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
name: Job Wrapper
|
||||
description: Setup and cleanup for build jobs
|
||||
inputs:
|
||||
artifacts:
|
||||
description: Required artifacts
|
||||
required: false
|
||||
default: ''
|
||||
command:
|
||||
description: The build command
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Get artifacts
|
||||
uses: ./.github/actions/download_artifacts
|
||||
with:
|
||||
keys: |
|
||||
JUCE-utils
|
||||
${{ inputs.artifacts }}
|
||||
- run: ${{ inputs.command }}
|
||||
shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }}
|
||||
- name: Handle job failure
|
||||
if: failure()
|
||||
run: python3 JUCE-utils/.github/workflows/post_job.py
|
||||
shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }}
|
||||
|
||||
49
.github/actions/upload_artifact/action.yaml
vendored
Normal file
49
.github/actions/upload_artifact/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
name: Upload Artifact
|
||||
description: Upload an artifact preserving file permissions
|
||||
inputs:
|
||||
key:
|
||||
description: The artifact key
|
||||
required: true
|
||||
paths:
|
||||
description: The artifact paths
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create tarball
|
||||
shell: python3 {0}
|
||||
run: |
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.abspath('.github/workflows'))
|
||||
|
||||
from configure_logger import configure_logger
|
||||
|
||||
from logging import getLogger
|
||||
from os import mkdir
|
||||
import tarfile
|
||||
|
||||
logger = getLogger(__name__)
|
||||
configure_logger(logger)
|
||||
|
||||
input_paths = """${{ inputs.paths }}"""
|
||||
logger.debug(f'Input paths: {input_paths}')
|
||||
paths = filter(None, [x.strip() for x in input_paths.split('\n')])
|
||||
logger.debug(f'Parsed paths: {paths}')
|
||||
mkdir('tmp_artifact_upload')
|
||||
archive_path = 'tmp_artifact_upload/${{ inputs.key }}.tar'
|
||||
logger.debug(f'Creating archive: {archive_path}')
|
||||
with tarfile.open('tmp_artifact_upload/${{ inputs.key }}.tar', 'w') as tar:
|
||||
for path in paths:
|
||||
logger.debug(f'Adding path to archive archive: {path}')
|
||||
tar.add(path)
|
||||
- uses: actions/upload-artifact@v4.6.0
|
||||
with:
|
||||
name: ${{ inputs.key }}
|
||||
path: tmp_artifact_upload
|
||||
- name: Clean up
|
||||
shell: python3 {0}
|
||||
run: |
|
||||
from shutil import rmtree
|
||||
rmtree('tmp_artifact_upload')
|
||||
|
||||
1
.github/workflows/check-cla.yml
vendored
1
.github/workflows/check-cla.yml
vendored
|
|
@ -7,6 +7,7 @@ jobs:
|
|||
PR_NUMBER: ${{ github.event.number }}
|
||||
steps:
|
||||
- name: check-CLA
|
||||
if: github.repository == 'juce-framework/JUCE'
|
||||
run: |
|
||||
import urllib.request
|
||||
import json
|
||||
|
|
|
|||
13
.github/workflows/configure_logger.py
vendored
Normal file
13
.github/workflows/configure_logger.py
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import logging
|
||||
from os import getenv
|
||||
from sys import stdout
|
||||
|
||||
def configure_logger(logger):
|
||||
handler = logging.StreamHandler(stdout)
|
||||
formatter = logging.Formatter('[%(name)s] %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
level = logging.DEBUG if (getenv('RUNNER_DEBUG', '0').lower() not in ('0', 'f', 'false')) else logging.WARNING
|
||||
logger.setLevel(level)
|
||||
handler.setLevel(level)
|
||||
logger.addHandler(handler)
|
||||
|
||||
55
.github/workflows/github_api_request.py
vendored
Normal file
55
.github/workflows/github_api_request.py
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
from configure_logger import configure_logger
|
||||
|
||||
from logging import getLogger
|
||||
from urllib.request import Request, urlopen
|
||||
from urllib.error import HTTPError
|
||||
from json import dumps, loads
|
||||
from os import environ
|
||||
from shutil import copyfileobj
|
||||
from time import sleep
|
||||
|
||||
logger = getLogger(__name__)
|
||||
configure_logger(logger)
|
||||
|
||||
def github_api_request(path, method='GET', data=None):
|
||||
url = f'https://api.github.com/repos/{environ["GITHUB_REPOSITORY"]}/{path}'
|
||||
logger.debug(f'Requesting GitHub API: {url}')
|
||||
serialised_data = dumps(data).encode('utf-8') if data else None
|
||||
if serialised_data:
|
||||
logger.debug(f'Data: {serialised_data}')
|
||||
req = Request(
|
||||
url=url,
|
||||
method=method,
|
||||
headers={
|
||||
'Accept': 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
},
|
||||
data=serialised_data
|
||||
)
|
||||
req.add_unredirected_header('Authorization', f'Bearer {environ["GITHUB_API_TOKEN"]}')
|
||||
num_attempts = 0
|
||||
while True:
|
||||
response = None
|
||||
try:
|
||||
response = urlopen(req)
|
||||
return response
|
||||
except HTTPError as e:
|
||||
num_attempts += 1
|
||||
if num_attempts == 3:
|
||||
logger.warning(f'GitHub API access failed\n{e.headers}\n{e.fp.read()}')
|
||||
raise e
|
||||
logger.debug(f'Request attempt {num_attempts} failed, retrying')
|
||||
sleep(5)
|
||||
|
||||
def json_github_api_request(path, method='GET', data=None):
|
||||
with github_api_request(path, method, data) as response:
|
||||
result = loads(response.read().decode('utf-8'))
|
||||
logger.debug(f'GitHub API result: {result}')
|
||||
return result
|
||||
|
||||
def download_github_api_request(filename, path, method='GET', data=None):
|
||||
with github_api_request(path, method, data) as response:
|
||||
with open(filename, 'wb') as f:
|
||||
copyfileobj(response, f)
|
||||
logger.debug(f'Downloaded to: {filename}')
|
||||
|
||||
57
.github/workflows/juce_private_build.yml
vendored
Normal file
57
.github/workflows/juce_private_build.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
name: JUCE Private Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
triggerer:
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
description: The GitHub ID to receive email notifications (leave blank)
|
||||
nightly-targets:
|
||||
required: false
|
||||
type: string
|
||||
default: "[]"
|
||||
description: A list of nightly build targets in JSON format
|
||||
cpp-std:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
description: The C++ standard to use (optional [20, 23])
|
||||
|
||||
run-name: "[${{ inputs.triggerer && inputs.triggerer || github.event.sender.login }}] ${{ github.sha }}"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: .
|
||||
# Not having the ability to do a dynamic 'uses' call is a real pain. To
|
||||
# test some new CI configuration you must set the branch in both places
|
||||
# below.
|
||||
uses: juce-framework/JUCE-utils/.github/workflows/main.yml@master
|
||||
with:
|
||||
juce-utils-branch: master
|
||||
nightly-targets: ${{ inputs.nightly-targets }}
|
||||
triggerer: ${{ inputs.triggerer && inputs.triggerer || github.event.sender.login }}
|
||||
cpp-std: ${{ inputs.cpp-std }}
|
||||
secrets: inherit
|
||||
deploy:
|
||||
if: ${{ contains(fromJSON('["master", "develop"]'), github.ref_name) && inputs.nightly-targets == '[]' }}
|
||||
needs: [build]
|
||||
name: Deploy
|
||||
uses: juce-framework/JUCE-utils/.github/workflows/deploy.yml@master
|
||||
secrets: inherit
|
||||
docs:
|
||||
if: ${{ contains(fromJSON('["master", "develop"]'), github.ref_name) && inputs.nightly-targets == '[]' }}
|
||||
needs: [deploy]
|
||||
name: Docs
|
||||
uses: juce-framework/JUCE-utils/.github/workflows/docs.yml@master
|
||||
secrets: inherit
|
||||
notify:
|
||||
if: ${{ inputs.nightly-targets == '[]' }}
|
||||
needs: [docs]
|
||||
name: Notify
|
||||
uses: juce-framework/JUCE-utils/.github/workflows/notify.yml@master
|
||||
with:
|
||||
triggerer: ${{ inputs.triggerer && inputs.triggerer || github.event.sender.login }}
|
||||
secrets: inherit
|
||||
|
||||
31
.github/workflows/juce_private_nightly_trigger.yml
vendored
Normal file
31
.github/workflows/juce_private_nightly_trigger.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
name: JUCE Private Nightly Trigger
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * *'
|
||||
env:
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TRIGGER_WORKFLOW_REF: develop
|
||||
jobs:
|
||||
juce-private-nightly-trigger:
|
||||
if: github.repository == 'juce-framework/JUCE-dev'
|
||||
name: JUCE Push Trigger
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
sparse-checkout: ./.github/workflows
|
||||
- env:
|
||||
TRIGGER_WORKFLOW_INPUTS: |
|
||||
{"triggerer":"Nightly Build","nightly-targets":${{ vars.NIGHTLY_BUILD_TARGETS }}}
|
||||
run: python3 ./.github/workflows/trigger_workflow.py
|
||||
- if: ${{ contains(fromJSON(vars.NIGHTLY_BUILD_TARGETS), 'cpp20') }}
|
||||
env:
|
||||
TRIGGER_WORKFLOW_INPUTS: |
|
||||
{"triggerer":"Nightly Build C++20","cpp-std":"20"}
|
||||
run: python3 ./.github/workflows/trigger_workflow.py
|
||||
- if: ${{ contains(fromJSON(vars.NIGHTLY_BUILD_TARGETS), 'cpp23') }}
|
||||
env:
|
||||
TRIGGER_WORKFLOW_INPUTS: |
|
||||
{"triggerer":"Nightly Build C++23","cpp-std":"23"}
|
||||
run: python3 ./.github/workflows/trigger_workflow.py
|
||||
|
||||
24
.github/workflows/juce_private_push_trigger.yml
vendored
Normal file
24
.github/workflows/juce_private_push_trigger.yml
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
name: JUCE Private Push Trigger
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- bugfix/**
|
||||
- feature/**
|
||||
jobs:
|
||||
juce-private-push-trigger:
|
||||
if: github.repository == 'juce-framework/JUCE-dev'
|
||||
name: JUCE Push Trigger
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
sparse-checkout: ./.github/workflows
|
||||
- name: Trigger a private build using the GitHub API
|
||||
env:
|
||||
GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TRIGGER_WORKFLOW_INPUTS: |
|
||||
{"triggerer":"${{ github.actor }}"}
|
||||
run: python3 ./.github/workflows/trigger_workflow.py
|
||||
|
||||
35
.github/workflows/trigger_workflow.py
vendored
Normal file
35
.github/workflows/trigger_workflow.py
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
from configure_logger import configure_logger
|
||||
from github_api_request import github_api_request, json_github_api_request
|
||||
|
||||
from logging import getLogger
|
||||
from os import getenv
|
||||
from json import loads, dumps
|
||||
|
||||
logger = getLogger(__name__)
|
||||
configure_logger(logger)
|
||||
|
||||
input_string = getenv('TRIGGER_WORKFLOW_INPUTS', '{}')
|
||||
logger.debug(f'Input variable: {input_string}')
|
||||
input_json = loads(input_string)
|
||||
for key, value in input_json.items():
|
||||
if not isinstance(value, str):
|
||||
input_json[key] = dumps(value)
|
||||
logger.debug(f'Stringified input: {input_json}')
|
||||
|
||||
api_path_prefix = 'actions/workflows'
|
||||
|
||||
workflows = json_github_api_request(api_path_prefix)
|
||||
workflow_path = getenv('TRIGGER_WORKFLOW_PATH',
|
||||
'.github/workflows/juce_private_build.yml')
|
||||
workflow = [x for x in workflows['workflows'] if x['path'] == workflow_path][0]
|
||||
logger.debug(f'Workflow: {workflow}')
|
||||
|
||||
trigger_data = {
|
||||
'ref': getenv('TRIGGER_WORKFLOW_REF', getenv('GITHUB_REF_NAME')),
|
||||
'inputs': input_json
|
||||
}
|
||||
logger.debug(f'Trigger_data: {trigger_data}')
|
||||
github_api_request(f'{api_path_prefix}/{workflow["id"]}/dispatches',
|
||||
method='POST',
|
||||
data=trigger_data)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue