Skip to content

Commit

Permalink
ci: Modernize zipball script
Browse files Browse the repository at this point in the history
The old one was just running `git clean -f` in the repo, which is quite a footgun.
Let’s just use the latest version of the script I wrote for selfoss,
which obtains a clean working tree by cloning the repo to a temporary location.
  • Loading branch information
jtojnar committed Oct 1, 2021
1 parent d35d7b7 commit 9530d60
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 19 deletions.
127 changes: 127 additions & 0 deletions .github/workflows/create-zipball.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
import json
import logging
import os
import re
import subprocess
import sys
import tempfile
import zipfile
from pathlib import Path

logger = logging.getLogger('create-zipfile')

DISALLOWED_FILENAME_PATTERNS = list(map(re.compile, [
r'^\.git(hub|ignore|attributes|keep)$',
r'^\.(appveyor|travis)\.yml$',
r'^\.editorconfig$',
r'(?i)^changelog',
r'(?i)^contributing',
r'(?i)^upgrading',
r'(?i)^copying',
r'(?i)^index',
r'(?i)^readme',
r'(?i)^licen[cs]e',
r'(?i)^version',
r'^phpunit',
r'^l?gpl\.txt$',
r'^composer\.(json|lock)$',
r'^package(-lock)?\.json$',
r'^yarn\.lock$',
r'^Makefile$',
r'^build\.xml$',
r'^phpcs-ruleset\.xml$',
r'^\.php_cs$',
r'^phpmd\.xml$',
]))

DISALLOWED_DEST_PATTERNS = list(map(re.compile, [
r'^vendor/composer/installed\.json$',
r'^vendor/moneyphp/money/resources/logo.png$',
r'(?i)^vendor/[^/]+/[^/]+/\.?(test|doc|example|spec)s?',
r'^vendor/[^/]+/[^/]+/\.git((hub)?/|$)',
]))

def is_not_unimportant(dest: Path) -> bool:
filename = dest.name

filename_disallowed = any([expr.match(filename) for expr in DISALLOWED_FILENAME_PATTERNS])

dest_disallowed = any([expr.match(str(dest)) for expr in DISALLOWED_DEST_PATTERNS])

allowed = not (filename_disallowed or dest_disallowed)

return allowed

class ZipFile(zipfile.ZipFile):
def directory(self, name, allowed=None):
if allowed is None:
allowed = lambda item: True

for root, dirs, files in os.walk(name):
root = Path(root)

for directory in dirs:
directory = Path(directory)
path = root / directory

if allowed(path):
# Directories are empty files whose path ends with a slash.
# https://mail.python.org/pipermail/python-list/2003-June/205859.html
self.writestr(str(self.prefix / path) + '/', '')

for file in files:
path = root / file

if allowed(path):
self.write(path, self.prefix / path)
def file(self, name):
self.write(name, self.prefix / name)

def main():
source_dir = Path.cwd()
with tempfile.TemporaryDirectory(prefix='entries-dist-') as temp_dir:
dirty = subprocess.run(['git','-C', source_dir, 'diff-index', '--quiet', 'HEAD']).returncode == 1
if dirty:
logger.warning('Repository contains uncommitted changes that will not be included in the dist archive.')

logger.info('Cloning the repository into a temporary directory…')
subprocess.check_call(['git', 'clone', '--shared', source_dir, temp_dir])

os.chdir(temp_dir)

if len(sys.argv) >= 2:
filename = sys.argv[1]
else:
short_commit = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], encoding='utf-8').strip()
filename = f'entries-{short_commit}.zip'

logger.info('Installing frontend dependencies…')
subprocess.check_call(['yarn', 'install'])

logger.info('Building asset bundles…')
subprocess.check_call(['yarn', 'run', 'build'])

logger.info('Installing and optimizing backend dependencies…')
subprocess.check_call(['composer', 'install', '--no-dev', '--optimize-autoloader'])

# fill archive with data
with ZipFile(source_dir / filename, 'w', zipfile.ZIP_DEFLATED) as archive:
archive.prefix = Path('entries')

# Assets are copied by Webpack to www/dist/.
archive.directory('www/', lambda file: not file.match('www/assets'))

archive.directory('app/')
archive.directory('log/')
archive.directory('temp/')
archive.directory('vendor/', is_not_unimportant)

archive.file('.htaccess')
archive.file('install.sql')
archive.file('README.md')

logger.info('Zipball ‘{}’ has been successfully generated.'.format(filename))

if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
nix-shell --run 'composer test'
- name: Build a zipball
run: nix-shell --run '.github/workflows/package.sh "entries-${{ steps.vars.outputs.sha_short }}.zip"'
run: nix-shell --run '.github/workflows/create-zipball.py "entries-${{ steps.vars.outputs.sha_short }}.zip"'

- name: Upload the zipball to GitHub
uses: actions/upload-artifact@v2
Expand Down
18 changes: 0 additions & 18 deletions .github/workflows/package.sh

This file was deleted.

1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
pkgs.mkShell {
nativeBuildInputs = [
php
pkgs.python3 # for create-zipball.py
nette-code-checker
update-php-extradeps
] ++ (with pkgs.nodePackages; [
Expand Down

0 comments on commit 9530d60

Please sign in to comment.