diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..9b0002d --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,113 @@ +# CI for the Coffey Labs build of Mastodon: upstream Mastodon plus the +# coffeylabs theme (COFFEYLABS.md). Upstream's own .github/workflows were +# removed in this fork; this is the only workflow, and it runs on Gitea only. +# +# Every change builds the image without pushing it, to prove the theme still +# compiles against the upstream it sits on. Releases are cut by pushing a tag +# named v-coffeylabs., e.g. v4.7.3-coffeylabs.1, where +# is the version in lib/mastodon/version.rb. The tag must name the commit's +# own upstream version and be on main, or nothing is published. +# +# Every job runs in an image pinned by digest (tag in the trailing comment), +# and the only action used is coffey-labs/actions/checkout pinned by SHA. +# Read the comment for the version; the digest is what runs. +name: ci + +on: + push: + branches: [main] + tags: ['v*-coffeylabs.*'] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # ------------------------------------------------------------- build ------ + # The full production image, as the Dockerfile builds it: Ruby gems, the + # Vite asset build with both themes, libvips and ffmpeg. Nothing is pushed. + docker-build: + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + runs-on: docker + timeout-minutes: 90 + container: + image: docker:28-cli@sha256:625d9431a9f54c5a2bc90f24f0e1c3d55b1349fd857dd85035f98c2c9acbdd4d # 28-cli + volumes: + - /var/run/docker.sock:/var/run/docker.sock + steps: + - uses: coffey-labs/actions/checkout@fab0c4d45e0162963965f1555df27b7bed5e20ec + - run: | + tag="mastodon:ci-$(echo "$GITHUB_SHA" | cut -c1-8)" + docker build --build-arg MASTODON_VERSION_METADATA=coffeylabs.ci -t "$tag" . + docker run --rm --entrypoint sh "$tag" -c \ + 'ls public/packs/assets/themes/ | grep -q "^coffeylabs-.*\.css$"' \ + || { echo "!! the image has no compiled coffeylabs theme" >&2; exit 1; } + docker image rm "$tag" + + # ----------------------------------------------------------- release ------ + # linux/amd64 only: the one server that runs it is amd64. The streaming + # server is unchanged by the theme, so it keeps using upstream's image at + # the same version. PACKAGE_TOKEN (jcoffey-dev, write:package) logs in: the + # job's own token is refused by the container registry. The release is + # created last, so a release on the page always has its image behind it. + publish: + if: ${{ startsWith(github.ref, 'refs/tags/v') }} + runs-on: docker + timeout-minutes: 90 + container: + image: docker:28-cli@sha256:625d9431a9f54c5a2bc90f24f0e1c3d55b1349fd857dd85035f98c2c9acbdd4d # 28-cli + volumes: + - /var/run/docker.sock:/var/run/docker.sock + env: + REGISTRY: ${{ vars.REGISTRY }} + IMAGE: ${{ vars.REGISTRY }}/${{ github.repository }} + TAG: ${{ github.ref_name }} + PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }} + steps: + - uses: coffey-labs/actions/checkout@fab0c4d45e0162963965f1555df27b7bed5e20ec + with: + fetch-depth: 0 + - id: v + run: | + set -eu + upstream="$(awk '/def (major|minor|patch)$/ { getline; gsub(/ /, ""); printf "%s%s", sep, $0; sep="." }' lib/mastodon/version.rb)" + case "$TAG" in + "v$upstream-coffeylabs."[0-9]*) ;; + *) echo "!! $TAG does not name this commit's upstream version; expected v$upstream-coffeylabs." >&2; exit 1 ;; + esac + git merge-base --is-ancestor "$(git rev-parse "${TAG}^{commit}")" origin/main \ + || { echo "!! $TAG is not on main" >&2; exit 1; } + echo "METADATA=${TAG#v"$upstream"-}" >> "$GITHUB_OUTPUT" + - run: | + test -n "$REGISTRY" + test -n "$PACKAGE_TOKEN" || { echo "PACKAGE_TOKEN secret is not set on this repository" >&2; exit 1; } + echo "$PACKAGE_TOKEN" | docker login -u jcoffey-dev --password-stdin "$REGISTRY" + - env: + METADATA: ${{ steps.v.outputs.METADATA }} + run: | + docker build \ + --build-arg MASTODON_VERSION_METADATA="$METADATA" \ + --build-arg SOURCE_COMMIT="$GITHUB_SHA" \ + --build-arg SOURCE_BASE_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" \ + --build-arg SOURCE_TAG="$TAG" \ + --tag "$IMAGE:$TAG" . + docker push "$IMAGE:$TAG" + docker image rm "$IMAGE:$TAG" + # Show the package on the repository's Packages tab. Idempotent. + - run: | + apk add --no-cache -q curl + curl -fsS -o /dev/null -X POST -H "Authorization: token $PACKAGE_TOKEN" \ + "$CI_SERVER_INTERNAL/api/v1/packages/${GITHUB_REPOSITORY%%/*}/container/${GITHUB_REPOSITORY#*/}/-/link/${GITHUB_REPOSITORY#*/}" \ + || echo "package already linked (or link refused); not fatal" + - env: + TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eu + body="Mastodon ${TAG%-coffeylabs.*} with the coffeylabs theme.\n\nImage: \`$IMAGE:$TAG\` (linux/amd64). Use upstream's mastodon-streaming image at ${TAG%-coffeylabs.*}." + curl -fsS -o /dev/null -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ + --data "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\",\"body\":\"$body\"}" \ + "$CI_SERVER_INTERNAL/api/v1/repos/$GITHUB_REPOSITORY/releases" + echo "release $TAG created" + - if: always() + run: docker logout "$REGISTRY" || true diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml deleted file mode 100644 index 7924655..0000000 --- a/.github/workflows/build-container-image.yml +++ /dev/null @@ -1,171 +0,0 @@ -on: - workflow_call: - inputs: - cache: - type: boolean - default: true - push_to_images: - type: string - version_prerelease: - type: string - version_metadata: - type: string - flavor: - type: string - tags: - type: string - labels: - type: string - file_to_build: - type: string - -# This builds multiple images with one runner each, allowing us to build for multiple architectures -# using Github's runners. -# The two-step process is adapted form: -# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners -jobs: - # Build each (amd64 and arm64) image separately - build-image: - runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} - strategy: - fail-fast: false - matrix: - platform: - - linux/amd64 - - linux/arm64 - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Prepare - env: - PUSH_TO_IMAGES: ${{ inputs.push_to_images }} - run: | - platform=${{ matrix.platform }} - echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - # Transform multi-line variable into comma-separated variable - image_names=${PUSH_TO_IMAGES//$'\n'/,} - image_names_split=${image_names%,} - echo "IMAGE_NAMES=${image_names_split,,}" >> $GITHUB_ENV - - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - id: buildx - - - name: Log in to Docker Hub - if: contains(inputs.push_to_images, 'tootsuite') - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Log in to the GitHub Container registry - if: contains(inputs.push_to_images, 'ghcr.io') - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Docker meta - id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 - if: ${{ inputs.push_to_images != '' }} - with: - images: ${{ inputs.push_to_images }} - flavor: ${{ inputs.flavor }} - labels: ${{ inputs.labels }} - - - name: Build and push by digest - id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 - with: - context: . - file: ${{ inputs.file_to_build }} - build-args: | - MASTODON_VERSION_PRERELEASE=${{ inputs.version_prerelease }} - MASTODON_VERSION_METADATA=${{ inputs.version_metadata }} - SOURCE_COMMIT=${{ github.sha }} - platforms: ${{ matrix.platform }} - provenance: false - push: ${{ inputs.push_to_images != '' }} - cache-from: ${{ inputs.cache && format('type=gha,scope=build-{0}-{1}', hashFiles(inputs.file_to_build), env.PLATFORM_PAIR) || '' }} - cache-to: ${{ inputs.cache && format('type=gha,mode=max,scope=build-{0}-{1}', hashFiles(inputs.file_to_build), env.PLATFORM_PAIR) || '' }} - outputs: type=image,"name=${{ env.IMAGE_NAMES }}",push-by-digest=true,name-canonical=true,push=${{ inputs.push_to_images != '' }} - - - name: Export digest - if: ${{ inputs.push_to_images != '' }} - run: | - mkdir -p "${{ runner.temp }}/digests" - digest="${{ steps.build.outputs.digest }}" - touch "${{ runner.temp }}/digests/${digest#sha256:}" - - - name: Upload digest - if: ${{ inputs.push_to_images != '' }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - # `hashFiles` is used to disambiguate between streaming and non-streaming images - name: digests-${{ hashFiles(inputs.file_to_build) }}-${{ env.PLATFORM_PAIR }} - path: ${{ runner.temp }}/digests/* - if-no-files-found: error - retention-days: 1 - - # Then merge the docker images into a single one - merge-images: - if: ${{ inputs.push_to_images != '' }} - runs-on: ubuntu-24.04 - needs: - - build-image - - env: - PUSH_TO_IMAGES: ${{ inputs.push_to_images }} - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Download digests - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - path: ${{ runner.temp }}/digests - # `hashFiles` is used to disambiguate between streaming and non-streaming images - pattern: digests-${{ hashFiles(inputs.file_to_build) }}-* - merge-multiple: true - - - name: Log in to Docker Hub - if: contains(inputs.push_to_images, 'tootsuite') - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Log in to the GitHub Container registry - if: contains(inputs.push_to_images, 'ghcr.io') - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - - - name: Docker meta - id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 - if: ${{ inputs.push_to_images != '' }} - with: - images: ${{ inputs.push_to_images }} - flavor: ${{ inputs.flavor }} - tags: ${{ inputs.tags }} - labels: ${{ inputs.labels }} - - - name: Create manifest list and push - working-directory: ${{ runner.temp }}/digests - run: | - echo "${PUSH_TO_IMAGES,,}" | xargs -I{} \ - docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '{}@sha256:%s ' *) - - - name: Inspect image - run: | - echo "${PUSH_TO_IMAGES,,}" | xargs -i{} \ - docker buildx imagetools inspect {}:${{ steps.meta.outputs.version }} diff --git a/.github/workflows/build-nightly.yml b/.github/workflows/build-nightly.yml deleted file mode 100644 index 4a56f72..0000000 --- a/.github/workflows/build-nightly.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Build nightly container image -on: - workflow_dispatch: - schedule: - - cron: '0 2 * * *' # run at 2 AM UTC - -permissions: - contents: read - packages: write - -jobs: - compute-suffix: - runs-on: ubuntu-latest - if: github.repository == 'mastodon/mastodon' - steps: - - id: version_vars - env: - TZ: Etc/UTC - run: | - echo mastodon_version_prerelease=nightly.$(date +'%Y-%m-%d')>> $GITHUB_OUTPUT - outputs: - prerelease: ${{ steps.version_vars.outputs.mastodon_version_prerelease }} - - build-image: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: Dockerfile - cache: false - push_to_images: | - tootsuite/mastodon - ghcr.io/mastodon/mastodon - version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }} - labels: | - org.opencontainers.image.description=Nightly build image used for testing purposes - flavor: | - latest=auto - tags: | - type=raw,value=edge - type=raw,value=nightly - type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }} - secrets: inherit - - build-image-streaming: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: streaming/Dockerfile - cache: false - push_to_images: | - tootsuite/mastodon-streaming - ghcr.io/mastodon/mastodon-streaming - version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }} - labels: | - org.opencontainers.image.description=Nightly build image used for testing purposes - flavor: | - latest=auto - tags: | - type=raw,value=edge - type=raw,value=nightly - type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }} - secrets: inherit diff --git a/.github/workflows/build-push-pr.yml b/.github/workflows/build-push-pr.yml deleted file mode 100644 index f55012b..0000000 --- a/.github/workflows/build-push-pr.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Build container image for PR -on: - pull_request: - types: [labeled, synchronize, reopened, ready_for_review, opened] - -permissions: - contents: read - packages: write - -jobs: - compute-suffix: - runs-on: ubuntu-latest - # This is only allowed to run if: - # - the PR branch is in the `mastodon/mastodon` repository - # - the PR is not a draft - # - the PR has the "build-image" label - if: ${{ github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.draft && contains(github.event.pull_request.labels.*.name, 'build-image') }} - steps: - # Repository needs to be cloned so `git rev-parse` below works - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - id: version_vars - run: | - echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT - echo mastodon_short_sha=$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT - outputs: - metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }} - short_sha: ${{ steps.version_vars.outputs.mastodon_short_sha }} - - build-image: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: Dockerfile - push_to_images: | - ghcr.io/mastodon/mastodon - version_metadata: ${{ needs.compute-suffix.outputs.metadata }} - flavor: | - latest=auto - tags: | - type=ref,event=pr - type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }} - secrets: inherit - - build-image-streaming: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: streaming/Dockerfile - push_to_images: | - ghcr.io/mastodon/mastodon-streaming - version_metadata: ${{ needs.compute-suffix.outputs.metadata }} - flavor: | - latest=auto - tags: | - type=ref,event=pr - type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }} - secrets: inherit diff --git a/.github/workflows/build-releases.yml b/.github/workflows/build-releases.yml deleted file mode 100644 index c8e0925..0000000 --- a/.github/workflows/build-releases.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Build container release images -on: - push: - tags: - - '*' - -permissions: - contents: read - packages: write - -jobs: - check-latest-stable: - runs-on: ubuntu-latest - outputs: - latest: ${{ steps.check.outputs.is_latest_stable }} - steps: - # Repository needs to be cloned to list branches - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - with: - fetch-depth: 0 - - - name: Check latest stable - shell: bash - id: check - run: | - ref="${GITHUB_REF#refs/tags/}" - - if [[ "$ref" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?$ ]]; then - current="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" - else - echo "tag $ref is not semver" - echo "is_latest_stable=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - latest=$(git for-each-ref --format='%(refname:short)' "refs/remotes/origin/stable-*.*" \ - | sed -E 's#^origin/stable-##' \ - | sort -Vr \ - | head -n1) - - if [[ "$current" == "$latest" ]]; then - echo "is_latest_stable=true" >> "$GITHUB_OUTPUT" - else - echo "is_latest_stable=false" >> "$GITHUB_OUTPUT" - fi - - build-image: - needs: check-latest-stable - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: Dockerfile - push_to_images: | - tootsuite/mastodon - ghcr.io/mastodon/mastodon - # Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages - cache: false - # Only tag with latest when ran against the latest stable branch - # This needs to be updated after each minor version release - flavor: | - latest=${{ needs.check-latest-stable.outputs.latest }} - tags: | - type=pep440,pattern={{raw}} - type=pep440,pattern=v{{major}}.{{minor}} - secrets: inherit - - build-image-streaming: - needs: check-latest-stable - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: streaming/Dockerfile - push_to_images: | - tootsuite/mastodon-streaming - ghcr.io/mastodon/mastodon-streaming - # Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages - cache: false - # Only tag with latest when ran against the latest stable branch - # This needs to be updated after each minor version release - flavor: | - latest=${{ needs.check-latest-stable.outputs.latest }} - tags: | - type=pep440,pattern={{raw}} - type=pep440,pattern=v{{major}}.{{minor}} - secrets: inherit diff --git a/.github/workflows/build-security.yml b/.github/workflows/build-security.yml deleted file mode 100644 index 72729b5..0000000 --- a/.github/workflows/build-security.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Build security nightly container image -on: - workflow_dispatch: - -permissions: - contents: read - packages: write - -jobs: - compute-suffix: - runs-on: ubuntu-latest - steps: - - id: version_vars - env: - TZ: Etc/UTC - run: | - echo mastodon_version_prerelease=nightly.$(date --date='next day' +'%Y-%m-%d')-security>> $GITHUB_OUTPUT - outputs: - prerelease: ${{ steps.version_vars.outputs.mastodon_version_prerelease }} - - build-image: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: Dockerfile - cache: false - push_to_images: | - tootsuite/mastodon - ghcr.io/mastodon/mastodon - version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }} - labels: | - org.opencontainers.image.description=Nightly build image used for testing purposes - flavor: | - latest=auto - tags: | - type=raw,value=edge - type=raw,value=nightly - type=raw,value=${{ needs.compute-suffix.outputs.prerelease }} - secrets: inherit - - build-image-streaming: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: streaming/Dockerfile - cache: false - push_to_images: | - tootsuite/mastodon-streaming - ghcr.io/mastodon/mastodon-streaming - version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }} - labels: | - org.opencontainers.image.description=Nightly build image used for testing purposes - flavor: | - latest=auto - tags: | - type=raw,value=edge - type=raw,value=nightly - type=raw,value=${{ needs.compute-suffix.outputs.prerelease }} - secrets: inherit diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml deleted file mode 100644 index b51f792..0000000 --- a/.github/workflows/bundler-audit.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Bundler Audit -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - 'Gemfile*' - - '.ruby-version' - - '.github/workflows/bundler-audit.yml' - - pull_request: - paths: - - 'Gemfile*' - - '.ruby-version' - - '.github/workflows/bundler-audit.yml' - - schedule: - - cron: '0 5 * * 1' - -jobs: - security: - runs-on: ubuntu-latest - timeout-minutes: 15 - - env: - BUNDLE_ONLY: development - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Ruby - uses: ruby/setup-ruby@6e5d382445ae5590b7449d8b3bc8cb1c2c27f617 # v1 - with: - bundler-cache: true - - - name: Run bundler-audit - run: bin/bundler-audit check --update diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml deleted file mode 100644 index bd77ec5..0000000 --- a/.github/workflows/check-i18n.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Check i18n - -on: - push: - branches: - - 'main' - - 'stable-*' - pull_request: - branches: - - 'main' - - 'stable-*' - -env: - RAILS_ENV: test - -permissions: - contents: read - -jobs: - check-i18n: - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: Check for missing strings in English JSON - run: | - yarn i18n:extract --throws - git diff --exit-code - - - name: Check locale file normalization - run: bin/i18n-tasks check-normalized - - - name: Check for unused strings - run: bin/i18n-tasks unused -l en - - - name: Check for missing strings in English YML - run: | - bin/i18n-tasks missing -t used -l en - - - name: Check for wrong string interpolations - run: bin/i18n-tasks check-consistent-interpolations - - - name: Check that all required locale files exist - run: bin/rake repo:check_locales_files diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml deleted file mode 100644 index 0068fc2..0000000 --- a/.github/workflows/chromatic.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: 'Chromatic' -permissions: - contents: read - -on: - push: - branches-ignore: - - renovate/* - - stable-* - -jobs: - pathcheck: - name: Check for relevant changes - runs-on: ubuntu-latest - timeout-minutes: 15 - outputs: - changed: ${{ steps.filter.outputs.src }} - steps: - - name: Checkout code - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - with: - fetch-depth: 0 - - - uses: dorny/paths-filter@0e4a8c6effa4802afeda77dc8d303f8176d7dfad # v3 - id: filter - with: - filters: | - src: - - 'package.json' - - 'yarn.lock' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '**/*.css' - - '**/*.scss' - - '.github/workflows/chromatic.yml' - - chromatic: - name: Run Chromatic - runs-on: ubuntu-latest - timeout-minutes: 15 - needs: pathcheck - if: github.repository == 'mastodon/mastodon' && needs.pathcheck.outputs.changed == 'true' - steps: - - name: Checkout code - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - with: - fetch-depth: 0 - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: Build Storybook - run: yarn build-storybook - - - name: Run Chromatic - uses: chromaui/action@98132da0fca2211fb41b3af7b49ce85176007851 # v17 - with: - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - zip: true - storybookBuildDir: 'storybook-static' - exitOnceUploaded: true # Exit immediately after upload - autoAcceptChanges: 'main' # Auto-accept changes on main branch only diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index fea0b46..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: 'CodeQL' - -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - pull_request: - branches: - - 'main' - - 'stable-*' - schedule: - - cron: '22 6 * * 1' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - timeout-minutes: 15 - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ['actions', 'javascript', 'ruby'] - # CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, 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@5595ccaf912efad79be6eef63a5619ff05969be3 # 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. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4 - with: - category: '/language:${{matrix.language}}' diff --git a/.github/workflows/crowdin-download-stable.yml b/.github/workflows/crowdin-download-stable.yml deleted file mode 100644 index 2eef46f..0000000 --- a/.github/workflows/crowdin-download-stable.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Crowdin / Download translations (stable branches) -on: - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - download-translations-stable: - runs-on: ubuntu-latest - if: github.repository == 'mastodon/mastodon' - - steps: - - name: Checkout - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Increase Git http.postBuffer - # This is needed due to a bug in Ubuntu's cURL version? - # See https://github.com/orgs/community/discussions/55820 - run: | - git config --global http.version HTTP/1.1 - git config --global http.postBuffer 157286400 - - # Download the translation files from Crowdin - - name: crowdin action - uses: crowdin/github-action@c7af9bc98b01694653031fef2a0dc6c7888ce9bc # v2 - with: - upload_sources: false - upload_translations: false - download_translations: true - crowdin_branch_name: ${{ github.base_ref || github.ref_name }} - push_translations: false - create_pull_request: false - env: - CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - # As the files are extracted from a Docker container, they belong to root:root - # We need to fix this before the next steps - - name: Fix file permissions - run: sudo chown -R runner:docker . - - # This is needed to run the normalize step - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Run i18n normalize task - run: bin/i18n-tasks normalize - - # Create or update the pull request - - name: Create Pull Request - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 - with: - commit-message: 'New Crowdin translations' - title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)' - author: 'GitHub Actions ' - body: | - New Crowdin translations, automated with GitHub Actions - - See `.github/workflows/crowdin-download.yml` - - This PR will be updated every day with new translations. - - Due to a limitation in GitHub Actions, checks are not running on this PR without manual action. - If you want to run the checks, then please press “Approve workflows to run”. - branch: i18n/crowdin/translations-${{ github.base_ref || github.ref_name }} - base: ${{ github.base_ref || github.ref_name }} - labels: i18n diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml deleted file mode 100644 index e221fd6..0000000 --- a/.github/workflows/crowdin-download.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Crowdin / Download translations -on: - schedule: - - cron: '17 4 * * *' # Every day - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - download-translations: - runs-on: ubuntu-latest - if: github.repository == 'mastodon/mastodon' - - steps: - - name: Checkout - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Increase Git http.postBuffer - # This is needed due to a bug in Ubuntu's cURL version? - # See https://github.com/orgs/community/discussions/55820 - run: | - git config --global http.version HTTP/1.1 - git config --global http.postBuffer 157286400 - - # Download the translation files from Crowdin - - name: crowdin action - uses: crowdin/github-action@c7af9bc98b01694653031fef2a0dc6c7888ce9bc # v2 - with: - upload_sources: false - upload_translations: false - download_translations: true - crowdin_branch_name: main - push_translations: false - create_pull_request: false - env: - CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - # As the files are extracted from a Docker container, they belong to root:root - # We need to fix this before the next steps - - name: Fix file permissions - run: sudo chown -R runner:docker . - - # This is needed to run the normalize step - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Run i18n normalize task - run: bin/i18n-tasks normalize - - # Create or update the pull request - - name: Create Pull Request - uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8 - with: - commit-message: 'New Crowdin translations' - title: 'New Crowdin Translations (automated)' - author: 'GitHub Actions ' - body: | - New Crowdin translations, automated with GitHub Actions - - See `.github/workflows/crowdin-download.yml` - - This PR will be updated every day with new translations. - - Due to a limitation in GitHub Actions, checks are not running on this PR without manual action. - If you want to run the checks, then please press “Approve workflows to run”. - branch: i18n/crowdin/translations - base: main - labels: i18n diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml deleted file mode 100644 index 08858de..0000000 --- a/.github/workflows/crowdin-upload.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Crowdin / Upload translations - -on: - push: - branches: - - 'main' - - 'stable-*' - paths: - - crowdin.yml - - app/javascript/mastodon/locales/en.json - - config/locales/en.yml - - config/locales/simple_form.en.yml - - config/locales/activerecord.en.yml - - config/locales/devise.en.yml - - config/locales/doorkeeper.en.yml - - .github/workflows/crowdin-upload.yml - workflow_dispatch: - -jobs: - upload-translations: - runs-on: ubuntu-latest - if: github.repository == 'mastodon/mastodon' - - steps: - - name: Checkout - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: crowdin action - uses: crowdin/github-action@c7af9bc98b01694653031fef2a0dc6c7888ce9bc # v2 - with: - upload_sources: true - upload_translations: false - download_translations: false - crowdin_branch_name: ${{ github.base_ref || github.ref_name }} - - env: - CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml deleted file mode 100644 index ee4b262..0000000 --- a/.github/workflows/format-check.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Check formatting -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - pull_request: - -jobs: - lint: - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: Check formatting - run: yarn format:check diff --git a/.github/workflows/lint-css.yml b/.github/workflows/lint-css.yml deleted file mode 100644 index e69fdc1..0000000 --- a/.github/workflows/lint-css.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: CSS Linting -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - 'stylelint.config.js' - - '**/*.css' - - '**/*.scss' - - '.github/workflows/lint-css.yml' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - 'stylelint.config.js' - - '**/*.css' - - '**/*.scss' - - '.github/workflows/lint-css.yml' - -jobs: - lint: - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: Stylelint - run: yarn lint:css --custom-formatter @csstools/stylelint-formatter-github diff --git a/.github/workflows/lint-haml.yml b/.github/workflows/lint-haml.yml deleted file mode 100644 index fdb6cf1..0000000 --- a/.github/workflows/lint-haml.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Haml Linting -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - '.github/workflows/lint-haml.yml' - - '.haml-lint*.yml' - - '.rubocop*.yml' - - '.ruby-version' - - '**/*.haml' - - 'Gemfile*' - - pull_request: - paths: - - '.github/workflows/lint-haml.yml' - - '.haml-lint*.yml' - - '.rubocop*.yml' - - '.ruby-version' - - '**/*.haml' - - 'Gemfile*' - -jobs: - lint: - runs-on: ubuntu-latest - timeout-minutes: 15 - - env: - BUNDLE_ONLY: development - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Ruby - uses: ruby/setup-ruby@6e5d382445ae5590b7449d8b3bc8cb1c2c27f617 # v1 - with: - bundler-cache: true - - - name: Run haml-lint - run: | - bin/haml-lint --reporter github diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml deleted file mode 100644 index 65c3056..0000000 --- a/.github/workflows/lint-js.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: JavaScript Linting -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - 'package.json' - - 'yarn.lock' - - 'tsconfig.json' - - '.nvmrc' - - 'eslint.config.mjs' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '.github/workflows/lint-js.yml' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - 'tsconfig.json' - - '.nvmrc' - - 'eslint.config.mjs' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '.github/workflows/lint-js.yml' - -jobs: - lint: - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: ESLint - run: yarn workspaces foreach --all --parallel run lint:js --max-warnings 0 - - - name: Typecheck - run: yarn typecheck diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml deleted file mode 100644 index 950e502..0000000 --- a/.github/workflows/lint-ruby.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Ruby Linting -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - 'Gemfile*' - - '.rubocop*.yml' - - '.ruby-version' - - 'bin/rubocop' - - '**/*.rb' - - '**/*.rake' - - '.github/workflows/lint-ruby.yml' - - pull_request: - paths: - - 'Gemfile*' - - '.rubocop*.yml' - - '.ruby-version' - - 'bin/rubocop' - - '**/*.rb' - - '**/*.rake' - - '.github/workflows/lint-ruby.yml' - -jobs: - lint: - runs-on: ubuntu-latest - timeout-minutes: 15 - - env: - BUNDLE_ONLY: development - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Ruby - uses: ruby/setup-ruby@6e5d382445ae5590b7449d8b3bc8cb1c2c27f617 # v1 - with: - bundler-cache: true - - - name: Run rubocop - run: bin/rubocop --format github - - - name: Run brakeman - if: always() # Run both checks, even if the first failed - run: bin/brakeman diff --git a/.github/workflows/rebase-needed.yml b/.github/workflows/rebase-needed.yml deleted file mode 100644 index cf594c2..0000000 --- a/.github/workflows/rebase-needed.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: PR Needs Rebase - -on: - schedule: - - cron: '0 * * * *' - -permissions: - pull-requests: write - -jobs: - label-rebase-needed: - runs-on: ubuntu-latest - if: github.repository == 'mastodon/mastodon' - - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - - steps: - - name: Check for merge conflicts - uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3 - with: - dirtyLabel: 'rebase needed :construction:' - repoToken: '${{ secrets.GITHUB_TOKEN }}' - commentOnClean: This pull request has resolved merge conflicts and is ready for review. - commentOnDirty: This pull request has merge conflicts that must be resolved before it can be merged. - retryMax: 30 - continueOnMissingPermissions: false diff --git a/.github/workflows/test-image-build.yml b/.github/workflows/test-image-build.yml deleted file mode 100644 index 121b8b0..0000000 --- a/.github/workflows/test-image-build.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Test container image build -on: - pull_request: - paths: - - .github/workflows/build-nightly.yml - - .github/workflows/build-push-pr.yml - - .github/workflows/build-releases.yml - - .github/workflows/test-image-build.yml - - Dockerfile - - streaming/Dockerfile - - .dockerignore -permissions: - contents: read - -jobs: - build-image: - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: Dockerfile - cache: true - - build-image-streaming: - concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-streaming - cancel-in-progress: true - - uses: ./.github/workflows/build-container-image.yml - with: - file_to_build: streaming/Dockerfile - cache: true diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml deleted file mode 100644 index 5a3c578..0000000 --- a/.github/workflows/test-js.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: JavaScript Testing -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '**/*.snap' - - '.github/workflows/test-js.yml' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '**/*.snap' - - '.github/workflows/test-js.yml' - -jobs: - test: - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Clone repository - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: JavaScript testing - run: yarn test:js diff --git a/.github/workflows/test-migrations.yml b/.github/workflows/test-migrations.yml deleted file mode 100644 index 79268f3..0000000 --- a/.github/workflows/test-migrations.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Historical data migration test - -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - paths: - - 'Gemfile*' - - '.ruby-version' - - '**/*.rb' - - '.github/workflows/test-migrations.yml' - - 'lib/tasks/tests.rake' - - 'lib/tasks/db.rake' - - pull_request: - paths: - - 'Gemfile*' - - '.ruby-version' - - '**/*.rb' - - '.github/workflows/test-migrations.yml' - - 'lib/tasks/tests.rake' - -jobs: - test: - runs-on: ubuntu-latest - timeout-minutes: 15 - - strategy: - fail-fast: false - - matrix: - postgres: - - 14-alpine - - 15-alpine - - 16-alpine - - 17-alpine - - services: - postgres: - image: postgres:${{ matrix.postgres}} - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 6379:6379 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - RAILS_ENV: test - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development:production' - BUNDLE_JOBS: 3 - BUNDLE_RETRY: 3 - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Ensure no errors with `db:prepare` - run: | - bin/rails db:drop - bin/rails db:prepare - bin/rails db:migrate - - - name: Ensure no errors with `db:prepare` and SKIP_POST_DEPLOYMENT_MIGRATIONS - run: | - bin/rails db:drop - SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails db:prepare - bin/rails db:migrate - - - name: Test "one step migration" flow - run: | - bin/rails db:drop - bin/rails db:create - bin/rails tests:migrations:prepare_database - bin/rails db:migrate - bin/rails tests:migrations:check_database - - - name: Test "two step migration" flow - run: | - bin/rails db:drop - bin/rails db:create - SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails tests:migrations:prepare_database - - # Migrate up to v4.3.0 breakpoint - bin/rails db:migrate VERSION=20241007071624 - - # Migrate the rest - SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails db:migrate - bin/rails db:migrate - bin/rails tests:migrations:check_database diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml deleted file mode 100644 index 117d6df..0000000 --- a/.github/workflows/test-ruby.yml +++ /dev/null @@ -1,390 +0,0 @@ -name: Ruby Testing - -on: - merge_group: - push: - branches: - - 'main' - - 'stable-*' - pull_request: - -env: - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - name: build (production) - runs-on: ubuntu-latest - timeout-minutes: 15 - - env: - RAILS_ENV: production - BUNDLE_WITH: production - SECRET_KEY_BASE_DUMMY: 1 - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - with: - onlyProduction: 'true' - - - name: Cache assets from compilation - uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 - with: - path: | - public/assets - public/packs - public/packs-test - tmp/cache/vite - key: assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }} - restore-keys: | - assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }} - assets-${{ github.head_ref || github.ref_name }} - assets-main - assets - - - name: Precompile assets - run: |- - bin/rails assets:precompile - - - name: Archive asset artifacts - run: | - tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs* - - - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - path: |- - ./artifacts.tar.gz - name: ${{ github.sha }} - retention-days: 0 - - test: - runs-on: ubuntu-latest - timeout-minutes: 60 - - needs: - - build - - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 6379:6379 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - COVERAGE: ${{ matrix.ruby-version == '.ruby-version' }} - RAILS_ENV: test - ALLOW_NOPAM: true - PAM_ENABLED: true - PAM_DEFAULT_SERVICE: pam_test - PAM_CONTROLLED_SERVICE: pam_test_controlled - OIDC_ENABLED: true - OIDC_SCOPE: read - SAML_ENABLED: true - CAS_ENABLED: true - BUNDLE_WITH: 'pam_authentication test' - GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }} - - strategy: - fail-fast: false - matrix: - ruby-version: - - '3.3' - - '3.4' - - '.ruby-version' - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - path: './' - name: ${{ github.sha }} - - - name: Expand archived asset artifacts - run: | - tar xvzf artifacts.tar.gz - - - name: Set up Ruby environment - timeout-minutes: 15 - uses: ./.github/actions/setup-ruby - with: - ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg libpam-dev - - - name: Load database schema - run: | - bin/rails db:setup - bin/flatware fan bin/rails db:test:prepare - - - name: Cache RSpec persistence file - uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 - with: - path: | - tmp/rspec/examples.txt - key: rspec-persistence-${{ github.head_ref || github.ref_name }}-${{ github.sha }} - restore-keys: | - rspec-persistence-${{ github.head_ref || github.ref_name }}-${{ github.sha }}-${{ matrix.ruby-version }} - rspec-persistence-${{ github.head_ref || github.ref_name }}-${{ github.sha }} - rspec-persistence-${{ github.head_ref || github.ref_name }} - rspec-persistence-main - rspec-persistence - - - run: bin/flatware rspec - - - name: Upload coverage reports to Codecov - if: matrix.ruby-version == '.ruby-version' - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6 - with: - files: coverage/lcov/*.lcov - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - test-e2e: - name: End to End testing - runs-on: ubuntu-latest - timeout-minutes: 30 - - needs: - - build - - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 6379:6379 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - RAILS_ENV: test - BUNDLE_WITH: test - LOCAL_DOMAIN: localhost:3000 - LOCAL_HTTPS: false - - strategy: - fail-fast: false - matrix: - ruby-version: - - '3.3' - - '3.4' - - '.ruby-version' - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - path: './' - name: ${{ github.sha }} - - - name: Expand archived asset artifacts - run: | - tar xvzf artifacts.tar.gz - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - timeout-minutes: 15 - with: - ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: Load database schema - run: './bin/rails db:create db:schema:load db:seed' - - - name: Cache Playwright Chromium browser - id: playwright-cache - uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5 - with: - path: ~/.cache/ms-playwright - key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - - - name: Install Playwright Chromium browser (with deps) - if: steps.playwright-cache.outputs.cache-hit != 'true' - run: yarn run playwright install --with-deps chromium - - - name: Install Playwright Chromium browser deps - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: yarn run playwright install-deps chromium - - - run: bin/rspec spec/system --tag streaming --tag js - - - name: Archive logs - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - if: failure() - with: - name: e2e-logs-${{ matrix.ruby-version }} - path: log/ - - - name: Archive test screenshots - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - if: failure() - with: - name: e2e-screenshots-${{ matrix.ruby-version }} - path: tmp/capybara/ - - test-search: - name: Elastic Search integration testing - runs-on: ubuntu-latest - timeout-minutes: 30 - - needs: - - build - - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10ms - --health-timeout 3s - --health-retries 50 - ports: - - 6379:6379 - - elasticsearch: - image: ${{ contains(matrix.search-image, 'elasticsearch') && matrix.search-image || '' }} - env: - discovery.type: single-node - xpack.security.enabled: false - options: >- - --health-cmd "curl http://localhost:9200/_cluster/health" - --health-interval 2s - --health-timeout 3s - --health-retries 50 - ports: - - 9200:9200 - - opensearch: - image: ${{ contains(matrix.search-image, 'opensearch') && matrix.search-image || '' }} - env: - discovery.type: single-node - DISABLE_INSTALL_DEMO_CONFIG: true - DISABLE_SECURITY_PLUGIN: true - options: >- - --health-cmd "curl http://localhost:9200/_cluster/health" - --health-interval 2s - --health-timeout 3s - --health-retries 50 - ports: - - 9200:9200 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - RAILS_ENV: test - BUNDLE_WITH: test - ES_ENABLED: true - ES_HOST: localhost - ES_PORT: 9200 - - strategy: - fail-fast: false - matrix: - ruby-version: - - '3.3' - - '3.4' - - '.ruby-version' - search-image: - - docker.elastic.co/elasticsearch/elasticsearch:7.17.29 - include: - - ruby-version: '.ruby-version' - search-image: docker.elastic.co/elasticsearch/elasticsearch:8.19.2 - - ruby-version: '.ruby-version' - search-image: opensearchproject/opensearch:2 - - steps: - - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - path: './' - name: ${{ github.sha }} - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - timeout-minutes: 15 - with: - ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg - - - name: Set up Javascript environment - uses: ./.github/actions/setup-javascript - - - name: Load database schema - run: './bin/rails db:create db:schema:load db:seed' - - - run: bin/rspec --tag search - - - name: Archive logs - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - if: failure() - with: - name: test-search-logs-${{ matrix.ruby-version }} - path: log/ diff --git a/COFFEYLABS.md b/COFFEYLABS.md new file mode 100644 index 0000000..80f8747 --- /dev/null +++ b/COFFEYLABS.md @@ -0,0 +1,43 @@ +# Coffey Labs build of Mastodon + +This repository is [Mastodon](https://github.com/mastodon/mastodon) with one +addition: the **coffeylabs** theme, the palette, type and blueprint grid of +coffeylabs.org. It is what runs on linuxexpert.org. Everything else is +upstream Mastodon, unchanged, under the same license (AGPL-3.0, see +[LICENSE](LICENSE)). + +## How it tracks upstream + +Upstream releases come in as snapshots, not as a merged history: the +`upstream` branch holds one unmodified "Import Mastodon vX.Y.Z" commit per +release, and each import is merged into `main` through a pull request. + +## What is changed + +Added (new files, Coffey Labs, 2026-10-06): + +- `app/javascript/styles/coffeylabs.scss` and `app/javascript/styles/coffeylabs/` + -- the theme. It loads the stock stylesheet, then overrides Mastodon's color + tokens and adds the fonts and surfaces. Users can still pick Mastodon's + default theme in their appearance preferences. +- `app/javascript/fonts/coffeylabs/` -- Bricolage Grotesque and JetBrains Mono, + both under the SIL Open Font License (license files alongside). +- `.gitea/workflows/ci.yml` -- builds the image on every change and publishes + it from release tags. +- This file. + +Modified (each carries a notice at the top): + +- `config/themes.yml` -- registers the coffeylabs theme. +- `app/lib/themes.rb` -- the dark browser-bar color matches the theme. +- `Dockerfile` -- `SOURCE_BASE_URL` and `SOURCE_TAG` build arguments, so the + "View source code" link points at this repository. + +Removed: upstream's `.github/workflows`, which run upstream's own CI. + +## Releases + +A tag named `v-coffeylabs.` (e.g. `v4.7.3-coffeylabs.1`) +publishes the `mastodon` image for linux/amd64 to this repository's +packages. The streaming server is unchanged, so use upstream's +`mastodon-streaming` image at the same upstream version. diff --git a/Dockerfile b/Dockerfile index 9e99a52..e36d4c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,9 @@ # syntax=docker/dockerfile:1.18 +# Modified by Coffey Labs, 2026-10-06: SOURCE_BASE_URL and SOURCE_TAG build +# arguments, so the "View source code" link points at this fork (see +# COFFEYLABS.md). + # This file is designed for production server deployment, not local development work # For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/docs/DEVELOPMENT.md#docker @@ -32,6 +36,9 @@ ARG MASTODON_VERSION_PRERELEASE="" ARG MASTODON_VERSION_METADATA="" # Will be available as Mastodon::Version.source_commit ARG SOURCE_COMMIT="" +# Where "View source code" points: the fork's repository and its tag +ARG SOURCE_BASE_URL="" +ARG SOURCE_TAG="" # Allow Ruby on Rails to serve static files # See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files @@ -51,6 +58,8 @@ ENV \ MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \ MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \ SOURCE_COMMIT="${SOURCE_COMMIT}" \ + SOURCE_BASE_URL="${SOURCE_BASE_URL}" \ + SOURCE_TAG="${SOURCE_TAG}" \ RAILS_SERVE_STATIC_FILES="${RAILS_SERVE_STATIC_FILES}" \ RUBY_YJIT_ENABLE="${RUBY_YJIT_ENABLE}" \ TZ="${TZ}" diff --git a/app/javascript/fonts/coffeylabs/OFL-bricolage.txt b/app/javascript/fonts/coffeylabs/OFL-bricolage.txt new file mode 100644 index 0000000..a397658 --- /dev/null +++ b/app/javascript/fonts/coffeylabs/OFL-bricolage.txt @@ -0,0 +1,93 @@ +Copyright 2022 The Bricolage Grotesque Project Authors (https://github.com/ateliertriay/bricolage) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/app/javascript/fonts/coffeylabs/OFL-jetbrains-mono.txt b/app/javascript/fonts/coffeylabs/OFL-jetbrains-mono.txt new file mode 100644 index 0000000..8f7ed67 --- /dev/null +++ b/app/javascript/fonts/coffeylabs/OFL-jetbrains-mono.txt @@ -0,0 +1,93 @@ +Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) JetBrainsMono-Italic[wght].ttf: Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/app/javascript/fonts/coffeylabs/bricolage-grotesque-latin-wght-normal.woff2 b/app/javascript/fonts/coffeylabs/bricolage-grotesque-latin-wght-normal.woff2 new file mode 100644 index 0000000..82152a4 Binary files /dev/null and b/app/javascript/fonts/coffeylabs/bricolage-grotesque-latin-wght-normal.woff2 differ diff --git a/app/javascript/fonts/coffeylabs/jetbrains-mono-latin-wght-normal.woff2 b/app/javascript/fonts/coffeylabs/jetbrains-mono-latin-wght-normal.woff2 new file mode 100644 index 0000000..cd5102a Binary files /dev/null and b/app/javascript/fonts/coffeylabs/jetbrains-mono-latin-wght-normal.woff2 differ diff --git a/app/javascript/styles/coffeylabs.scss b/app/javascript/styles/coffeylabs.scss new file mode 100644 index 0000000..99faf1a --- /dev/null +++ b/app/javascript/styles/coffeylabs.scss @@ -0,0 +1,7 @@ +// Coffey Labs theme: the stock stylesheet, then the coffeylabs.org palette, +// type and surfaces on top. Everything below overrides tokens or adds rules +// after the stock ones, so a Mastodon upgrade only needs a rebuild. +@use 'application'; +@use 'coffeylabs/fonts'; +@use 'coffeylabs/palette'; +@use 'coffeylabs/surfaces'; diff --git a/app/javascript/styles/coffeylabs/_fonts.scss b/app/javascript/styles/coffeylabs/_fonts.scss new file mode 100644 index 0000000..29f9867 --- /dev/null +++ b/app/javascript/styles/coffeylabs/_fonts.scss @@ -0,0 +1,32 @@ +// Bricolage Grotesque for display, JetBrains Mono for the wordmark, labels +// and numbers, the system sans for reading -- as on coffeylabs.org. Both +// faces are variable and OFL; licenses sit next to the font files. +@font-face { + font-family: 'Bricolage Grotesque'; + font-style: normal; + font-weight: 200 800; + font-stretch: 75% 100%; + font-display: swap; + src: url('@/fonts/coffeylabs/bricolage-grotesque-latin-wght-normal.woff2') + format('woff2'); +} + +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 100 800; + font-display: swap; + src: url('@/fonts/coffeylabs/jetbrains-mono-latin-wght-normal.woff2') + format('woff2'); +} + +html, +html[data-redesign='true'] { + --font-body: + ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Inter, Roboto, + 'Helvetica Neue', Arial, sans-serif; + --font-heading: 'Bricolage Grotesque', ui-sans-serif, system-ui, sans-serif; + --font-monospace: + 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'SFMono-Regular', Consolas, + 'Liberation Mono', monospace; +} diff --git a/app/javascript/styles/coffeylabs/_palette.scss b/app/javascript/styles/coffeylabs/_palette.scss new file mode 100644 index 0000000..a6c8b58 --- /dev/null +++ b/app/javascript/styles/coffeylabs/_palette.scss @@ -0,0 +1,89 @@ +// coffeylabs.org palette. Mastodon builds its scheme tokens from the grey +// and indigo scales, so those become Coffey Labs' blue-slate and blue; the +// semantic tokens that need an exact coffeylabs.org value are set after. + +html { + // Blue-slate, from the ground (#0C1017) up to the light ground (#EEF2F7) + --color-grey-50: #eef2f7; + --color-grey-100: #dce6f2; + --color-grey-200: #c3d0df; + --color-grey-300: #a7b8cc; + --color-grey-400: #8fa3bc; + --color-grey-500: #6b7c92; + --color-grey-600: #46586e; + --color-grey-700: #2f3d52; + --color-grey-800: #222d3c; + --color-grey-900: #131923; + --color-grey-950: #0c1017; + + // Blue accent, #4EA8FF on dark and #1668C7 on light + --color-indigo-50: #eef6ff; + --color-indigo-100: #dceeff; + --color-indigo-200: #b9dcff; + --color-indigo-300: #7dc0ff; + --color-indigo-400: #4ea8ff; + --color-indigo-500: #2f8fef; + --color-indigo-600: #1668c7; + --color-indigo-700: #0f54a5; + --color-indigo-800: #0e4380; + --color-indigo-900: #0f3360; + --color-indigo-950: #0b1f3a; + + // Status colors from coffeylabs.org: live green, warm orange + --color-green-400: #3ddc97; + --color-green-600: #0e8a5a; + --color-yellow-400: #ff8a00; + --color-yellow-700: #c75a00; + + --cl-grid-line: rgb(78 168 255 / 6%); + --cl-glow: rgb(78 168 255 / 20%); +} + +[data-color-scheme='dark'], +html:not([data-color-scheme]) { + --color-text-primary: #dce6f2; + --color-text-secondary: #8fa3bc; + --color-text-tertiary: #5f7288; + --color-text-brand: #4ea8ff; + + --color-bg-primary: #0c1017; + --color-bg-secondary: #131923; + --color-bg-tertiary: #18202c; + + // Accent buttons are bright blue with dark ink, as on coffeylabs.org + --color-bg-brand-base: #4ea8ff; + --color-bg-brand-base-hover: #7dc0ff; + --color-text-on-brand-base: #06101c; + --color-bg-brand-soft: #12304f; + --color-bg-brand-softest: #0f1d2e; + --color-border-brand-soft: #1f4b78; + + --color-border-primary: #222d3c; + + --dropdown-shadow: + 0 1px 2px rgb(0 0 0 / 30%), 0 10px 30px -12px rgb(0 0 0 / 60%); +} + +[data-color-scheme='light'] { + --color-text-primary: #0f1822; + --color-text-secondary: #46586e; + --color-text-tertiary: #6b7c92; + --color-text-brand: #1668c7; + + --color-bg-primary: #fff; + --color-bg-secondary: #eef2f7; + --color-bg-tertiary: #e9eff6; + + --color-bg-brand-base: #1668c7; + --color-bg-brand-base-hover: #0f54a5; + --color-text-on-brand-base: #fff; + --color-bg-brand-soft: #dceeff; + --color-bg-brand-softest: #eef6ff; + + --color-border-primary: #d6dfea; + + --dropdown-shadow: + 0 1px 2px rgb(15 24 34 / 5%), 0 8px 24px -12px rgb(15 24 34 / 14%); + --cl-grid-line: rgb(22 104 199 / 7%); + --cl-glow: rgb(22 104 199 / 14%); +} diff --git a/app/javascript/styles/coffeylabs/_surfaces.scss b/app/javascript/styles/coffeylabs/_surfaces.scss new file mode 100644 index 0000000..e0e8e02 --- /dev/null +++ b/app/javascript/styles/coffeylabs/_surfaces.scss @@ -0,0 +1,108 @@ +// Coffey Labs surfaces: the blueprint grid behind the page, the logo and +// wordmark in the navigation, mono for labels and numbers. + +// The faint 32px grid with a glow where the eye starts, behind the columns +body { + background-color: var(--color-bg-primary); + background-image: + radial-gradient( + ellipse 60rem 40rem at 20% -10%, + var(--cl-glow), + transparent 60% + ), + linear-gradient(var(--cl-grid-line) 1px, transparent 1px), + linear-gradient(90deg, var(--cl-grid-line) 1px, transparent 1px); + background-size: + 100% 100%, + 32px 32px, + 32px 32px; + background-attachment: fixed; +} + +.ui, +.columns-area__panels { + background: transparent; +} + +::selection { + background: var(--color-bg-brand-base); + color: var(--color-text-on-brand-base); +} + +// LINUXexpert mark and mono wordmark in place of the Mastodon wordmark +.column-link--logo { + display: flex; + align-items: center; + gap: 10px; + + .logo--wordmark { + display: none; + } + + &::before { + content: ''; + flex: none; + width: 32px; + height: 32px; + background: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20512%20512%27%3E%3Crect%20width%3D%27512%27%20height%3D%27512%27%20rx%3D%27104%27%20fill%3D%27%2314171D%27%2F%3E%3Crect%20x%3D%2710%27%20y%3D%2710%27%20width%3D%27492%27%20height%3D%27492%27%20rx%3D%2796%27%20fill%3D%27none%27%20stroke%3D%27%234FA7FF%27%20stroke-opacity%3D%270.18%27%20stroke-width%3D%274%27%2F%3E%3Cpolyline%20points%3D%27172%2C150%20284%2C256%20172%2C362%27%20fill%3D%27none%27%20stroke%3D%27%234FA7FF%27%20stroke-width%3D%2742%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%2F%3E%3Crect%20x%3D%27322%27%20y%3D%27308%27%20width%3D%2792%27%20height%3D%2748%27%20rx%3D%278%27%20fill%3D%27%234FA7FF%27%2F%3E%3C%2Fsvg%3E") + center / contain no-repeat; + } + + &::after { + content: 'LINUXexpert'; + font-family: var(--font-monospace); + font-size: 18px; + font-weight: 700; + letter-spacing: -0.02em; + color: var(--color-text-primary); + } +} + +// Display face for headings and names +.column-header__title, +.column-title h1, +.column-title h2, +.account__header__tabs__name h1, +.status__display-name strong, +.display-name__html { + font-family: var(--font-heading); + letter-spacing: -0.01em; +} + +.column-header__title { + font-weight: 700; +} + +// Mono for timestamps, counts and small labels +.status__relative-time, +.icon-button__counter, +.account__header__extra__links a, +.trends__item__current, +.notification-group__main__header__label, +.dismissable-banner__message, +.column-subheading { + font-family: var(--font-monospace); + font-size: 0.86em; +} + +.column-subheading { + text-transform: uppercase; + letter-spacing: 0.14em; + font-weight: 600; +} + +// Hashtags and mentions read as code, like links on coffeylabs.org +.hashtag-bar a, +.status__content a.hashtag { + font-family: var(--font-monospace); + font-size: 0.92em; +} + +// Cards get the coffeylabs.org border and soft shadow +.status-card, +.dropdown-menu, +.search__popout, +.modal-root__modal { + border-color: var(--color-border-primary); + box-shadow: var(--dropdown-shadow); +} diff --git a/app/lib/themes.rb b/app/lib/themes.rb index 67b1275..c85929f 100644 --- a/app/lib/themes.rb +++ b/app/lib/themes.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +# Modified by Coffey Labs, 2026-10-06: the dark browser-bar color is the +# coffeylabs theme's ground (see COFFEYLABS.md). + require 'singleton' require 'yaml' @@ -7,7 +10,7 @@ class Themes include Singleton THEME_COLORS = { - dark: '#181820', + dark: '#0c1017', light: '#ffffff', }.freeze diff --git a/config/themes.yml b/config/themes.yml index a1049fa..1215309 100644 --- a/config/themes.yml +++ b/config/themes.yml @@ -1 +1,3 @@ +# Modified by Coffey Labs, 2026-10-06: adds the coffeylabs theme (see COFFEYLABS.md). default: styles/application.scss +coffeylabs: styles/coffeylabs.scss