Skip to content

Commit

Permalink
Merge pull request #715 from heroku/python312-compat
Browse files Browse the repository at this point in the history
Python 3.12 compatibility for build tooling
  • Loading branch information
dzuelke committed May 23, 2024
2 parents 3ae0558 + c976c7f commit 6b58b7f
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 51 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ jobs:
with:
php-version: "8.2"
tools: "composer:2.7"
- name: Install packages from requirements.txt (for some tests)
run: pip install -r requirements.txt
- name: Hatchet setup
run: bundle exec hatchet ci:setup
- name: Export HEROKU_PHP_PLATFORM_REPOSITORIES to …-develop (since we are not building main or a tag)
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
bob-builder>=0.0.15
bob-builder>=0.0.20
s3cmd>=1.6.0
natsort
8 changes: 4 additions & 4 deletions support/build/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ The following environment variables are highly recommended (see section *Underst

The following environment variables are optional, but strongly recommended:

- `S3_REGION`, to be set to the AWS region name (e.g. "`s3.eu-west-1`"), otherwise it will default to "`s3`", which is deprecated by AWS and may cause rate limit problems when resolving the bucket region from this global endpoint.
- `S3_REGION`, to be set to the AWS region name (e.g. "`eu-west-1`"), otherwise it will default to an empty value and resolve to just "`s3`" in the domain name, which is deprecated by AWS and may cause rate limit problems when resolving the bucket region from this global endpoint.

#### Understanding Prefixes

Expand Down Expand Up @@ -626,7 +626,7 @@ First, create, in a secure location on your file system, a `heroku-php-s3.docker
AWS_SECRET_ACCESS_KEY=<yourkey>
S3_BUCKET=<yourbucketname>
S3_PREFIX=dist-develop/ # overriding the Dockerfile default here, which contains the stack
S3_REGION=… # bucket region, e.g. "s3.eu-west-1"
S3_REGION=… # bucket region, e.g. "eu-west-1"

Have your Git fork ready:

Expand Down Expand Up @@ -700,7 +700,7 @@ First, create, in a secure location on your file system, a `heroku-php-s3.docker
AWS_SECRET_ACCESS_KEY=<yourkey>
S3_BUCKET=<yourbucketname>
S3_PREFIX=dist-stable/ # overriding the Dockerfile default here, which contains the stack
S3_REGION=… # bucket region, e.g. "s3.us-east-1"
S3_REGION=… # bucket region, e.g. "us-east-1"

Pull in the buildpack as a Composer dependency:

Expand Down Expand Up @@ -834,5 +834,5 @@ The extension is then ready for use in applications by requiring it in `composer

## Tips & Tricks

- All manifests generated by Bob formulas, by `mkrepo.sh` and by `sync.sh` use an S3 region from environment variable `$S3_REGION` and fall back to "`s3`", which is deprecated by AWS and may cause rate limit problems when resolving the bucket region from this global endpoint. Resulting URLs look like e.g. "`https://<your-bucket-name>.s3.us-east-1.amazonaws.com/your-prefix/...`".
- All manifests generated by Bob formulas, by `mkrepo.sh` and by `sync.sh` use an S3 region from environment variable `$S3_REGION` and fall back to using only "`s3`" in the URL, which is deprecated by AWS and may cause rate limit problems when resolving the bucket region from this global endpoint. Resulting URLs look like e.g. "`https://<your-bucket-name>.s3.us-east-1.amazonaws.com/your-prefix/...`".
- If any dependencies are not yet deployed, you need to deploy them first, or use `UPSTREAM_S3_BUCKET` and `UPSTREAM_S3_PREFIX` (recommended).
12 changes: 8 additions & 4 deletions support/build/_docker/heroku-20.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ FROM heroku/heroku:20-build.v84

WORKDIR /app
ENV WORKSPACE_DIR=/app/support/build
ENV PATH=/app/support/build/_util:$PATH
ENV S3_BUCKET=lang-php
ENV S3_PREFIX=dist-heroku-20-develop/
ENV S3_REGION=s3.us-east-1
ENV S3_REGION=us-east-1
ENV STACK=heroku-20
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y python3-pip
RUN apt-get update && apt-get install -y python3-pip python3-venv

ENV VIRTUAL_ENV=/app/.venv
RUN python3 -m venv "$VIRTUAL_ENV"

ENV PATH="/app/support/build/_util:$VIRTUAL_ENV/bin:$PATH"

COPY requirements.txt /app/requirements.txt

RUN pip3 install -r /app/requirements.txt
RUN pip install -r /app/requirements.txt

COPY . /app
12 changes: 8 additions & 4 deletions support/build/_docker/heroku-22.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ FROM heroku/heroku:22-build.v84

WORKDIR /app
ENV WORKSPACE_DIR=/app/support/build
ENV PATH=/app/support/build/_util:$PATH
ENV S3_BUCKET=lang-php
ENV S3_PREFIX=dist-heroku-22-develop/
ENV S3_REGION=s3.us-east-1
ENV S3_REGION=us-east-1
ENV STACK=heroku-22
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y python3-pip
RUN apt-get update && apt-get install -y python3-pip python3-venv

ENV VIRTUAL_ENV=/app/.venv
RUN python3 -m venv "$VIRTUAL_ENV"

ENV PATH="/app/support/build/_util:$VIRTUAL_ENV/bin:$PATH"

COPY requirements.txt /app/requirements.txt

RUN pip3 install -r /app/requirements.txt
RUN pip install -r /app/requirements.txt

COPY . /app
11 changes: 6 additions & 5 deletions support/build/_util/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ shift $((OPTIND-1))

if [[ $# -lt 1 ]]; then
cat >&2 <<-EOF
Usage: $(basename $0) [--publish] FORMULA-VERSION [--overwrite]
Usage: $(basename "$0") [--publish] FORMULA-VERSION [--overwrite]
If --publish is given, mkrepo.sh will be invoked after a successful deploy to
re-generate the repo. CAUTION: this will cause all manifests in the bucket to
be included in the repo, including potentially currently unpublished ones.
Expand All @@ -44,8 +44,9 @@ if [[ -z "${AWS_ACCESS_KEY_ID:-}" || -z "${AWS_SECRET_ACCESS_KEY:-}" ]]; then
fi

# a helper (print_or_export_manifest_cmd) called in the script invoked by Bob will write to this if set
export MANIFEST_CMD=$(mktemp -t "manifest.XXXXX")
trap 'rm -rf $MANIFEST_CMD;' EXIT
MANIFEST_CMD=$(mktemp -t "manifest.XXXXX")
export MANIFEST_CMD
trap 'rm -rf "$MANIFEST_CMD";' EXIT

# make sure we start cleanly
rm -rf /app/.heroku/php
Expand All @@ -69,9 +70,9 @@ bob deploy "${args[@]}"
# invoke manifest upload
echo ""
echo "Uploading manifest..."
. $MANIFEST_CMD
. "$MANIFEST_CMD"

if $publish; then
echo "Updating repository..."
$(dirname $BASH_SOURCE)/mkrepo.sh --upload "$S3_BUCKET" "${S3_PREFIX}"
"$(dirname "$BASH_SOURCE")/mkrepo.sh" --upload "$S3_BUCKET" "${S3_PREFIX}"
fi
12 changes: 9 additions & 3 deletions support/build/_util/include/manifest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os, sys, json, re, datetime

require = json.loads(sys.argv[5]) if len(sys.argv) > 5 else {}
stack=re.match("^([^-]+)(?:-([0-9]+))?$", os.getenv("STACK", "heroku-22"))
stack=re.match(r"^([^-]+)(?:-([0-9]+))?$", os.getenv("STACK", "heroku-22"))
require["heroku-sys/"+stack.group(1)] = "^{}.0.0".format(stack.group(2) or "1")

require["heroku/installer-plugin"] = "^1.2.0"
Expand All @@ -14,20 +14,26 @@
elif sys.argv[1] == 'heroku-sys-program':
require["heroku/installer-plugin"] = "^1.4.0"

s3_region_string = os.getenv("S3_REGION")
if s3_region_string == None:
s3_region_string = "s3"
else:
s3_region_string = "s3.{}".format(s3_region_string)

manifest = {
"type": sys.argv[1],
"name": sys.argv[2],
"version": sys.argv[3],
"dist": {
"type": "heroku-sys-tar",
"url": "https://"+os.getenv("S3_BUCKET")+"."+os.getenv("S3_REGION", "s3")+".amazonaws.com/"+os.getenv("S3_PREFIX")+sys.argv[4]
"url": "https://"+os.getenv("S3_BUCKET")+"."+s3_region_string+".amazonaws.com/"+os.getenv("S3_PREFIX")+sys.argv[4]
},
"require": require,
"conflict": json.loads(sys.argv[6]) if len(sys.argv) > 6 else {},
"replace": json.loads(sys.argv[7]) if len(sys.argv) > 7 else {},
"provide": json.loads(sys.argv[8]) if len(sys.argv) > 8 else {},
"extra": json.loads(sys.argv[9]) if len(sys.argv) > 9 else {},
"time": os.getenv("NOW", datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))
"time": os.getenv("NOW", datetime.datetime.now(tz=datetime.timezone.utc).strftime("%Y-%m-%d %H:%M:%S"))
}

# if it's a PHP manifest, we will generate full manifests for each shared extension into extra.shared; mkrepo.sh will then expand those into actual package declarations when it generates the repo
Expand Down
14 changes: 7 additions & 7 deletions support/build/_util/include/manifest.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#!/bin/bash
#!/usr/bin/env bash

print_or_export_manifest_cmd() {
if [[ "${MANIFEST_CMD:-}" ]]; then
echo "$1" > $MANIFEST_CMD
echo "$1" > "$MANIFEST_CMD"
else
echo "-----> Done. Run '$1' to upload manifest."
echo "-----> Done. To upload manifest, run: $1"
fi
}

generate_manifest_cmd() {
echo "s3cmd --host=${S3_REGION:-s3}.amazonaws.com --host-bucket='%(bucket)s.${S3_REGION:-s3}.amazonaws.com' --ssl -m application/json put $(pwd)/${1} s3://${S3_BUCKET}/${S3_PREFIX}${1}"
echo "s3cmd --host=s3.${S3_REGION:-}${S3_REGION:+.}amazonaws.com --host-bucket='%(bucket)s.s3.${S3_REGION:-}${S3_REGION:+.}amazonaws.com' --ssl -m application/json put $(pwd)/${1} s3://${S3_BUCKET}/${S3_PREFIX}${1}"
}

soname_version() {
soname=$(objdump -p $1 | grep SONAME | awk '{ printf $2; }')
file=$(basename $1)
soname=$(objdump -p "$1" | grep SONAME | awk '{ printf $2; }')
file=$(basename "$1")
echo "${soname#${file}.}"
}
}
14 changes: 6 additions & 8 deletions support/build/_util/mkrepo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ if [[ $# == "1" ]]; then
S3_PREFIX: S3 prefix, e.g. '' or 'dist-stable/'; default: '\$S3_PREFIX'.
The environment variable '\$S3_REGION' is used to determine the bucket region;
it defaults to 's3' if not present. Use e.g. 's3.us-east-1' to set a region.
it defaults to 's3' if not present. Use e.g. 'us-east-1' to set a region.
If MANIFEST arguments are given, those are used to build the repo; otherwise,
all manifests from given or default S3_BUCKET+S3_PREFIX are downloaded.
Expand All @@ -66,15 +66,13 @@ if [[ $# != "0" ]]; then
S3_PREFIX=$1; shift
fi

S3_REGION=${S3_REGION:-s3}

if [[ $# == "0" ]]; then
manifests_tmp=$(mktemp -d -t "dst-repo.XXXXX")
trap 'rm -rf $manifests_tmp;' EXIT
echo -n "-----> Fetching manifests... " >&2
(
cd $manifests_tmp
s3cmd --host="${S3_REGION}.amazonaws.com" --host-bucket="%(bucket)s.${S3_REGION}.amazonaws.com" --ssl --progress get s3://${S3_BUCKET}/${S3_PREFIX}*.composer.json 2>&1 | tee download.log | s3cmd_get_progress >&2 || { echo -e "failed! Error:\n$(cat download.log)" >&2; exit 1; }
s3cmd --host="s3.${S3_REGION:-}${S3_REGION:+.}amazonaws.com" --host-bucket="%(bucket)s.s3.${S3_REGION:-}${S3_REGION:+.}amazonaws.com" --ssl --progress get s3://${S3_BUCKET}/${S3_PREFIX}*.composer.json 2>&1 | tee download.log | s3cmd_get_progress >&2 || { echo -e "failed! Error:\n$(cat download.log)" >&2; exit 1; }
rm download.log
)
echo "" >&2
Expand All @@ -99,7 +97,7 @@ fi
python <(cat <<-'PYTHON' # beware of single quotes in body
import sys, re, json
import itertools
from distutils import version
from natsort import natsorted
manifests = [ json.load(open(item)) for item in sys.argv[1:] if json.load(open(item)).get("type", "") != "heroku-sys-package" ]
# for PHP, transform all manifests in extra.shared into their own packages
for php in filter(lambda package: package.get("type", "") == "heroku-sys-php", manifests):
Expand All @@ -126,8 +124,8 @@ python <(cat <<-'PYTHON' # beware of single quotes in body
if pkg.get("type") == "heroku-sys-php-extension":
replaces["%s.native"%pkg.get("name", "")] = "self.version"
# we sort by a tuple: name first (so the following dictionary grouping works), then "php" requirement (see initial comment block)
manifests.sort(
key=lambda package: (package.get("name"), version.LooseVersion(re.sub("[<>=*~^]", "0", package.get("require", {}).get("heroku-sys/php", "0.0.0")))),
manifests = natsorted(manifests,
key=lambda package: (package.get("name"), re.sub(r"[<>=*~^]", "0", package.get("require", {}).get("heroku-sys/php", "0.0.0"))),
reverse=True)
# convert the list to a dict with package names as keys and list of versions (sorted by "php" requirement by previous sort) as values
json.dump({"packages": dict((name, list(versions)) for name, versions in itertools.groupby(manifests, key=lambda package: package.get("name"))) }, sys.stdout, sort_keys=True)
Expand All @@ -140,7 +138,7 @@ if $redir; then
exec 1>&3 3>&-
fi

cmd="s3cmd --host=${S3_REGION}.amazonaws.com --host-bucket='%(bucket)s.${S3_REGION}.amazonaws.com' --ssl -m application/json put packages.json s3://${S3_BUCKET}/${S3_PREFIX}packages.json"
cmd="s3cmd --host=s3.${S3_REGION:-}${S3_REGION:+.}amazonaws.com --host-bucket='%(bucket)s.s3.${S3_REGION:-}${S3_REGION:+.}amazonaws.com' --ssl -m application/json put packages.json s3://${S3_BUCKET}/${S3_PREFIX}packages.json"
if $upload; then
echo "-----> Uploading packages.json..." >&2
eval "$cmd 1>&2"
Expand Down
13 changes: 7 additions & 6 deletions support/build/_util/remove.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ if [[ $# -lt "1" ]]; then
$(basename $0) php-8.1.{8..16} ext-{redis-4,newrelic-9}.*_php-7.*
Bucket name and prefix will be read from '\$S3_BUCKET' and '\$S3_PREFIX'.
Bucket region (e.g. 's3.us-east-1') will be read from '\$S3_REGION'.
Bucket region (e.g. 'us-east-1') will be read from '\$S3_REGION'.
EOF
exit 2
fi

S3_PREFIX=${S3_PREFIX:-}
S3_REGION=${S3_REGION:-s3}
S3_REGION=${S3_REGION:-}
S3_REGION_PART=s3${S3_REGION:+.}${S3_REGION:-}

here=$(cd $(dirname $0); pwd)

Expand All @@ -79,7 +80,7 @@ trap 'rm -rf $manifests_tmp;' EXIT
echo -n "-----> Fetching manifests... " >&2
(
cd $manifests_tmp
s3cmd --host=${S3_REGION}.amazonaws.com --host-bucket="%(bucket)s.${S3_REGION}.amazonaws.com" --ssl --progress get "${manifests[@]}" 2>&1 | tee download.log | s3cmd_get_progress >&2 || { echo -e "failed! Error:\n$(cat download.log)" >&2; exit 1; }
s3cmd --host=${S3_REGION_PART}.amazonaws.com --host-bucket="%(bucket)s.${S3_REGION_PART}.amazonaws.com" --ssl --progress get "${manifests[@]}" 2>&1 | tee download.log | s3cmd_get_progress >&2 || { echo -e "failed! Error:\n$(cat download.log)" >&2; exit 1; }
rm download.log
)
echo "" >&2
Expand Down Expand Up @@ -139,7 +140,7 @@ for manifest in "$manifests_tmp/"*".composer.json"; do
print(url)
sys.exit(1)
PYTHON
) $S3_BUCKET ${S3_REGION} ${S3_PREFIX})
) $S3_BUCKET ${S3_REGION_PART} ${S3_PREFIX})
then
echo " - queued '$filename' for removal." >&2
remove_files+=("$filename")
Expand All @@ -148,7 +149,7 @@ for manifest in "$manifests_tmp/"*".composer.json"; do
echo " - WARNING: not removing '$filename' (in manifest 'dist.url')!" >&2
fi
echo -n " - removing manifest file '$(basename "$manifest")'... " >&2
out=$(s3cmd --host=${S3_REGION}.amazonaws.com --host-bucket="%(bucket)s.${S3_REGION}.amazonaws.com" --ssl rm "s3://${S3_BUCKET}/${S3_PREFIX}$(basename "$manifest")" 2>&1) || { echo -e "failed! Error:\n$out" >&2; exit 1; }
out=$(s3cmd --host=${S3_REGION_PART}.amazonaws.com --host-bucket="%(bucket)s.${S3_REGION_PART}.amazonaws.com" --ssl rm "s3://${S3_BUCKET}/${S3_PREFIX}$(basename "$manifest")" 2>&1) || { echo -e "failed! Error:\n$out" >&2; exit 1; }
rm $manifest
echo "done." >&2
done
Expand All @@ -169,7 +170,7 @@ if [[ "${#remove_files[@]}" != "0" ]]; then
echo "Removing files queued for deletion from bucket:" >&2
for filename in "${remove_files[@]}"; do
echo -n " - removing '$filename'... " >&2
out=$(s3cmd --host=${S3_REGION}.amazonaws.com --host-bucket="%(bucket)s.${S3_REGION}.amazonaws.com" --ssl rm s3://${S3_BUCKET}/${S3_PREFIX}${filename} 2>&1) && echo "done." >&2 || echo -e "failed! Error:\n$out" >&2
out=$(s3cmd --host=${S3_REGION_PART}.amazonaws.com --host-bucket="%(bucket)s.${S3_REGION_PART}.amazonaws.com" --ssl rm s3://${S3_BUCKET}/${S3_PREFIX}${filename} 2>&1) && echo "done." >&2 || echo -e "failed! Error:\n$out" >&2
done
echo "" >&2
fi
Expand Down
20 changes: 12 additions & 8 deletions support/build/_util/sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if [[ $# -lt "2" || $# -gt "6" ]]; then
cat >&2 <<-EOF
Usage: $(basename $0) [--no-remove] DEST_BUCKET DEST_PREFIX [DEST_REGION [SOURCE_BUCKET SOURCE_PREFIX [SOURCE_REGION]]]
DEST_BUCKET: destination S3 bucket name.
DEST_REGION: destination bucket region, e.g. 's3.us-west-1'; default: '$\S3_REGION' or 's3'.
DEST_REGION: destination bucket region, e.g. 'us-west-1'; default: '$\S3_REGION'.
DEST_PREFIX: destination prefix, e.g. '' or 'dist-stable/'.
SOURCE_BUCKET: source S3 bucket name; default: '\$S3_BUCKET'.
SOURCE_REGION: source bucket region; default: <DEST_REGION>.
Expand All @@ -56,21 +56,25 @@ dst_prefix=$1; shift
if [[ $# -gt 2 ]]; then
# region name given
dst_region=$1; shift
dst_region_part=s3.${dst_region}
else
dst_region=${S3_REGION:-"s3"}
dst_region=${S3_REGION:-}
dst_region_part=s3${dst_region:+.}${dst_region:-}
fi

src_bucket=${1:-$S3_BUCKET}; shift || true
src_prefix=${1:-$S3_PREFIX}; shift || true
if [[ $# == "1" ]]; then
# region name given
src_region=$1; shift
src_region_part=s3.${src_region}; shift
else
src_region=$dst_region
src_region_part=s3${src_region:+.}${src_region:-}
fi

s3cmd_src_host_options="--host=${src_region}.amazonaws.com --host-bucket=%(bucket)s.${src_region}.amazonaws.com"
s3cmd_dst_host_options="--host=${dst_region}.amazonaws.com --host-bucket=%(bucket)s.${dst_region}.amazonaws.com"
s3cmd_src_host_options="--host=${src_region_part}.amazonaws.com --host-bucket=%(bucket)s.${src_region_part}.amazonaws.com"
s3cmd_dst_host_options="--host=${dst_region_part}.amazonaws.com --host-bucket=%(bucket)s.${dst_region_part}.amazonaws.com"

if [[ "$src_region" != "$dst_region" ]]; then
echo "CAUTION: Source and destination regions differ. Sync may run into rate limits." >&2
Expand Down Expand Up @@ -141,12 +145,12 @@ for filename in $common; do
try:
src_time = datetime.datetime.strptime(src_manifest.pop("time"), "%Y-%m-%d %H:%M:%S") # UTC
except (KeyError, ValueError):
src_time = datetime.datetime.utcfromtimestamp(os.path.getmtime(sys.argv[1]))
src_time = datetime.datetime.fromtimestamp(os.path.getmtime(sys.argv[1]), tz=datetime.timezone.utc)
stderrprint("WARNING: source manifest {} has invalid time entry, using mtime: {}".format(os.path.basename(sys.argv[1]), src_time.isoformat()))
try:
dst_time = datetime.datetime.strptime(dst_manifest.pop("time"), "%Y-%m-%d %H:%M:%S") # UTC
except (KeyError, ValueError):
dst_time = datetime.datetime.utcfromtimestamp(os.path.getmtime(sys.argv[2]))
dst_time = datetime.datetime.fromtimestamp(os.path.getmtime(sys.argv[2]), tz=datetime.timezone.utc)
stderrprint("WARNING: destination manifest {} has invalid time entry, using mtime: {}".format(os.path.basename(sys.argv[2]), dst_time.isoformat()))
# a newer source time means we will copy
if src_time > dst_time:
Expand Down Expand Up @@ -240,7 +244,7 @@ for manifest in $add_manifests ${update_manifests[@]:-}; do
print(url)
sys.exit(1)
PYTHON
) $src_bucket $src_region $src_prefix $dst_bucket $dst_region $dst_prefix ${dst_tmp}/${manifest})
) $src_bucket $src_region_part $src_prefix $dst_bucket $dst_region_part $dst_prefix ${dst_tmp}/${manifest})
then
# the dist URL in the source's manifest points to the source bucket, so we copy the file to the dest bucket
echo -n " - copying '$filename'... " >&2
Expand Down Expand Up @@ -279,7 +283,7 @@ for manifest in $remove_manifests; do
print(url)
sys.exit(1)
PYTHON
) $dst_bucket $dst_region $dst_prefix)
) $dst_bucket $dst_region_part $dst_prefix)
then
# the dist URL in the destination manifest points to the destination bucket, so we remove that file at the end of the script...
if [[ " ${copied_files[@]:-} " =~ " $filename " ]]; then
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
NOW="2022-01-26 20:49:45" STACK=heroku-20 S3_BUCKET=lang-php S3_PREFIX=dist-heroku-20-develop/ S3_REGION=s3.us-east-1
NOW="2022-01-26 20:49:45" STACK=heroku-20 S3_BUCKET=lang-php S3_PREFIX=dist-heroku-20-develop/ S3_REGION=us-east-1

0 comments on commit 6b58b7f

Please sign in to comment.