mirror of
https://github.com/haskell/haskell-language-server.git
synced 2024-09-11 08:45:35 +03:00
Add release scripts
This commit is contained in:
parent
5ce21d0a77
commit
9114c11907
7
release/README.md
Normal file
7
release/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Making and uploading the Gitlab release to downloads.haskell.org
|
||||
|
||||
1. Run the gitlab release pipeline using https://gitlab.haskell.org/haskell/haskell-language-server/-/pipelines/new
|
||||
2. Once the pipeline has completed, download the artifacts using `fetch_gitlab.py`
|
||||
- For example for the `1.7.0.0` release: `python fetch_gitlab.py -p <pipeline_id> --output haskell-language-server-1.7.0.0 -r 1.7.0.0`
|
||||
- Ensure all the artifacts in the output directory are accurate and add any missing/extra artifacts
|
||||
3. `cd` to the output directory created in the previous step, and run `SIGNING_KEY=<your signing key> ../upload.sh`
|
76
release/fetch_gitlab.py
Normal file
76
release/fetch_gitlab.py
Normal file
@ -0,0 +1,76 @@
|
||||
# adapted from https://gitlab.haskell.org/bgamari/ghc-utils/-/blob/master/rel-eng/fetch-gitlab-artifacts/fetch_gitlab.py
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import gitlab
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
def strip_prefix(s, prefix):
|
||||
if s.startswith(prefix):
|
||||
return s[len(prefix):]
|
||||
else:
|
||||
return None
|
||||
|
||||
def fetch_artifacts(release: str, pipeline_id: int,
|
||||
dest_dir: Path, gl: gitlab.Gitlab):
|
||||
dest_dir.mkdir(exist_ok=True)
|
||||
proj = gl.projects.get('haskell/haskell-language-server')
|
||||
pipeline = proj.pipelines.get(pipeline_id)
|
||||
tmpdir = Path("fetch-gitlab")
|
||||
tmpdir.mkdir(exist_ok=True)
|
||||
for pipeline_job in pipeline.jobs.list(all=True):
|
||||
if len(pipeline_job.artifacts) == 0:
|
||||
logging.info(f'job {pipeline_job.name} ({pipeline_job.id}) has no artifacts')
|
||||
continue
|
||||
|
||||
job = proj.jobs.get(pipeline_job.id)
|
||||
platform = strip_prefix(job.name, 'tar-')
|
||||
if not platform:
|
||||
logging.info(f'Skipping {job.name} (not a tar job)')
|
||||
continue
|
||||
try:
|
||||
destdir = tmpdir / job.name
|
||||
zip_name = Path(f"{tmpdir}/{job.name}.zip")
|
||||
if not zip_name.exists() or zip_name.stat().st_size == 0:
|
||||
logging.info(f'downloading archive {zip_name} for job {job.name} (job {job.id})...')
|
||||
with open(zip_name, 'wb') as f:
|
||||
job.artifacts(streamed=True, action=f.write)
|
||||
|
||||
if zip_name.stat().st_size == 0:
|
||||
logging.info(f'artifact archive for job {job.name} (job {job.id}) is empty')
|
||||
continue
|
||||
|
||||
dest = dest_dir / f'haskell-language-server-{release}-{platform}.tar.xz'
|
||||
if dest.exists():
|
||||
logging.info(f'bindist {dest} already exists')
|
||||
continue
|
||||
|
||||
subprocess.run(['unzip', '-bo', zip_name, '-d', destdir])
|
||||
bindist_files = list(destdir.glob('*/haskell-language-server*.tar.xz'))
|
||||
if len(bindist_files) == 0:
|
||||
logging.warn(f'Bindist does not exist')
|
||||
continue
|
||||
|
||||
bindist = bindist_files[0]
|
||||
logging.info(f'extracted {job.name} to {dest}')
|
||||
bindist.replace(dest)
|
||||
except Exception as e:
|
||||
logging.error(f'Error fetching job {job.name}: {e}')
|
||||
pass
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--pipeline', '-p', required=True, type=int, help="pipeline id")
|
||||
parser.add_argument('--release', '-r', required=True, type=str, help="release name")
|
||||
parser.add_argument('--output', '-o', type=Path, default=Path.cwd(), help="output directory")
|
||||
parser.add_argument('--profile', '-P', default='haskell',
|
||||
help='python-gitlab.cfg profile name')
|
||||
args = parser.parse_args()
|
||||
gl = gitlab.Gitlab.from_config(args.profile)
|
||||
fetch_artifacts(args.release, args.pipeline,
|
||||
dest_dir=args.output, gl=gl)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
154
release/upload.sh
Executable file
154
release/upload.sh
Executable file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
# This is a script for preparing and uploading a release of Haskell Language Server.
|
||||
# Adapted from https://gitlab.haskell.org/bgamari/ghc-utils/-/commits/master/rel-eng/upload.sh
|
||||
#
|
||||
# Usage,
|
||||
# 1. Set $SIGNING_KEY to your key id (prefixed with '=')
|
||||
# 2. Create a directory called haskell-langauge-server-<release_number> and place the binary tarballs there
|
||||
# 4. Run this script from that directory
|
||||
#
|
||||
# You can also invoke the script with an argument to perform only
|
||||
# a subset of the usual release,
|
||||
#
|
||||
# upload.sh gen_hashes generate signed hashes of the release
|
||||
# tarballs
|
||||
# upload.sh sign generate signed hashes of the release
|
||||
# tarballs
|
||||
# upload.sh upload upload the tarballs and documentation
|
||||
# to downloads.haskell.org
|
||||
#
|
||||
# Prerequisites: moreutils
|
||||
|
||||
# Infer release name from directory name
|
||||
if [ -z "$rel_name" ]; then
|
||||
rel_name="$(basename $(pwd))"
|
||||
fi
|
||||
|
||||
# Infer version from tarball names
|
||||
if [ -z "$ver" ]; then
|
||||
ver="$(ls haskell-language-server-*.tar.* | sed -ne 's/haskell-language-server-\([0-9]\+\.[0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\).\+/\1/p' | head -n1)"
|
||||
if [ -z "$ver" ]; then echo "Failed to infer \$ver"; exit 1; fi
|
||||
fi
|
||||
|
||||
echo HLS version $ver
|
||||
|
||||
host="webhost.haskell.org"
|
||||
|
||||
usage() {
|
||||
echo "Usage: [rel_name=<name>] SIGNING_KEY=<key> $0 <action>"
|
||||
echo
|
||||
echo "where,"
|
||||
echo " rel_name gives the release name (e.g. 1.7.0.0)"
|
||||
echo "and <action> is one of,"
|
||||
echo " [nothing] do everything below"
|
||||
echo " gen_hashes generated hashes of the release tarballs"
|
||||
echo " sign sign hashes of the release tarballs"
|
||||
echo " upload upload the tarballs and documentation to downloads.haskell.org"
|
||||
echo " purge_all purge entire release from the CDN"
|
||||
echo " purge_file file purge a given file from the CDN"
|
||||
echo " verify verify the signatures in this directory"
|
||||
echo
|
||||
}
|
||||
|
||||
if [ -z "$ver" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$rel_name" ]; then
|
||||
rel_name="$ver"
|
||||
fi
|
||||
|
||||
# returns the set of files that must have hashes generated.
|
||||
function hash_files() {
|
||||
echo $(find -maxdepth 1 \
|
||||
-iname '*.xz' \
|
||||
-o -iname '*.lz' \
|
||||
-o -iname '*.bz2' \
|
||||
-o -iname '*.zip' \
|
||||
)
|
||||
echo $(find -maxdepth 1 -iname '*.patch')
|
||||
}
|
||||
|
||||
function gen_hashes() {
|
||||
echo -n "Hashing..."
|
||||
sha1sum $(hash_files) >| SHA1SUMS &
|
||||
sha256sum $(hash_files) >| SHA256SUMS &
|
||||
wait
|
||||
echo "done"
|
||||
}
|
||||
|
||||
function sign() {
|
||||
# Kill DISPLAY lest pinentry won't work
|
||||
DISPLAY=
|
||||
eval "$(gpg-agent --daemon --sh --pinentry-program $(which pinentry))"
|
||||
for i in $(hash_files) SHA1SUMS SHA256SUMS; do
|
||||
if [ -e $i -a -e $i.sig -a $i.sig -nt $i ]; then
|
||||
echo "Skipping signing of $i"
|
||||
continue
|
||||
elif [ -e $i.sig ] && gpg2 --verify $i.sig; then
|
||||
# Don't resign if current signature is valid
|
||||
touch $i.sig
|
||||
continue
|
||||
fi
|
||||
echo "Signing $i"
|
||||
rm -f $i.sig
|
||||
gpg2 --use-agent --detach-sign --local-user="$SIGNING_KEY" $i
|
||||
done
|
||||
}
|
||||
|
||||
function verify() {
|
||||
if [ $(find -iname '*.sig' | wc -l) -eq 0 ]; then
|
||||
echo "No signatures to verify"
|
||||
return
|
||||
fi
|
||||
|
||||
for i in *.sig; do
|
||||
echo
|
||||
echo Verifying $i
|
||||
gpg2 --verify $i $(basename $i .sig)
|
||||
done
|
||||
}
|
||||
|
||||
function upload() {
|
||||
verify
|
||||
chmod ugo+r,o-w -R .
|
||||
dir=$(echo $rel_name | sed s/-release//)
|
||||
lftp -c " \
|
||||
open -u hls-downloads: sftp://$host && \
|
||||
mirror -P20 -c --reverse --exclude=fetch-gitlab --exclude=out . hls/$dir && \
|
||||
wait all;"
|
||||
chmod ugo-w $(ls *.xz *.bz2 *.zip)
|
||||
}
|
||||
|
||||
function purge_all() {
|
||||
# Purge CDN cache
|
||||
curl -X PURGE http://downloads.haskell.org/hls/
|
||||
curl -X PURGE http://downloads.haskell.org/~hls/
|
||||
curl -X PURGE http://downloads.haskell.org/hls/$dir
|
||||
curl -X PURGE http://downloads.haskell.org/hls/$dir/
|
||||
curl -X PURGE http://downloads.haskell.org/~hls/$dir
|
||||
curl -X PURGE http://downloads.haskell.org/~hls/$dir/
|
||||
for i in *; do
|
||||
purge_file $i
|
||||
done
|
||||
}
|
||||
|
||||
function purge_file() {
|
||||
curl -X PURGE http://downloads.haskell.org/~hls/$rel_name/$i
|
||||
curl -X PURGE http://downloads.haskell.org/~hls/$rel_name/$i/
|
||||
curl -X PURGE http://downloads.haskell.org/hls/$rel_name/$i
|
||||
curl -X PURGE http://downloads.haskell.org/hls/$rel_name/$i/
|
||||
}
|
||||
|
||||
|
||||
if [ "x$1" == "x" ]; then
|
||||
gen_hashes
|
||||
sign
|
||||
upload
|
||||
purge_all
|
||||
else
|
||||
$@
|
||||
fi
|
Loading…
Reference in New Issue
Block a user