Skip to content

Update Everfull Dart Holster #370

Update Everfull Dart Holster

Update Everfull Dart Holster #370

Workflow file for this run

name: bundle ASH script(s), and push to new branch
# By https://github.com/fredg1
# USER MANUAL
# This workflow should run by itself without the need for any change.
# It's, however, currently tailored to TourGuide.
# If you wish to change its behavior (change the name of the target branch, where it places the result in it, or if you wish to use it on a folder + script other than Source + relay/TourGuide.ash), all you need to modify should be in the "env" section down below.
# I'm working on making this its own action that can be called as many times as needed, on any script, with as much customization as possible, but github is still not done on the feature I'd need for that :/
env:
# Branch to checkout under ./target_branch/ . If contains {0}, {0} will be replaced by the source branch's name.
# (doesn't need to be the name of an existing branch. Will create one if needed (will be a copy of the source branch))
# examples: 'Pre-Release', 'Bundled-{0}', 'my_{0}_2.0' or just '{0}' (not the best idea, though...)
TARGET_NAME: 'Bundled-{0}'
# The path to take (folders to go through) to reach the "mafia folder" in both branches.
# RELATIVE paths only (relative to the root of the repository).
# Empty string if it is reachable from the root.
# Only its content will be transferred to <target_branch>
SOURCE_PATH_TO_MAFIA: 'Source'
# If this folder already exists on the target branch, IT'S PREVIOUS CONTENT WILL BE ERASED.
# Stuff outside of it won't.
TARGET_PATH_TO_MAFIA: ''
# comma-separated list of (relative) path and name of the ASH scripts you want to bundle, and their new names and (relative) destinations.
# Paths need to be relative to the "mafia folder".
# Any .ash script not in this list won't be transferred, so if you have scripts that don't have imports, but want them in the result, include them here anyway
# The scripts to bundle
ASH_SCRIPT_SOURCES: 'relay/relay_TourGuide.ash'
# Their (RESPECTIVE; order matters) destinations
ASH_SCRIPT_DESTINATIONS: 'relay/relay_TourGuide.ash'
on:
workflow_dispatch:
# for more info about this if you want to modify it, see
# https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestbranchestags
# and
# https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpaths
push:
paths:
#- '${{ SOURCE_PATH_TO_MAFIA }}/**' # it's impossible to query env. variables at this point, sorry :(
- '**'
- '!.github/**' # security measure: doesn't trigger if anything in .github was changed (such as the creation, modification or deletion of this very file)
# Anything past this point shouldn't need to be modified.
jobs:
build:
runs-on: windows-latest
steps:
- name: setup Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Get branch name
uses: nelonoel/branch-name@v1.0.1
# Checkout referrer (source) under ./source_branch/
- name: checkout current branch
uses: actions/checkout@v2
with:
path: ./source_branch
# Parse wanted target name, then checkout under ./target_branch/
- name: set desired target branch
id: set-target
shell: python
run: |
source = '${{ env.BRANCH_NAME }}'
target = '${{ env.TARGET_NAME }}'
if target == source:
pass
elif target == '':
target = 'Bundled-' + source
elif '{0}' in target:
target = target.format( source )
print(f'::set-output name=target-branch::{target}')
- name: checkout target branch
id: target_get
uses: actions/checkout@v2
continue-on-error: true
with:
ref: ${{ steps.set-target.outputs.target-branch }}
path: ./target_branch
persist-credentials: false
fetch-depth: 0
# target branch doesn't exist; create it
- name: create target branch
id: target_create
if: ${{ steps.target_get.outcome == 'failure' }}
uses: peterjgrainger/action-create-branch@v2.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
branch: ${{ steps.set-target.outputs.target-branch }}
# NOW checkout the newly-made target branch
- name: checkout created target branch
id: target_get_created
if: ${{ steps.target_create.outcome == 'success' }}
uses: actions/checkout@v2
with:
ref: ${{ steps.set-target.outputs.target-branch }}
path: ./target_branch
persist-credentials: false
fetch-depth: 0
# If this branch needed to be created, assume the user doesn't want to have this workflow trigger in it
# this was way too much work for something so situational/niche... X_X
- name: get workflow path
id: get-workflow-path
if: ${{ steps.target_get_created.outcome == 'success' }}
shell: pwsh
run: |
$Header = @{"Accept" = "application/vnd.github.v3+json"}
$uri = "https://api.github.com/repos/${{ github.repository }}/actions/workflows"
$Workflows = Invoke-RestMethod -Method GET -Header $Header -uri $uri
Foreach ($workflow in $Workflows.workflows)
{
if ( $workflow.path -eq "${{ github.workflow }}" -or $workflow.name -eq "${{ github.workflow }}" )
{
$workflow_path = $workflow.path
echo "::set-output name=workflow-path::$workflow_path"
break
}
}
- name: don't carry workflow
if: ${{ steps.get-workflow-path.outcome == 'success' }}
working-directory: ./target_branch
shell: python
run: |
import os
workflow_file = '${{ steps.get-workflow-path.outputs.workflow-path }}'
new_branch_to_exclude = '${{ steps.set-target.outputs.target-branch }}'
def removeComment(line: str, start = 0):
comment_start = line.find('#', start)
if comment_start == -1:
return line
else:
if line[comment_start - 1] == '\\':
removeComment( line, comment_start + 1 )
else:
return line[:comment_start]
extra_line_separator_characters = len( os.linesep ) - 1 # may mess us up when we manually move the pointer on Windows (which is \r\n , 2 characters)
if os.path.exists( workflow_file ):
with open(workflow_file, mode='r+', encoding='UTF-8') as f:
in_event_trigger_section = False # whether we reached "on:". Never set back to False; we exit the loop instead
in_push_event_trigger = False # whether we reached "push:", and if we're still in it
push_event_trigger_indentation = 0 # the indentation of the "push:" block. Used to check when to set in_push_event_trigger back to False, and in case the push: block ends up being empty, as a backup of indentation_after_push
push_event_trigger_location = 0 # pointer location after the "push:" block. Used in case the push: block ends up being empty
indentation_after_push = 0 # the indentation of the "branches:"/"branches-ignore:" block (or, if we don't see it, the first block inside of "push:" that we see). Used to tell when we left the branches:/branches-ignore: block, and, if that block didn't end up being here, the indentation we'll use to MAKE said block
found_branches = False # which, of branches or branches-ignore, we found
found_branches_ignore = False # which, of branches or branches-ignore, we found
branches_start_location = 0 # pointer location after the "branches:" or "branches-ignore:" block (currently unused)
branches_end_location = None # furthest we got the pointer while in_branches was True. We want to add something right after that
branches_indentation = 0 # by how much the user indented what's IN their branches:/branches-ignore: scope. They all need the same indentation
in_branches = False # whether we reached "branches:" or "branches-ignore:", and if we're still in it
branches_lines = [] # list of lines interpreted as being under the "branches:" or "branches-ignore:" scope
while True:
line = f.readline()
# we're looking for:
#on: (event_trigger_section)
# [...]
# push: (push_event_trigger)
# [...]
# branches:
if line == '':
if in_branches:
branches_end_location = f.tell()
break # end of file
elif in_event_trigger_section:
# remove comments from the line
no_commented_line = removeComment( line )
stripped_line = no_commented_line.lstrip()
current_indentation = len( no_commented_line ) - len( stripped_line )
if stripped_line == '':
if in_branches:
branches_lines.append( line )
continue
if in_push_event_trigger and current_indentation <= push_event_trigger_indentation:
in_push_event_trigger = False # we left that block
if in_branches and current_indentation <= indentation_after_push and (current_indentation < indentation_after_push or not stripped_line.startswith('-')):
in_branches = False
branches_end_location = f.tell() - ( len( line ) + extra_line_separator_characters )
if current_indentation == 0:
break # we left the event trigger section
if stripped_line.startswith('push:') and ( push_event_trigger_indentation == 0 or current_indentation < push_event_trigger_indentation ):
in_push_event_trigger = True
push_event_trigger_indentation = current_indentation
push_event_trigger_location = f.tell()
# also reset all the other variables in case we previously set them in the wrong(???) "push:" block
indentation_after_push = 0
found_branches = False
found_branches_ignore = False
branches_start_location = 0
branches_end_location = None
branches_indentation = 0
in_branches = False
branches_lines = []
elif in_push_event_trigger:
if indentation_after_push == 0:
indentation_after_push = current_indentation # save this for later in case there's no "branches:" tag, and we need to add it ourselves
if in_branches:
if stripped_line.startswith('-') and branches_indentation == 0:
branches_indentation = current_indentation
branches_lines.append( line )
elif stripped_line.startswith('branches:'):
found_branches = True
branches_start_location = f.tell()
in_branches = True
indentation_after_push = current_indentation
elif stripped_line.startswith('branches-ignore:'):
found_branches_ignore = True
branches_start_location = f.tell()
in_branches = True
indentation_after_push = current_indentation
elif line.startswith('on:'):
in_event_trigger_section = True
if push_event_trigger_location > 0: # if it's just not there, don't bother creating it
rest_of_file = """"""
if indentation_after_push == 0: # push: is empty
indentation_after_push = push_event_trigger_indentation * 2
if not found_branches and not found_branches_ignore: # need to create one ourselves
f.seek(push_event_trigger_location)
rest_of_file = f.read()
f.seek(push_event_trigger_location)
most_recently_added_line = ''.rjust( indentation_after_push )
most_recently_added_line += 'branches-ignore:\n'
most_recently_added_line += ''.rjust( indentation_after_push ) + "- '"
else:
# trim any lines at the end that are empty lines / only a comment
for x in range(len( branches_lines ), 0, -1):
branches_line = branches_lines[x-1]
if removeComment( branches_line ).lstrip() != '':
break
branches_lines.pop(x)
branches_end_location -= len( branches_line ) + extra_line_separator_characters
f.seek( branches_end_location )
rest_of_file = f.read()
f.seek( branches_end_location )
if branches_indentation == 0:
branches_indentation = indentation_after_push
most_recently_added_line = ''.rjust( branches_indentation ) + "- '"
if found_branches:
most_recently_added_line += '!'
most_recently_added_line += new_branch_to_exclude + "'\n"
f.write( most_recently_added_line )
f.write( rest_of_file )
# Clean mafia folder in target branch
- name: clean target branch
shell: python
run: |
import os
import shutil
target_base = os.path.join( 'target_branch', '${{ env.TARGET_PATH_TO_MAFIA }}' )
if not os.path.exists( target_base ):
os.makedirs( target_base )
with os.scandir(target_base) as cur_dir:
for dir_entry in cur_dir:
if dir_entry.name != '.git':
path_to_entry = os.path.join(target_base, dir_entry.name)
if dir_entry.is_dir(follow_symlinks=False):
shutil.rmtree(path=path_to_entry)
else:
os.remove(path=path_to_entry)
- name: checkout bundler
uses: actions/checkout@v2
with:
repository: fredg1/ASH-bundler
path: bundler_branch
- name: Forward bundle output to target branch
id: bundle-ASH
shell: python
run: |
import os
import sys
sys.path.append( os.path.join( os.getcwd(), 'bundler_branch' ) )
import Bundle_ASH_script
source_scripts = tuple( map(str, '${{ env.ASH_SCRIPT_SOURCES }}'.split(',') ) )
destinations = tuple( map(str, '${{ env.ASH_SCRIPT_DESTINATIONS }}'.split(',') ) )
if len(source_scripts) != len(destinations):
raise Exception("ASH_SCRIPT_SOURCES and ASH_SCRIPT_DESTINATIONS aren't properly paired")
imported_files = []
bundled_files = []
for i in range( len( source_scripts ) ):
# The script that bundles the target script.
# First argument is the source script.
source_script = source_scripts[i]
# Second argument is the path to reach the file to create/put the result in.
destination = os.path.join( 'target_branch', '${{ env.TARGET_PATH_TO_MAFIA }}', destinations[i] )
# Third argument (optional) is the path to reach the "mafia folder".
path_to_source_script = os.path.join( 'source_branch', '${{ env.SOURCE_PATH_TO_MAFIA }}' )
imports = Bundle_ASH_script.bundle_and_write( source_script, destination, path_to_source_script, allow_overwrite=True, return_imported_files=True )
imported_files.extend( imports )
bundled_files.append( source_script )
print(f'::set-output name=imported_files::{imported_files}')
print(f'::set-output name=bundled_files::{bundled_files}')
# copy any non-ASH file in target_branch
- name: Add non-ash in Source
id: parse-rest
shell: python
run: |
import os
source_base = os.path.join('source_branch', '${{ env.SOURCE_PATH_TO_MAFIA }}')
target_base = os.path.join('target_branch', '${{ env.TARGET_PATH_TO_MAFIA }}')
imported_files = ${{ steps.bundle-ASH.outputs.imported_files }}
bundled_files = ${{ steps.bundle-ASH.outputs.bundled_files }}
used_ASH_files = []
for file in (imported_files + bundled_files):
used_ASH_files.append( os.path.normcase( os.path.normpath( file ) ) )
unused_ASH_files = []
def parse_folder(cur_dir, current_path = ''):
for dir_entry in cur_dir:
if dir_entry.is_symlink():
continue
if dir_entry.is_dir():
next_path = os.path.join(current_path, dir_entry.name)
with os.scandir( os.path.join(source_base, next_path) ) as next_dir:
parse_folder(next_dir, next_path)
elif dir_entry.is_file():
this_path = os.path.join(current_path, dir_entry.name)
if this_path.endswith('.ash'):
if used_ASH_files.count( os.path.normcase( os.path.normpath( this_path ) ) ) == 0:
unused_ASH_files.append( this_path )
else:
print('Grabbing ' + this_path + ' ...')
this_path_source = os.path.join(source_base, this_path)
this_path_target = os.path.join(target_base, this_path)
if os.path.exists( this_path_target ):
os.remove( this_path_target )
os.renames(this_path_source, this_path_target)
with os.scandir(source_base) as source_dir:
parse_folder(cur_dir = source_dir)
if len( unused_ASH_files ) > 0:
print()
with open('artifact.txt', mode='x', encoding='UTF-8') as f:
message = str( len( unused_ASH_files ) ) + ' unused ASH file(s) (not imported by any of the scripts) found:'
print( message )
f.write( message + '\n' )
for unused_file in unused_ASH_files:
message = ' ' + unused_file
print( message )
f.write( message + '\n' )
- name: upload unused files message as artifact
uses: actions/upload-artifact@v2
with:
name: unused files found
path: ./artifact.txt
if-no-files-found: ignore
- name: commit changes to target
working-directory: ./target_branch
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add --all -v *
git commit -m "Import changes from ${{ github.ref }}" -a
git push "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" HEAD:refs/heads/${{ steps.set-target.outputs.target-branch }} --follow-tags --tags