From f74a838506ce107f1075ee9a524414fe7ea48d79 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Sat, 20 Mar 2021 11:24:15 +0100 Subject: [PATCH] feat(github_actions): Add workflow to update API docs Signed-off-by: Lucas Schwiderski --- .github/scripts/apidoc.sh | 158 +++++++++++++++++++++++++++++++++++ .github/workflows/apidoc.yml | 155 ++++++++++++++++++++++++++++++++++ .github/workflows/main.yml | 10 +-- 3 files changed, 318 insertions(+), 5 deletions(-) create mode 100755 .github/scripts/apidoc.sh create mode 100644 .github/workflows/apidoc.yml diff --git a/.github/scripts/apidoc.sh b/.github/scripts/apidoc.sh new file mode 100755 index 000000000..b2daaf624 --- /dev/null +++ b/.github/scripts/apidoc.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env bash +# +# Process (API) docs after a successful build on Travis (via ../.travis.yml). +# +# Updated/changed documentation for "master" is pushed to gh-pages. +# In case of pull requests or other branches, it will get added to a separate branch. +# In case of a pull request, a compare view comment will be posted. +# +# NOTE: stdout/stderr might/should be discarded to not leak sensitive information. + +echo "Post-processing (API) documentation." +echo "PR Number: $PR_NUMBER" +echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF" + +if [ -z "$APIDOC_TOKEN" ]; then + echo "No APIDOC_TOKEN available. Skipping." + exit +fi + +# NOTE: DO NOT USE "set -x", or anything else that would reveal APIDOC_TOKEN! +# GitHub Actions does filter secrets, but extra caution won't hurt +set -e +set +x + +# Display exit code in case of failure (probably due to 'set -x'). +trap '[ "$?" = 0 ] || echo "EXIT CODE: $?"' EXIT + +REPO_APIDOC="https://${APIDOC_TOKEN}@github.com/awesomeWM/apidoc" +REPO_DIR="$PWD" + +export GIT_AUTHOR_NAME="awesome-robot on GitHub Actions" +export GIT_AUTHOR_EMAIL="awesome-robot@users.noreply.github.com" +export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" +export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL" + +git clone --depth 1 --branch gh-pages "$REPO_APIDOC" build/apidoc \ + 2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g" +cd build/apidoc + +# This will re-use already existing branches (updated PR). +if [ "$PR_NUMBER" != false ]; then + BRANCH="pr-$PR_NUMBER" +elif [ "$GITHUB_HEAD_REF" != master ]; then + # Use merge-base of master in branch name, to keep different branches with + # the same name apart. + # shellcheck disable=SC2015 + BRANCH="$GITHUB_HEAD_REF-$(cd "$REPO_DIR" \ + && git fetch --unshallow origin master \ + && git rev-parse --short "$(git merge-base HEAD FETCH_HEAD || true)" || true)" +else + BRANCH="gh-pages" +fi +if [ "$BRANCH" != "gh-pages" ]; then + git checkout -b "$BRANCH" "origin/${BRANCH}" 2> /dev/null || git checkout -b "$BRANCH" +fi + +# Use a temporary branch for the two commits, which allows for a better UI. +git checkout -b merged-update + +# Create the README for the Git repo (https://github.com/awesomeWM/apidoc). +cat > ../doc/README.md <Release:" \ + -I "

API documentation for awesome, a highly configurable X window manager (version .*)\.

" \ + -x .git | patch -p1 + +git add --all . +if git diff --cached --exit-code --quiet; then + echo "Documentation has not changed." + exit +fi + +LAST_COMMIT_MSG="$(cd "$REPO_DIR" && git log -1 --pretty=format:%s)" +LAST_COMMIT="$(cd "$REPO_DIR" && git rev-parse --short HEAD)" + +# Commit the relevant changes. +COMMIT_MSG="Update docs for $AWESOME_VERSION via Github Actions + +Last commit message: +$LAST_COMMIT_MSG + +Commits: https://github.com/awesomeWM/awesome/compare/${GITHUB_BASE_REF}..${GITHUB_HEAD_REF} +Build URL: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" +git commit -m "[relevant] $COMMIT_MSG" + +# Commit the irrelevant changes. +mv .git ../doc +cd ../doc +git add --all . +git commit -m "[boilerplate] $COMMIT_MSG" + +# Reorder/swap commits, to have "relevant" after "boilerplate". +# This makes it show up earlier in the Github interface etc. +git tag _old +git reset --hard HEAD~2 +git cherry-pick _old _old~1 +RELEVANT_REV="$(git rev-parse --short HEAD)" +git tag -d _old + +git checkout "$BRANCH" +OLD_REV="$(git rev-parse --short HEAD)" +if [ "$PR_NUMBER" != false ]; then + MERGE_COMMIT_MSG="$COMMIT_MSG +Pull request: https://github.com/awesomeWM/awesome/pull/${PR_NUMBER}" +else + PR_OR_ISSUE="$(echo "$COMMIT_MSG" | head -n 1 | grep -o '#[0-9]\+' || true)" + if [ -n "$PR_OR_ISSUE" ]; then + MERGE_COMMIT_MSG="$COMMIT_MSG +Ref: https://github.com/awesomeWM/awesome/pull/${PR_OR_ISSUE}" + else + PR_OR_ISSUE_URL="$(echo "$COMMIT_MSG" \ + | grep -Eo 'https://github.com/awesomeWM/awesome/(issues|pull)/[0-9]+' || true)" + if [ -n "$PR_OR_ISSUE_URL" ]; then + MERGE_COMMIT_MSG="$COMMIT_MSG +Ref: $PR_OR_ISSUE_URL" + else + MERGE_COMMIT_MSG="$COMMIT_MSG +Commit: https://github.com/awesomeWM/awesome/commit/${LAST_COMMIT} +Tree: https://github.com/awesomeWM/awesome/commits/${LAST_COMMIT}" + fi + fi +fi +git merge --no-ff -m "$MERGE_COMMIT_MSG" merged-update +NEW_REV="$(git rev-parse --short HEAD)" + +git push origin "$BRANCH" 2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g" + +# Generate compare view links. +# NOTE: use "\n" for line endings, not real ones for valid json! +COMPARE_LINKS="Compare view: https://github.com/awesomeWM/apidoc/compare/${OLD_REV}...${NEW_REV}" +COMPARE_LINKS="$COMPARE_LINKS\nRelevant changes: https://github.com/awesomeWM/apidoc/commit/${RELEVANT_REV}" +if [ "$BRANCH" != "gh-pages" ]; then + COMPARE_LINKS="$COMPARE_LINKS\nComparison against master (gh-pages): https://github.com/awesomeWM/apidoc/compare/gh-pages...${NEW_REV}" +fi +# shellcheck disable=SC2028 +echo "Compare links:\n$COMPARE_LINKS" + +# Post a comment to the PR. +if [ "$PR_NUMBER" != false ]; then + curl -H "Authorization: token $APIDOC_TOKEN" \ + -d "{\"body\": \"Documentation has been updated for this PR.\n\n$COMPARE_LINKS\"}" \ + "https://api.github.com/repos/awesomeWM/awesome/issues/${PR_NUMBER}/comments" \ + 2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g" +fi + +# vim: filetype=sh:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/.github/workflows/apidoc.yml b/.github/workflows/apidoc.yml new file mode 100644 index 000000000..6c291f1c6 --- /dev/null +++ b/.github/workflows/apidoc.yml @@ -0,0 +1,155 @@ +name: Update API docs + +on: + # Trigger on push to branches `master` and `3.5`. + push: + branches: [ master, 3.5 ] + # Trigger on pull request events for PRs that have `master` as their target branch + pull_request: + branches: [ master ] + + # Allow running the workflow manually + workflow_dispatch: + +defaults: + run: + # GitHub Actions adds `errexit` and `pipefail` by default, but we add `xtrace` + # to improve debugging some of the longer scripts. + shell: /bin/bash -o errexit -o pipefail -o xtrace {0} + +jobs: + main: + runs-on: ubuntu-20.04 + + steps: + # Create a cache invalidation key based on the current year + week. + # This way, packages will be checked for updates once every week. + - name: Get Date + id: get-date + run: echo "::set-output name=date::$(/bin/date -u "+%Y%W")" + + - name: Create apt cache directory + run: mkdir /tmp/apt + + - name: Cache apt packages + id: cache-apt + uses: actions/cache@v2 + with: + path: /tmp/apt/*.deb + # The trailing number serves as a version flag that can be incremented + # to invalidate the cache after changing the list of packages. + key: ${{ github.workflow }}-${{ runner.os }}-${{ steps.get-date.outputs.date }}-apt-2 + + - name: Download apt packages + if: steps.cache-apt.outputs.cache-hit != 'true' + run: | + sudo apt-get update + sudo apt-get install --download-only -y --no-install-recommends \ + asciidoctor \ + cmake \ + dbus-x11 \ + gettext \ + gir1.2-gtk-3.0 \ + gir1.2-pango-1.0 \ + git \ + libdbus-1-dev \ + libgirepository1.0-dev \ + libnotify-bin \ + libpango1.0-dev \ + libstartup-notification0-dev \ + libx11-xcb-dev \ + libxcb-cursor-dev \ + libxcb-icccm4-dev \ + libxcb-keysyms1-dev \ + libxcb-randr0-dev \ + libxcb-shape0-dev \ + libxcb-util0-dev \ + libxcb-xfixes0-dev \ + libxcb-xinerama0-dev \ + libxcb-xkb-dev \ + libxcb-xrm-dev \ + libxcb-xtest0-dev \ + libxdg-basedir-dev \ + libxkbcommon-dev \ + libxkbcommon-x11-dev \ + xutils-dev \ + liblua5.3-dev \ + lua5.3 + sudo mv /var/cache/apt/archives/*.deb /tmp/apt/ + + - name: Install downloaded packages + run: | + sudo dpkg -i /tmp/apt/*.deb + + - name: Cache luarocks + id: cache-luarocks + uses: actions/cache@v2 + with: + path: /tmp/luarocks + key: ${{ github.workflow }}-${{ runner.os }}-luarocks-3.5.0 + + - name: Install fresh Luarocks + if: steps.cache-luarocks.outputs.cache-hit != 'true' + run: | + wget -O /tmp/luarocks.tar.gz https://github.com/luarocks/luarocks/archive/v3.5.0.tar.gz + mkdir /tmp/luarocks + tar -xf /tmp/luarocks.tar.gz -C /tmp/luarocks --strip-components=1 + cd /tmp/luarocks + ./configure + make build + sudo make install + + - name: Install cached Luarocks + if: steps.cache-luarocks.outputs.cache-hit == 'true' + run: | + cd /tmp/luarocks + sudo make install + + - name: Install rocks + run: | + sudo -H luarocks install lgi + sudo -H luarocks install ldoc + + - uses: actions/checkout@v2 + + - name: Build Awesome version string + run: | + AWESOME_VERSION="" + + # If this workflow is triggered by a pull request, we get a base branch. + # Otherwise, check if the current commit has a meaningful name. + if [ -n "${{ github.base_ref }}" ]; then + AWESOME_VERSION="${{ github.base_ref }}" + else + AWESOME_VERSION="$(git rev-parse --abbrev-ref HEAD)" + fi + + AWESOME_VERSION="${AWESOME_VERSION}-g$(git rev-parse --short HEAD)" + + if [ "${{ github.event_name }}" == "pull_request" && -n "${{ matrix.test_prev_commits }}" ]; then + AWESOME_VERSION="${AWESOME_VERSION}-PR${{ github.event.number }}" + elif [ "${{ github.event_name }}" == "pull_request" ]; then + AWESOME_VERSION="v9999-PR${{ github.event.number }}" + fi + + echo "AWESOME_VERSION=${AWESOME_VERSION}" >> ${GITHUB_ENV} + + - name: Create Build Environment + run: cmake -E make_directory -B "${{ github.workspace }}/build" + + - name: Configure CMake + run: | + cmake -S ${{ github.workspace }} -B "${{ github.workspace}}/build" \ + -DAWESOME_VERSION=$AWESOME_VERSION \ + -DGENERATE_DOC=ON \ + -DGENERATE_MANPAGES=ON \ + -DDO_COVERAGE=OFF + + - name: Build + run: cd "${{ github.workspace }}/build" && make + + - name: Run apidoc script + env: + PR_NUMBER: ${{ github.event.number }} + APIDOC_TOKEN: ${{ secrets.APIDOC_TOKEN || github.token }} + run: .github/scripts/apidoc.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7df881c92..11dc355e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -95,7 +95,7 @@ jobs: path: /tmp/apt/*.deb # The trailing number serves as a version flag that can be incremented # to invalidate the cache after changing the list of packages. - key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-apt-3 + key: ${{ github.workflow }}-${{ runner.os }}-${{ steps.get-date.outputs.date }}-apt-3 - name: Download apt packages if: steps.cache-apt.outputs.cache-hit != 'true' @@ -158,7 +158,7 @@ jobs: with: path: /tmp/luarocks # The build input for luarocks changes per test, so we need separate caches - key: ${{ runner.os }}-${{ matrix.test_name }}-luarocks-3.5.0 + key: ${{ github.workflow }}-${{ runner.os }}-${{ matrix.test_name }}-luarocks-3.5.0 - name: Install fresh Luarocks if: steps.cache-luarocks.outputs.cache-hit != 'true' @@ -184,7 +184,7 @@ jobs: path: /tmp/xcb-errors # xcb-errors doesn't have versioned releases, so we checkout and cache by commit. # Make sure to keep this in sync with the `git checkout` below. - key: ${{ runner.os }}-xcb-errors-5d660ebe872cadcdc85de9d6f9afe05de629c030 + key: ${{ github.workflow }}-${{ runner.os }}-xcb-errors-5d660ebe872cadcdc85de9d6f9afe05de629c030 - name: Install fresh xcb-errors if: steps.cache-xcb-errors.outputs.cache-hit != 'true' @@ -261,8 +261,8 @@ jobs: -DAWESOME_VERSION=$AWESOME_VERSION \ -DLUA_LIBRARY=${{ matrix.lua_library || env.LUALIBRARY }} \ -DLUA_INCLUDE_DIR=${{ matrix.lua_include_dir || env.LUAINCLUDE }} \ - -DGENERATE_DOC=${{ matrix.build_api_doc && 'ON' || 'OFF' }} \ - -DGENERATE_MANPAGES=${{ matrix.build_api_doc && 'ON' || 'OFF' }} \ + -DGENERATE_DOC=OFF \ + -DGENERATE_MANPAGES=OFF \ -DDO_COVERAGE=${{ matrix.coverage != '' && 'ON' || 'OFF' }} \ -DTEST_MANUAL_SCREENS=${{ matrix.manual_screens }} \ -DSTRICT_TESTS=true \