Improve helper object api (#2745) #3960
This file contains hidden or 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: Check for Broken Links and Publish Wiki | |
| 'on': | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| types: [ opened, synchronize, reopened ] | |
| branches: [ main ] | |
| workflow_dispatch: | |
| workflow_run: | |
| workflows: ["Release Action"] | |
| branches: [ main ] | |
| types: | |
| - completed | |
| schedule: | |
| # every monday at night | |
| - cron: '0 1 * * 1' | |
| env: | |
| PUBLISH: ${{ github.event_name == 'workflow_dispatch' | |
| || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') }} | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 65 | |
| if: ${{ !(github.event_name == 'push' && startsWith(github.event.head_commit.message, '[release:')) | |
| && (github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success') }} | |
| outputs: | |
| publish: ${{ steps.gate.outputs.publish }} | |
| steps: | |
| - name: "🚦 Publish Gate" | |
| id: gate | |
| run: echo "publish=$PUBLISH" >> "$GITHUB_OUTPUT" | |
| - name: "🛒 Checkout Repository" | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| lfs: ${{ env.PUBLISH == 'true' }} | |
| token: ${{ secrets.RELEASE_TOKEN }} | |
| fetch-tags: true | |
| fetch-depth: 0 | |
| ref: ${{ github.event_name == 'workflow_run' && 'main' || github.sha }} | |
| - name: "🌍 Load Versions to Use" | |
| run: bash .github/workflows/scripts/global-configuration.sh | |
| - name: "⬇️ Use Node.js" | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.ACTION_NODE_VERSION }} | |
| registry-url: "https://registry.npmjs.org/" | |
| cache: npm | |
| - name: "⬇️ Setup R" | |
| uses: ./.github/actions/setup-r | |
| timeout-minutes: 45 | |
| with: | |
| r-version: ${{ env.ACTION_R_VERSION }} | |
| - name: "📦 Install R Packages" | |
| uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| cache: 'true' | |
| cache-version: '1' | |
| extra-packages: | | |
| any::dplyr | |
| any::readr | |
| - name: "🛒 Checkout LFS" | |
| if: ${{ success() && env.PUBLISH == 'true' }} | |
| # just as a time-proven safety measure | |
| run: git lfs checkout | |
| - name: "⚗️ Test Suite (full, for data)" | |
| # we make sure we have a clean run | |
| run: | | |
| rm -rf "coverage/" | |
| rm -f "/tmp/flowr-label-summary.json" | |
| bash .github/workflows/scripts/run-flowr-command.sh "test:full -- --allowOnly=false" | |
| - name: "💾 Cache the Signature Database Bundles" | |
| uses: actions/cache@v4 | |
| with: | |
| # only the bundles, the shards unpacked next to them are re-derived on demand | |
| path: ~/.cache/flowr/sigdb/bundles | |
| key: sigdb-bundles-${{ hashFiles('src/data/sigdb/sigdb.remote.json') }} | |
| - name: "⬇️ Sync the Signature Database" | |
| # without it every sigdb-backed page says "No signature database is loaded" instead of showing a result | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: npm run sync:sigdb | |
| # the release workflow produces the data but does not commit it, so it lands in the same commit as the pages | |
| - name: "⬇️ Get the Benchmark Data from the Release Run" | |
| if: ${{ github.event_name == 'workflow_run' }} | |
| uses: actions/download-artifact@v4 | |
| continue-on-error: true | |
| with: | |
| name: benchmark-data | |
| path: wiki/stats/benchmark/ | |
| run-id: ${{ github.event.workflow_run.id }} | |
| github-token: ${{ secrets.RELEASE_TOKEN }} | |
| - name: "🛠️ Update the Generated Pages" | |
| run: | | |
| # npm ci is done by the full test run before | |
| CHANGED_ANY=false | |
| CHANGED_FILES=() | |
| # Generate all wiki pages | |
| npm run wiki | |
| # the landing page is generated too, from real flowR output; the signature browser is megabytes, | |
| # so the documentation job builds that one straight onto gh-pages instead | |
| FLOWR_LANDING_ONLY=1 npm run gen:landing | |
| # the signature browser is gitignored on purpose (megabytes); only the page and its samples are committed | |
| for LANDING in index.html wiki/landing/index.html; do | |
| if [ -n "$(git status --porcelain -- "$LANDING")" ]; then CHANGED_FILES+=("$LANDING"); fi | |
| done | |
| # read in everything from /tmp/flowr-wiki-changed-files.txt and add to CHANGED_FILES | |
| if [ -f /tmp/flowr-wiki-changed-files.txt ]; then | |
| while IFS= read -r line; do | |
| CHANGED_FILES+=("$line") | |
| done < /tmp/flowr-wiki-changed-files.txt | |
| fi | |
| if [ ${#CHANGED_FILES[@]} -gt 0 ]; then | |
| echo "The following Wiki pages were changed:" | |
| for file in "${CHANGED_FILES[@]}"; do | |
| echo "- $file" | |
| git add -f "$file" | |
| done | |
| CHANGED_ANY=true | |
| echo "CHANGED=true" >> $GITHUB_ENV | |
| else | |
| echo "No Wiki pages were changed!" | |
| fi | |
| echo "====== Benchmark Data (if any) ======" | |
| if [ -n "$(git status --porcelain -- wiki/stats/benchmark/)" ]; then | |
| echo "New benchmark data!" | |
| git add -f wiki/stats/benchmark/ | |
| CHANGED_ANY=true | |
| echo "CHANGED=true" >> $GITHUB_ENV | |
| CHANGED_FILES+=("benchmark-data") | |
| else | |
| echo "No new benchmark data!" | |
| fi | |
| echo "====== Producing Update (if necessary) ======" | |
| # check for an update in the versions! (including the updated name information) | |
| LIMIT_TO_LAST=8 | |
| ALL_TAGS=$( git tag --list --format="%(tag) (%(creatordate))" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | sed -E 's/^(v[0-9]+\.[0-9]+\.[0-9]+)\s*\(([a-zA-Z]+\s*)([a-zA-Z]+)\s*([0-9]+)\s*[0-9:]+\s+([0-9]+).*/\1 (\3 \4, \5)/' | sort -V | tail -n$LIMIT_TO_LAST) | |
| NUM_OF_TAGS=$(echo "$ALL_TAGS" | wc -l) | |
| LATEST_TAG=$(echo "$ALL_TAGS" | tail -n1) | |
| # add (latest) to the latest tag | |
| ALL_TAGS=$(sed -E "s/^$LATEST_TAG$/$LATEST_TAG (latest)/" <<< "$ALL_TAGS") | |
| ALL_TAGS=$(echo -e "<Older> (please consider updating)\n$ALL_TAGS") | |
| ALL_TAGS+="\nUnknown\nUnreleased/Dev" | |
| ALL_TAGS=$(echo -e "$ALL_TAGS" | sed -E 's/^(.*)$/ - \1/') | |
| cp .github/ISSUE_TEMPLATE/bug-report.yaml .github/ISSUE_TEMPLATE/bug-report.yaml.tmp | |
| sed -i -E "/\s*# START::Versions/,/\s*# END::Versions/c\\# START::Versions\n$(echo "$ALL_TAGS" | sed 's/$/\\/' ) \n# END::Versions" .github/ISSUE_TEMPLATE/bug-report.yaml | |
| sed -i -E "/\s*# START::DefaultVersion/,/\s*# END::DefaultVersion/c\\# START::DefaultVersion\n default: $((NUM_OF_TAGS))\n# END::DefaultVersion" .github/ISSUE_TEMPLATE/bug-report.yaml | |
| if ! diff -q .github/ISSUE_TEMPLATE/bug-report.yaml .github/ISSUE_TEMPLATE/bug-report.yaml.tmp; then | |
| echo "Versions in the bug-report changed!" | |
| echo "CHANGED=true" >> $GITHUB_ENV | |
| CHANGED_ANY=true | |
| git add -f .github/ISSUE_TEMPLATE/bug-report.yaml | |
| CHANGED_FILES+=("bug-report.yaml") | |
| else | |
| echo "Versions in bug-report did not change!" | |
| fi | |
| echo "====== Make Commit (if necessary) ======" | |
| if [ $CHANGED_ANY == "true" ]; then | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| git config lfs.allowincompletepush true | |
| CHANGED_FILES_STRING=$(IFS=,; echo "${CHANGED_FILES[*]}") | |
| git commit -m "[skip ci] doc: update generated wiki pages ($CHANGED_FILES_STRING)" | |
| fi | |
| - name: "⬆️ Push changed Wiki pages" | |
| if: ${{ success() && env.CHANGED == 'true' && env.PUBLISH == 'true' }} | |
| run: | | |
| git fetch origin main | |
| git rebase --autostash origin/main | |
| git push origin HEAD:main | |
| - name: "⬆️ Publish the Wiki" | |
| uses: Andrew-Chen-Wang/github-wiki-action@v4.4.0 | |
| # We do not need to republish if nothing changes. Furthermore, do not publish on PR as this should be done by the push on main! | |
| if: ${{ success() && env.PUBLISH == 'true' }} | |
| with: | |
| path: "wiki/" | |
| strategy: 'init' | |
| token: ${{ secrets.GH_DEPLOY_WIKI }} | |
| ignore: | | |
| **/*.md.tmp | |
| **/*-Old.* | |
| - name: "🔎 Check the Wiki pages for broken external links" | |
| uses: becheran/mlc@v1.2.0 | |
| # thousands of links against a rate-limiting host can stall for hours; the step is allowed to | |
| # fail, so hitting the limit only ends the check, it never ends the run | |
| timeout-minutes: 20 | |
| continue-on-error: true | |
| if: ${{ success() && env.PUBLISH == 'true' }} | |
| with: | |
| args: >- | |
| --throttle 25 --ignore-path "wiki/stats" | |
| --do-not-warn-for-redirect-to "http*://github.com/flowr-analysis/*,http*://flowr-analysis.github.io/*" | |
| --ignore-links "http*://hub.docker.com/r/*,http*://*npmjs.com/*,http*://doi.org/*,http*://*linkedin.com/*,http*://*r-bloggers.com/*,http*://*gnu.org/*,http*://linux.die.net/*,http*://mermaid.js.org/*" | |
| wiki/ | |
| - name: "🔎 Check the README for broken external links" | |
| uses: becheran/mlc@v1.2.0 | |
| timeout-minutes: 5 | |
| continue-on-error: true | |
| if: ${{ success() && env.PUBLISH == 'true' }} | |
| with: | |
| args: >- | |
| --throttle 25 --files "./README.md" | |
| --do-not-warn-for-redirect-to "http*://github.com/flowr-analysis/*,http*://flowr-analysis.github.io/*" | |
| --ignore-links "http*://hub.docker.com/r/*,http*://*npmjs.com/*,http*://doi.org/*,http*://*linkedin.com/*,http*://*r-bloggers.com/*,http*://*gnu.org/*,http*://linux.die.net/*,http*://mermaid.js.org/*" | |
| deploy-doc: | |
| name: "🚀 Build and Deploy Documentation" | |
| needs: [ build ] | |
| if: ${{ needs.build.outputs.publish == 'true' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 65 | |
| steps: | |
| - name: "🛒 Checkout Repository" | |
| uses: actions/checkout@v6 | |
| with: | |
| token: ${{ secrets.DOCUMENTATION_TOKEN }} | |
| submodules: true | |
| lfs: true | |
| ref: main | |
| # the version marker compares HEAD against the release tag, which a shallow clone without tags cannot do | |
| fetch-tags: true | |
| fetch-depth: 0 | |
| - name: "🌍 Load Versions to Use" | |
| run: bash .github/workflows/scripts/global-configuration.sh | |
| - name: "⬇️ Use Node.js" | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.ACTION_NODE_VERSION }} | |
| registry-url: "https://registry.npmjs.org/" | |
| cache: npm | |
| - name: "⬇️ Setup R" | |
| uses: ./.github/actions/setup-r | |
| timeout-minutes: 45 | |
| with: | |
| r-version: ${{ env.ACTION_R_VERSION }} | |
| - name: "📦 Install R Packages" | |
| uses: r-lib/actions/setup-r-dependencies@v2 | |
| timeout-minutes: 20 | |
| with: | |
| cache: 'true' | |
| cache-version: '1' | |
| extra-packages: | | |
| any::dplyr | |
| any::readr | |
| - name: "📦 Install Node Dependencies" | |
| # the sync below runs through ts-node, so the dependencies have to be there before it | |
| run: npm ci | |
| - name: "💾 Cache the Signature Database Bundles" | |
| uses: actions/cache@v4 | |
| with: | |
| # only the bundles, the shards unpacked next to them are re-derived on demand | |
| path: ~/.cache/flowr/sigdb/bundles | |
| key: sigdb-bundles-${{ hashFiles('src/data/sigdb/sigdb.remote.json') }} | |
| - name: "⬇️ Sync the Signature Database" | |
| # the signature browser is built from it; without the shards it is skipped and the page 404s | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: npm run sync:sigdb | |
| - name: "🛠️ Build the documentation" | |
| run: bash .github/workflows/scripts/run-flowr-command.sh doc | |
| - name: "⬆️ Push New Documentation" | |
| run: git push --force origin HEAD:gh-pages |