diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..80721ac87 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,121 @@ +name: Release +# Credits: workflow inspired from +# https://github.com/grain-lang/binaryen.ml/blob/master/.github/workflows/release.yml +# then slightly adapted, using: +# - https://github.com/googleapis/release-please#readme +# - https://github.com/google-github-actions/release-please-action/blob/main/action.yml +# - https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#workflow_run +# - https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts +# - https://github.com/dawidd6/action-download-artifact#readme +# - https://hub.github.com/hub-release.1.html +on: + workflow_run: + workflows: ["Generate static binaries"] + branches: ["master"] + types: ["completed"] + # TODO: dispatch? + +jobs: + release-please: + name: Create Release + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + outputs: + release_created: ${{ steps.release.outputs.release_created }} + upload_url: ${{ steps.release.outputs.upload_url }} + tag_name: ${{ steps.release.outputs.tag_name }} + body: ${{ steps.release.outputs.body }} + steps: + - uses: GoogleCloudPlatform/release-please-action@v2 + id: release + with: + token: ${{ secrets.GITHUB_TOKEN }} + release-type: ocaml + package-name: learn-ocaml + bump-minor-pre-major: true + + add-binaries: + needs: [release-please] + if: ${{ needs.release-please.outputs.release_created }} + name: Add archive and binaries to release + runs-on: ubuntu-latest + steps: + - name: Check out the repo + # Mandatory step (otherwise, hub raises "fatal: Not a git repository") + uses: actions/checkout@v2 + - name: Download workflow artifacts + # cf. https://github.com/actions/download-artifact/issues/3 + uses: dawidd6/action-download-artifact@v2 + with: + workflow: static-builds.yml + workflow_conclusion: success + commit: ${{ github.sha }} + path: artifacts + - name: Unpack workflow artifacts + run: | + cd artifacts + mkdir -v target + dist=(linux darwin) + artifact() { printf "learn-ocaml-%s-x86_64.tar.gz" "$d"; } + for d in "${dist[@]}"; do + mkdir -v -- "$d" + ( cd "$d" && tar xvzf "../$(artifact "$d")/$(artifact "$d")" ) + bin=(./learn-ocaml-client ./learn-ocaml-server ./learn-ocaml) + for b in "${bin[@]}"; do + mv -v -- "$d/$b" "target/$b-$d-x86_64" + done + done + - name: Add binaries to release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: + hub release edit $(find artifacts/target -type f -printf "-a %p ") -m "" "${{ needs.release-please.outputs.tag_name }}" + + opam-release: + needs: [release-please] + if: ${{ needs.release-please.outputs.release_created }} + name: Publish to opam registry + env: + # Can be changed for debugging + source_repo: "ocaml-sf/learn-ocaml" + opam_repo: "ocaml/opam-repository" + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v2 + - name: Setup bot user + run: | + git config --global user.email "37002148+proofbot@users.noreply.github.com" + git config --global user.name "Learn-OCaml Bot" + # Some hacks to make sure opam doesn't pull the repo in a way we can't deal with + - name: Setup opam repository + run: | + mkdir -v -p ~/.opam/plugins/opam-publish/repos/ + git clone git://github.com/$opam_repo ~/.opam/plugins/opam-publish/repos/${opam_repo/\//%} + cd ~/.opam/plugins/opam-publish/repos/${opam_repo/\//%} + git remote add user https://${{ secrets.OPAM_RELEASE }}@github.com/proofbot/opam-repository + # Set up our token because opam doesn't support env var tokens + - name: Setup token + run: | + mkdir -p ~/.opam/plugins/opam-publish/ + echo -n ${{ secrets.OPAM_RELEASE }} > ~/.opam/plugins/opam-publish/proofbot.token + - name: Generate CHANGES file + env: + CHANGES: ${{ needs.release-please.outputs.body }} + run: | + printf "%s" "$CHANGES" > CHANGES.md + # TODO: Docker-based caching + - name: Setup OCaml + uses: avsm/setup-ocaml@v1 + with: + ocaml-version: 4.12.0 + - name: Install opam-publish + run: | + opam install -y -j 2 opam-publish + - name: Install expect + run: | + sudo apt-get update -y -q + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -q --no-install-recommends expect + - name: Publish to opam + run: | + ./scripts/opam-publish.exp "${{ needs.release-please.outputs.tag_name }}" "$opam_repo" "$source_repo" diff --git a/scripts/opam-publish.exp b/scripts/opam-publish.exp new file mode 100755 index 000000000..961e012d5 --- /dev/null +++ b/scripts/opam-publish.exp @@ -0,0 +1,57 @@ +#!/usr/bin/expect -f + +set tag_name [lindex $argv 0] +set opam_repo [lindex $argv 1] +set source_repo [lindex $argv 2] + +# This Expect script was generated by autoexpect on Tue Oct 5 17:03:15 2021 +# then modified by Erik Martin-Dorel +# Expect and autoexpect were both written by Don Libes, NIST. +# +# Note that autoexpect does not guarantee a working script. It +# necessarily has to guess about certain things. Two reasons a script +# might fail are: +# +# 1) timing - A surprising number of programs (rn, ksh, zsh, telnet, +# etc.) and devices discard or ignore keystrokes that arrive "too +# quickly" after prompts. If you find your new script hanging up at +# one spot, try adding a short sleep just before the previous send. +# Setting "force_conservative" to 1 (see below) makes Expect do this +# automatically - pausing briefly before sending each character. This +# pacifies every program I know of. The -c flag makes the script do +# this in the first place. The -C flag allows you to define a +# character to toggle this mode off and on. + +set force_conservative 0 ;# set to 1 to force conservative mode even if + ;# script wasn't run conservatively originally +if {$force_conservative} { + set send_slow {1 .1} + proc send {ignore arg} { + sleep .1 + exp_send -s -- $arg + } +} + +# +# 2) differing output - Some programs produce different output each time +# they run. The "date" command is an obvious example. Another is +# ftp, if it produces throughput statistics at the end of a file +# transfer. If this causes a problem, delete these patterns or replace +# them with wildcards. An alternative is to use the -p flag (for +# "prompt") which makes Expect only look for the last line of output +# (i.e., the prompt). The -P flag allows you to define a character to +# toggle this mode off and on. +# +# Read the man page for more info. +# +# -Don + + +set timeout -1 +spawn bash -c {export GIT_PAGER=cat && opam publish --no-browser --msg-file=CHANGES.md --tag "$1" --repo="$2" "$3"} bash "$tag_name" "$opam_repo" "$source_repo" +match_max 100000 +expect -exact "Please confirm the above data. Continue ? \[Y/n\] " +send -- "y" +expect -exact "File a pull-request for this patch ? \[Y/n\] " +send -- "y" +expect eof