diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index 747fc913..3d10552a 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -1,24 +1,15 @@ -name: Setup node -description: Local node setup for runners +name: Set up Node.js +description: Install Node.js and the project's npm dependencies runs: - using: "composite" + using: composite steps: - - name: Cache npm and node_modules - uses: actions/cache@v6 - with: - path: | - ~/.npm - node_modules - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm- + - name: Set up Node.js + uses: actions/setup-node@v7 + with: + node-version: "24" + cache: npm - - name: Set up Node.js - uses: actions/setup-node@v7 - with: - node-version: '24' - - - name: Install dependencies - shell: bash - run: npm install + - name: Install dependencies + shell: bash + run: npm ci diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d8a1e837..943315bb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,16 +1,33 @@ version: 2 updates: - - package-ecosystem: "docker" - directory: "/" + - package-ecosystem: npm + directory: / schedule: - interval: "daily" + interval: weekly + groups: + npm: + patterns: ["*"] - - package-ecosystem: "bundler" - directory: "/" + - package-ecosystem: bundler + directory: / schedule: - interval: "daily" + interval: weekly + groups: + bundler: + patterns: ["*"] - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: docker + directory: / schedule: - interval: "daily" + interval: weekly + groups: + docker: + patterns: ["*"] + + - package-ecosystem: github-actions + directories: ["/", "/.github/actions/*"] + schedule: + interval: weekly + groups: + github-actions: + patterns: ["*"] diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 06d70f8e..e7a6b3a4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,52 +1,40 @@ -name: "CodeQL" +name: CodeQL on: push: - branches: [ "main" ] + branches: [main] pull_request: - branches: [ "main" ] + branches: [main] schedule: - - cron: '39 7 * * 6' + - cron: "39 7 * * 6" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: - actions: read contents: read security-events: write - strategy: fail-fast: false matrix: - language: [ 'javascript', 'ruby' ] - + language: [actions, javascript] steps: - - name: Checkout repository - uses: actions/checkout@v7 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + - name: Checkout repository + uses: actions/checkout@v7 - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: none - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/pr-auto-label.yml b/.github/workflows/pr-auto-label.yml deleted file mode 100644 index 296b7aaa..00000000 --- a/.github/workflows/pr-auto-label.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: "Automatically mark PRs to sync" - -on: - pull_request: - types: - - opened - -jobs: - labeler: - if: github.repository == github.event.pull_request.head.repo.full_name && github.event.pull_request.user.type != 'Bot' - permissions: - pull-requests: write - - runs-on: ubuntu-latest - steps: - - name: Add "sync" label to PR - run: gh pr edit "$PR_URL" --add-label sync --repo "$PR_REPO" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} - PR_REPO: ${{ github.repository }} - - - name: Comment on PR to explain sync label - run: gh pr comment "$PR_URL" --body "This pull request has been marked to **automatically sync** to its base branch. You can **disable** this behavior by removing the `sync` label." --repo "$PR_REPO" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} - PR_REPO: ${{ github.repository }} diff --git a/.github/workflows/pr-auto-merge.yml b/.github/workflows/pr-auto-merge.yml deleted file mode 100644 index 1773d84f..00000000 --- a/.github/workflows/pr-auto-merge.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: "Automatically enable auto-merge on PRs" - -on: - pull_request_target: - types: - - opened - - ready_for_review - branches: - - main - -jobs: - enable-automerge: - if: github.event.pull_request.draft == false - permissions: - pull-requests: write - - runs-on: ubuntu-latest - steps: - - name: Enable auto-merge for the PR - run: gh pr merge "$PR_URL" --auto --squash - env: - GH_TOKEN: ${{ secrets.PR_AUTO_UPDATE_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/pr-auto-setup.yml b/.github/workflows/pr-auto-setup.yml new file mode 100644 index 00000000..d27402d2 --- /dev/null +++ b/.github/workflows/pr-auto-setup.yml @@ -0,0 +1,37 @@ +name: PR auto-setup + +on: + pull_request_target: + types: [opened, ready_for_review] + branches: [main] + +permissions: {} + +jobs: + pr-auto-setup: + name: Label and enable auto-merge + runs-on: ubuntu-latest + steps: + - name: Generate App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ vars.PR_AUTO_UPDATE_CLIENT_ID }} + private-key: ${{ secrets.PR_AUTO_UPDATE_PRIVATE_KEY }} + + - name: Add sync label + if: >- + github.event.action == 'opened' + && github.event.pull_request.head.repo.full_name == github.repository + && github.event.pull_request.user.type != 'Bot' + run: gh pr edit "$PR_URL" --add-label sync + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + PR_URL: ${{ github.event.pull_request.html_url }} + + - name: Enable auto-merge + if: ${{ !github.event.pull_request.draft }} + run: gh pr merge "$PR_URL" --auto --squash + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + PR_URL: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/pr-auto-update.yml b/.github/workflows/pr-auto-update.yml index d063aa10..ee8f4a52 100644 --- a/.github/workflows/pr-auto-update.yml +++ b/.github/workflows/pr-auto-update.yml @@ -1,27 +1,33 @@ -name: pr-auto-update +name: PR auto-update + on: - push: {} + push: + branches: [main] + +permissions: {} + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false jobs: pr-auto-update: - name: Automatic PR Updater + name: Update PRs labelled sync runs-on: ubuntu-latest if: github.repository == 'CSSUoB/cssuob.github.io' && github.actor != 'dependabot[bot]' - permissions: - pull-requests: write - contents: write steps: - - name: Generate Access Token + - name: Generate App token + id: app-token uses: actions/create-github-app-token@v3 - id: generate-token with: - app-id: ${{ vars.PR_AUTO_UPDATE_CLIENT_ID }} + client-id: ${{ vars.PR_AUTO_UPDATE_CLIENT_ID }} private-key: ${{ secrets.PR_AUTO_UPDATE_PRIVATE_KEY }} - - uses: CSSUoB/pr-auto-updater@v4.0.0 + - name: Update PRs labelled sync + uses: CSSUoB/pr-auto-updater@v5.0.0 env: - GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} - PR_FILTER: 'labelled' - PR_LABELS: 'sync' - MERGE_CONFLICT_ACTION: 'label' - MERGE_CONFLICT_LABEL: 'conflict' + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + PR_FILTER: labelled + PR_LABELS: sync + MERGE_CONFLICT_ACTION: label + MERGE_CONFLICT_LABEL: conflict diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 00000000..6430e39c --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,47 @@ +name: Static analysis + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + static-analysis: + name: Format, lint and spellcheck + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v7 + with: + fetch-depth: 2 + + - name: Set up Node.js + uses: ./.github/actions/setup-node + + - name: Check formatting + if: ${{ !cancelled() }} + run: npm run format + + - name: Lint JavaScript + if: ${{ !cancelled() }} + run: npm run lint:js + + - name: Lint Markdown + if: ${{ !cancelled() }} + run: npm run lint:md + + - name: Spellcheck changed files + if: ${{ !cancelled() }} + continue-on-error: true + run: | + git diff --name-only --diff-filter=d HEAD^ HEAD -- '*.md' '*.html' \ + | npx cspell --file-list stdin --no-must-find-files --no-progress \ + --issue-template '::warning file=$filename,line=$row,col=$col::Unknown word: $text' diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml deleted file mode 100644 index 2f66a8f9..00000000 --- a/.github/workflows/static_analysis.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Static analysis - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - format: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/setup-node - - - name: Run prettier - run: npx prettier --check . - - spellcheck: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/setup-node - - - name: Get changed files - id: changed-files - uses: tj-actions/changed-files@v47 - with: - files: | - **.md - **.html - - - name: Run cspell on changed files - id: run-cspell - continue-on-error: true - env: - ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: npx cspell --files $ALL_CHANGED_FILES - - - name: Report spellcheck failures - if: steps.run-cspell.outcome != 'success' - run: echo "::notice::Spellcheck found issues in some or all modified files" - - lint-js: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/setup-node - - - name: Run eslint - run: npx eslint - - lint-markdown: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/setup-node - - - name: Run markdownlint - run: npx markdownlint -c '.markdownlint.jsonc' -p '.gitignore' . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d128042a..054e9ac3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -132,6 +132,12 @@ Fix HTTP 418 error when navigating to /ball Once you have made your changes, please describe them in your pull request in full. We will then review them and communicate with you on GitHub. We may ask you to change a few things so please do check GitHub or your emails frequently. +When you open a pull request against `main`, a bot sets it up for you: + +* Auto-merge is turned on, so your pull request is squash-merged as soon as it has been approved. For draft pull requests, this happens when you mark it as ready for review. +* If your branch is in this repository rather than a fork, the `sync` label is added. While the label is there, your branch is updated automatically whenever `main` changes. Remove the label if you would rather update your branch yourself. +* If an automatic update hits a merge conflict, the `conflict` label is added and you will need to resolve the conflict yourself. + After that, that's it! You've made your first contribution to CSS' website. 🎉 ## Guidance diff --git a/dependabot.yml b/dependabot.yml deleted file mode 100644 index 1c9063d0..00000000 --- a/dependabot.yml +++ /dev/null @@ -1,18 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "bundler" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" - - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "weekly" - - diff --git a/package.json b/package.json index 1707aede..4bf6d031 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,13 @@ "prettier": "3.2.5" }, "scripts": { - "lint": "npx eslint && npx markdownlint-cli -c .markdownlint.jsonc -p .gitignore .", - "lint:fix": "npx eslint --fix && npx markdownlint-cli -c .markdownlint.jsonc -p .gitignore --fix .", - "format": "npx prettier --check .", - "format:fix": "npx prettier --write .", - "spellcheck": "npx cspell --gitignore '**/*.{md,html}'", - "spellcheck:staged": "git diff HEAD --name-only | grep -E '.md|.html' | npx cspell --file-list stdin" + "lint": "npm run lint:js && npm run lint:md", + "lint:js": "eslint", + "lint:md": "markdownlint -c .markdownlint.jsonc -p .gitignore .", + "lint:fix": "eslint --fix && markdownlint -c .markdownlint.jsonc -p .gitignore --fix .", + "format": "prettier --check .", + "format:fix": "prettier --write .", + "spellcheck": "cspell --gitignore '**/*.{md,html}'", + "spellcheck:staged": "git diff HEAD --name-only --diff-filter=d -- '*.md' '*.html' | cspell --file-list stdin --no-must-find-files" } }