Follow Upstream #202
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Follow Upstream | |
on: | |
push: | |
branches: [ main, master ] | |
pull_request: | |
branches: [ '**', '!gh-pages', '!coverage' ] | |
types: [ opened, reopened, ready_for_review, synchronize ] | |
schedule: | |
- cron: '0 17 * * 0' | |
workflow_dispatch: | |
inputs: | |
defaults: | |
run: | |
shell: bash | |
jobs: | |
check: | |
name: Check Upstream | |
uses: StirlingLabs/Actions/.github/workflows/nugetCheckRelease.yaml@main | |
with: | |
upstream: 'microsoft/msquic' | |
rids: 'linux-x64 osx win-x64' | |
releasePrefix: 'v' | |
ignoreReleases: '2.2.1 2.0.4 1.9.0 1.1.8 1.0.3 1.8.0 1.7.0 1.6.0 1.5.0 1.4.0 1.1.6 1.3.0 1.1.4 1.2.0 1.1.3 1.1.2 1.1.0-138070 1.0.0-129524 0.9.2-draft-31' | |
nupkgName: 'StirlingLabs.MsQuic.Bindings.runtime.RID.openssl' | |
binaries: | |
name: Get Upstream Binaries | |
needs: [ check ] | |
if: needs.check.outputs.continue == 'true' | |
strategy: | |
fail-fast: false | |
max-parallel: 1 | |
matrix: | |
release: ${{ fromJSON(needs.check.outputs.releases_needed_json) }} | |
runs-on: ubuntu-22.04 | |
outputs: | |
continue: ${{ steps.download.outputs.continue }} | |
manifest: ${{ steps.download.outputs.manifest }} | |
matrixRid: ${{ steps.download.outputs.ridArray }} | |
readme: ${{ steps.ancillary.outputs.readme }} | |
icon: ${{ steps.ancillary.outputs.icon }} | |
steps: | |
- name: Get Libraries | |
id: download | |
env: | |
release: ${{ matrix.release }} | |
releasePrefix: ${{ needs.check.outputs.releasePrefix }} | |
releasesUrl: ${{ needs.check.outputs.releasesUrl }} | |
tagsUrl: ${{ needs.check.outputs.tagsUrl }} | |
rids: ${{ needs.check.outputs.rids }} | |
run: | | |
# | |
# Get info about the release being processed | |
echo "Processing $release" | |
if ! allReleasesJson="$( jq -c . <<< "$(curl -s "${releasesUrl}")" )" ; then | |
echo "‼️ Problem getting releases: ${allReleasesJson}" | |
fi | |
if ! releaseJson="$( jq -r ".[] | select(.tag_name==\"${releasePrefix}${release}\" )" <<< "$allReleasesJson" )" \ | |
|| [[ "$releaseJson" == "" ]] ; then | |
echo "‼️ Problem getting release info for ${release}: ${releaseJson}" | |
fi | |
if ! gitBranch="$( jq -r ".target_commitish" <<< "$releaseJson" )" \ | |
|| [[ "$gitBranch" == "" ]] ; then | |
echo "‼️ Problem getting branch: ${gitBranch}" | |
fi | |
if ! tagsJson="$( jq -c . <<< "$(curl -s "$tagsUrl")" )" ; then | |
echo "‼️ Problem getting tags: ${tagsJson}" | |
fi | |
if ! gitCommit="$( jq -r ".[] | select(.name==\"${releasePrefix}${release}\" ) | .commit.sha" <<< "$tagsJson")" \ | |
|| [[ "$gitCommit" == "" ]] ; then | |
echo "‼️ Problem getting commit: ${gitCommit}" | |
fi | |
# | |
# Process this release | |
continue="false" | |
ridsAvailable="" && ridsAvailableComma="" | |
for rid in $rids ; do | |
echo " - $rid" | |
case "${rid}" in | |
linux-x64) platform="linux_x64" && upstreamFilename="libmsquic.so.$release" && ourFilename="libmsquic-openssl.so" ;; | |
osx) platform="macos_universal" && upstreamFilename="libmsquic.$release.dylib" && ourFilename="libmsquic-openssl.dylib" ;; | |
win-x64) platform="windows_x64" && upstreamFilename="msquic.dll" && ourFilename="msquic-openssl.dll" ;; | |
*) echo "Do not recognise ${rid}." && exit 1 ;; | |
esac | |
archive="msquic_${platform}_Release_openssl.zip" | |
if url="$(jq -r ".assets | .[] | select(.name==\"${archive}\") | .browser_download_url" <<< "$releaseJson")" ; then | |
if [ "$url" == "" ] ; then | |
echo " - ‼️ This release has no files for $rid." | |
continue | |
fi | |
echo "Downloading $url" | |
if wget --quiet "${url}" ; then | |
unzip "${archive}" -d "${platform}" | |
mkdir -p "${releasePrefix}${release}/${rid}" | |
finalFilename="${releasePrefix}${release}/${rid}/${ourFilename}" | |
mv "${platform}/bin/${upstreamFilename}" "${finalFilename}" | |
sudo chmod +r "${finalFilename}" | |
rm -Rf "${platform}" "${archive}" | |
else | |
echo " - ‼️ Problem downloading $url" | |
fi | |
ridsAvailable="${ridsAvailable}${ridsAvailableComma}{ \"rid\": \"${rid}\", \"location\": \"${finalFilename}\", \"filename\": \"${ourFilename}\" }" | |
ridsAvailableComma=", " | |
else | |
echo -e " - problem getting URL from $archive $releaseJson: $url" | |
fi | |
done | |
if [ "$ridsAvailable" != "" ] ; then | |
continue="true" | |
#shellcheck disable=SC2089 | |
manifest="{ \"version\": \"${release}\", \"gitBranch\": \"${gitBranch}\", \"gitCommit\": \"${gitCommit}\", \"platforms\": [ $ridsAvailable ] }" | |
echo "$manifest" > manifest.json | |
else | |
continue=false | |
fi | |
# | |
# Outputs | |
echo "continue=${continue}" >> "$GITHUB_OUTPUT" | |
echo "manifest=${manifest}" >> "$GITHUB_OUTPUT" | |
- name: Upload Libraries | |
if: steps.download.outputs.continue == 'true' | |
uses: actions/upload-artifact@v3 | |
with: | |
name: Libraries-${{ matrix.release }} | |
path: "./*" | |
- name: Get Source | |
if: steps.download.outputs.continue == 'true' | |
uses: actions/checkout@v3 | |
- name: Identify Ancillaries | |
if: steps.download.outputs.continue == 'true' | |
id: ancillary | |
env: | |
readme: StirlingLabs.MsQuic.Bindings/README.md | |
icon: SL.png | |
manifest: ${{ steps.download.outputs.manifest }} | |
run: | | |
main() { | |
if [[ -s "${readme}" ]] ; then | |
echo "readme=${readme}" >> $GITHUB_OUTPUT | |
else | |
echo "README Not found at ${readme}" | |
fi | |
if [[ -s "${icon}" ]] ; then | |
echo "icon=${icon}" >> $GITHUB_OUTPUT | |
else | |
echo "Icon Not found at ${icon}" | |
fi | |
[[ -f manifest.json ]] && rm -f manifest.json | |
if checkJson "$platformJson" ; then | |
echo $manifest > manifest.json | |
echo "Wrote manifest.json" | |
fi | |
find . | |
} | |
function checkJson() { | |
local json="$1" ; local out | |
if ! out="$( echo "$json" | jq -c '.' )" ; then | |
echo "‼️ Error: Failed to verify json: $out" >&2 | |
return 1 | |
fi | |
} | |
main "$@" ; exit $? | |
- name: Upload Ancillaries | |
if: steps.download.outputs.continue == 'true' | |
uses: actions/upload-artifact@v3 | |
with: | |
name: Ancillaries-${{ matrix.release }} | |
path: | | |
${{ steps.ancillary.outputs.readme }} | |
${{ steps.ancillary.outputs.icon }} | |
manifest.json | |
nupkg: | |
name: Publish NuPkg | |
needs: [ check, binaries ] | |
if: | | |
needs.check.outputs.continue == 'true' && | |
needs.binaries.outputs.continue == 'true' | |
strategy: | |
fail-fast: true | |
max-parallel: 3 | |
matrix: | |
version: ${{ fromJSON(needs.check.outputs.releases_needed_json) }} | |
rid: ${{ fromJSON(needs.check.outputs.rids_json) }} | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Get Ancillaries | |
id: ancillaries | |
uses: actions/download-artifact@v3 | |
with: | |
name: Ancillaries-${{ matrix.version }} | |
- name: Data | |
id: data | |
env: | |
debug: ${{ needs.check.outputs.debug }} | |
version: ${{ matrix.version }} | |
gitUrl: ${{ needs.check.outputs.gitUrl }} | |
releasePrefix: ${{ needs.check.outputs.releasePrefix }} | |
rid: ${{ matrix.rid }} | |
manifest: ${{steps.ancillaries.outputs.download-path}}/manifest.json | |
this_repo_url: ${{ github.repositoryUrl }} | |
this_repo_commit: ${{ github.sha }} | |
this_repo_branch: ${{ github.ref_name }} | |
run: | | |
if [[ ! -s "$manifest" ]] ; then | |
echo "Manifest does not exist yet at $manifest" | |
ls -la | |
unzip ./*.zip | |
ls -la | |
[[ ! -s "$manifest" ]] && exit 1 | |
echo "Manifest now exists at $manifest" | |
fi | |
if ! ridJson="$( jq -c ".platforms[] | select(.rid==\"${rid}\")" "$manifest" )" ; then | |
echo -e "Problem getting JSON for $rid from $manifest:\n$ridJson" | |
#exit 1 | |
fi | |
if [[ "$ridJson" == "" ]] ; then | |
echo "No manifest for $rid, so no need to continue." | |
continue="false" | |
else | |
echo -n "Reading details; " | |
if gitCommit="$( jq -r ".gitCommit" "$manifest" )" ; then | |
echo -n "git commit ${gitCommit}, " | |
else | |
echo "Problem getting gitCommit from manifest: $gitCommit" | |
fi | |
if gitBranch="$( jq -r ".gitBranch" "$manifest" )" ; then | |
echo -n "git branch ${gitBranch}, " | |
else | |
echo "Problem getting gitBranch from manifest: $gitBranch" | |
fi | |
if location="$( jq -r ".location" <<< "$ridJson" )" ; then | |
echo -n "location ${location}, " | |
else | |
echo "Problem getting location from manifest: $location" | |
fi | |
if filename="$( jq -r ".filename" <<< "$ridJson" )" ; then | |
echo -n "filename ${filename}, " | |
else | |
echo "Problem getting filename from manifest: $filename" | |
fi | |
echo "done." | |
continue="true" | |
fi | |
# If this is not a produciton build (so it will use our GitHub store), we have to lie about where it comes from | |
if [[ "$debug" == "true" ]] ; then | |
echo "Note: this is a workaround" | |
gitUrl="$this_repo_url" | |
gitCommit="$this_repo_commit" | |
gitBranch="$this_repo_branch" | |
fi | |
#shellcheck disable=SC2129 | |
echo "filename=${filename}" >> "$GITHUB_OUTPUT" | |
echo "location=${location}" >> "$GITHUB_OUTPUT" | |
echo "packageName=StirlingLabs.MsQuic.Bindings.runtime.${rid}.openssl" >> "$GITHUB_OUTPUT" | |
echo "gitUrl=${gitUrl}" >> "$GITHUB_OUTPUT" | |
echo "gitCommit=${gitCommit}" >> "$GITHUB_OUTPUT" | |
echo "gitBranch=${gitBranch}" >> "$GITHUB_OUTPUT" | |
echo "continue=${continue}" >> "$GITHUB_OUTPUT" | |
- name: Get Libraries | |
if: steps.data.outputs.continue == 'true' | |
id: libraries | |
uses: actions/download-artifact@v3 | |
with: | |
name: Libraries-${{ matrix.version }} | |
- name: Show File Context | |
if: steps.data.outputs.continue == 'true' | |
run: | | |
find . | |
- name: Create NuSpec | |
if: steps.data.outputs.continue == 'true' | |
id: nuspec | |
uses: StirlingLabs/CreateNuSpecAction@main | |
with: | |
id: ${{ steps.data.outputs.packageName }} | |
version: ${{ matrix.version }} | |
title: MsQuic runtime for ${{ matrix.rid }} ${{ needs.check.outputs.releasePrefix }}${{ matrix.version }} | |
description: | | |
Platform-specific runtime for MsQuic, Microsoft's C implementation of the IETF QUIC protocol. | |
fileSources: ${{ steps.libraries.outputs.download-path }}/${{ steps.data.outputs.location }} | |
fileTargets: runtimes/${{ matrix.rid }}/native/${{ steps.data.outputs.filename }} | |
readme: ${{ steps.ancillaries.outputs.download-path }}/${{ needs.binaries.outputs.readme }} | |
icon: ${{ steps.ancillaries.outputs.download-path }}/${{ needs.binaries.outputs.icon }} | |
gitUrl: ${{ steps.data.outputs.gitUrl }} | |
gitBranch: ${{ steps.data.outputs.gitBranch }} | |
gitCommit: ${{ steps.data.outputs.gitCommit }} | |
targetFrameworks: net6.0;netstandard2.0;netstandard2.1 | |
- name: Build NuPkg | |
if: steps.data.outputs.continue == 'true' | |
id: build | |
env: | |
nuspec: ${{ steps.nuspec.outputs.filename }} | |
run: | | |
nuget pack $nuspec | |
[ $? -eq 0 ] && continue="true" || continue="false" | |
echo "continue=${continue}" >> $GITHUB_OUTPUT | |
ls -la | |
- name: Push NuPkg | |
if: steps.build.outputs.continue == 'true' | |
id: push | |
env: | |
debug: ${{ needs.check.outputs.debug }} | |
githubKey: ${{ github.token }} | |
githubUrl: "https://nuget.pkg.github.com/${{github.repository_owner}}/index.json" | |
nugetKey: ${{ secrets.NUGET_STIRLINGLABS_API_KEY }} | |
nugetUrl: "https://api.nuget.org/v3/index.json" | |
run: | | |
if [[ "$debug" == "true" ]] ; then | |
key="$githubKey" && url="$githubUrl" | |
else | |
key="$nugetKey" && url="$nugetUrl" | |
fi | |
if dotnet nuget push ./*.nupkg -k "$key" -s "$url" --no-symbols --skip-duplicate ; then | |
continue="true" | |
else | |
continue="false" | |
echo "Failed to push NuPkg to $url" | |
fi | |
echo "continue=${continue}" >> "$GITHUB_OUTPUT" | |
- name: Summary | |
if: steps.push.outputs.continue == 'true' | |
id: summary | |
env: | |
id: ${{ steps.data.outputs.packageName }} | |
version: ${{ matrix.version }} | |
rid: ${{ matrix.rid }} | |
run: | | |
echo "### Uploaded NuPkg for [${id}](https://www.nuget.org/packages/${id}) ${version} ${rid}." >> "$GITHUB_STEP_SUMMARY" | |
code: | |
name: Get Upstream Code | |
needs: [ check ] | |
if: needs.check.outputs.continue == 'true' | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Get Our Source | |
uses: actions/checkout@v3 | |
with: | |
submodules: true | |
- name: Get Latest Code Archive | |
id: retrieve | |
env: | |
upstream: ${{ needs.check.outputs.upstream }} | |
import: 'src/cs/lib' | |
target: 'StirlingLabs.MsQuic.Bindings' | |
run: | | |
base="${upstream}" | |
echo "base is ${base}" | |
if ! latestJson="$(curl -s https://github.com/repos/${upstream}/releases/latest)" ; then | |
echo "Failed to get latest release for ${upstream}: $latestJson" | |
exit 1 | |
fi | |
if ! version="$(jq -r ".tag_name" <<< "$latestJson")" ; then | |
echo -e "Failed to get version from JSON: $version\nsource:\n$latestJson" | |
exit 1 | |
fi | |
if ! url="$(jq -r ".zipball_url" <<< "$latestJson")" ; then | |
echo -e "Failed to get URL from JSON: $url\nsource:\n$latestJson" | |
exit 1 | |
fi | |
if ! wget --quiet "${url}" -O upstream.zip ; then | |
echo "Failed to download ${url}" | |
exit 1 | |
fi | |
mkdir -p "${base}" | |
unzip upstream.zip -d "${base}" | |
rm -f upstream.zip | |
subdir="$(ls "${base}")" && subdirArray=( $subdir ) | |
if [[ "${#subdirArray[@]}" != "1" ]] ; then | |
echo "${#subdirArray[@]} objects in $base ... $subdir" | |
exit 1 | |
fi | |
codebase="${base}/${subdir}" | |
echo "base=${base}" >> "$GITHUB_OUTPUT" | |
echo "source=${codebase}/${import}" >> "$GITHUB_OUTPUT" | |
echo "target=${target}" >> "$GITHUB_OUTPUT" | |
echo "version=${version}" >> "$GITHUB_OUTPUT" | |
- name: Edit Upstream Files | |
id: edit | |
env: | |
base: ${{ steps.retrieve.outputs.base }} | |
source: ${{ steps.retrieve.outputs.source }} | |
target: ${{ steps.retrieve.outputs.target }}/Imported | |
run: | | |
ls -la "${source}" | |
files="${source}/*.cs" | |
for file in $files ; do | |
echo -n "Processing $file ... " | |
if [[ "$file" != *"InternalsVisible.cs" ]] ; then | |
sed -i '1i \#nullable enable' "$file" && echo -n "nullable " || echo -n "‼️ nullable failed ‼️ " | |
sed -i 's/\(^\s*\) \(\binternal\b\)/\1 public/' "$file" && echo -n "public " || echo -n "‼️ public failed ‼️ " | |
sed -i 's/\bMicrosoft\.Quic\b/StirlingLabs.MsQuic.Bindings/' "$file" && echo -n "namespace " || echo -n "‼️ namespace failed ‼️ " | |
sed -i 's/\(^.*DllImport.\{1,3\}\"msquic\)\(\"\)/\1-openssl\2/' "$file" && echo -n "openssl " || echo -n "‼️ openssl failed ‼️ " | |
echo "done." | |
mv -f "$file" "${target}/" | |
fi | |
done | |
rm -Rf "$base" | |
ls -la "$target" | |
- name: Update Our Files | |
id: update | |
env: | |
target: ${{ steps.retrieve.outputs.target }} | |
version: ${{ steps.retrieve.outputs.version }} | |
releasePrefix: ${{ needs.check.outputs.releasePrefix }} | |
run: | | |
rawVersion="${version#"$releasePrefix"}" | |
echo "Updating files for version $version ($rawVersion)" | |
if [[ "$rawVersion" == "" ]] ; then | |
echo "Version not set, can't continue." | |
exit 1 | |
fi | |
# file="${target}/${target}.csproj" | |
# [[ -f "$file" ]] && echo -n "Editing $file ... " || echo -n "Can't find $file ... " | |
# sed -i "s/\(\bStirlingLabs\.MsQuic\.Bindings\.runtime\.\(linux\|osx\|win\).*\.openssl.*Version=\"\)\(.*\)\(\"\)/\1${rawVersion}\4/" "$file" && echo "done." || echo "failed‼️" | |
file="MsQuicBindingsVersionOnly.proj" | |
[[ -f "$file" ]] && echo -n "Replacing $file ... " || echo -n "Creating $file ... " | |
echo "<Project><PropertyGroup><StirlingLabsMsQuicRuntimeVersion>${version:1}</StirlingLabsMsQuicRuntimeVersion></PropertyGroup></Project>" > "$file" && echo "done." || echo "failed‼️" | |
cat "$file" | |
- name: Create PR | |
uses: peter-evans/create-pull-request@v5 | |
with: | |
commit-message: Update to incorporate upstream changes in ${{ steps.retrieve.outputs.version }} | |
base: main | |
branch: upstream-${{ steps.retrieve.outputs.version }} | |
delete-branch: true | |
title: Update to ${{ steps.check.outputs.upstream }} ${{ steps.retrieve.outputs.version }} | |
body: | | |
Automatically prepared the following changes: | |
- Re-imported upstream files and re-applied our modifications | |
- Updated projects to refer to new upstream libraries | |
- name: Summary | |
id: summary | |
env: | |
version: ${{ steps.retrieve.outputs.version }} | |
run: | | |
echo "### Created PR for update to ${version}." >> "$GITHUB_STEP_SUMMARY" |