-
Notifications
You must be signed in to change notification settings - Fork 17
424 lines (346 loc) · 19.7 KB
/
main.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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@v4
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